spring技术内幕 -- AOP 的实现

1.总览

  • 了解什么是AOP 
  • AOP 简单是怎么实现的?
  • AOP 在spring 中是怎么实现的?
  • AOP 在spring 中是怎么运用起来的?具体简单的结合一下之前的项目还有或者看到的框架


2.AOP 概念

AOP 简单的直译就是面向切面编程,通常是借助于 JDK 动态代理、CGLIB 等在内存中“临时”生成 AOP 动态代理类
主要采用了JDK 的动态代理, 然后CGLIB 是动态的在字节码中增加代理类.

AOP中用了一个叫动态代理的设计模式, 简单来说就是多了一个代理类在中间帮你做了.而不是你自己亲手做了.
如果用java 反射来实现动态代理 主要是这两个点:
  • 第一,是InvocationHandler接口, 这里接口里面只有一个方法.
         
         
    //Object proxy:指被代理的对象。
    //Method method:要调用的方法
    //Object[] args:方法调用时所需要的参数
    public Object invoke ( Object proxy , Method method , Object [] args ) throws Throwable ;
    //这个方法代理类通过反射 主动来调用的方法.
  • 第二,Proxy 代理类提供用于创建动态代理类和实例的静态方法。所谓动态代理类是在运行时生成的class,在生成它时,你必须提供一组interface给它,则动态代理类就宣称它实现了这些interface。当然,动态代理类就充当一个代理,你不要企图它会帮你干实质性的工作,在生成它的实例时你必须提供一个handler,由它接管实际的工作. (这就是为什么java 反射做代理需要一个接口, 而 cglib 做代理不用的原因/区别)
         
         
    //从这个方法就可以看出创建一个动态的代理类需要绑定接口,如果没有就不能创建了,因为通过代理类需要借口中的方法来调用它的实现, 这也是jdk反射创建代理类和cglib 创建代理类区别的地方.
    //这里返回的其实就是一个通过 封装的 实现类 impl, 只是中间代理了很多方法.  
    public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h)
通过cglib 来实现代理类
原理跟jdk 的差不多.但是,不是用反射, 而是使用了一种叫ASM的框架来操纵字节码从而产生我们想要的代理类.
之类有一段引用
    
    
CGLIB包的底层是通过使用一个小而快的字节码处理框架ASM(Java字节码操控框架),来转换字节码并生成新的类。除了CGLIB包,脚本语言例如 Groovy和BeanShell,也是使用ASM来生成java的字节码。当不鼓励直接使用ASM,因为它要求你必须对JVM内部结构包括class文件的格式和指令集都很熟悉。所以cglib包要依赖于asm包,需要一起导入。下图为cglib与一些框架和语言的关系(CGLIB Library and ASM Bytecode Framework)
 
来源: <http://blog.csdn.net/xiaohai0504/article/details/6832990>
     
     
//cglib 的原理有点像拦截器那样来拦截我们的方法 然后做操作.
//跟jdk 中的invoke 类似.
//MethodInterception接口的方法.
Object invoke(MethodInvocation invocation) throws Throwable;

  

可能你会问.我自己好好的自己调用自己的方法 就好像 A方法调用B 方法 现在就是在中间多加一个 C 调用同样的方法 有用吗?
有!肯定不是没用的!你可以再你自己实现的相同接口下面多加一些你本来不知道的东西, 比如我们经常做的 try-catch 如果放在 C 的invoke 方法中那么A 中所有的类就看不到 也不用写try-catch 这种东西了.!这样就达到了面向切口编程的目的!

   
   
/***
* 用户控制接口
* @author Administrator
*
*/
public interface UserManager {
public void addUser(String userId,String userName);
public void modifyUser(String userId,String userName);
public void delUser(String userId);
public String findUser(String userId);
}
 
/****
* 用户管理真正的实现类
* @author Administrator
*
*/
public class UserManagerImpl implements UserManager {
/*****
* 添加用户
*/
public void addUser(String userId, String userName) {
System.out.println("正在添加用户,用户为:"+userId+userName+"……");
}
/*****
* 删除用户
*/
public void delUser(String userId) {
System.out.println("delUser,userId="+userId);
}
/***
* 查找用户
*/
public String findUser(String userId) {
System.out.println("findUser,userId="+userId);
return userId;
}
public void modifyUser(String userId, String userName) {
System.out.println("modifyUser,userId="+userId);
}
}
 
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class LogHandler implements InvocationHandler {
private Object targetObject;
public Object newProxyInstance(Object targetObject) {
this.targetObject = targetObject;
return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),
targetObject.getClass().getInterfaces(), this);
}
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object ret = null;
try {
System.out.println("正在进行操作前的准备工作……");
//调用目标方法
ret = method.invoke(targetObject, args);
System.out.println("操作成功,正在进行确认处理……");
} catch (Exception e) {
e.printStackTrace();
System.out.println("error-->>" + method.getName());
throw e;
}
return ret;
}
}
public class Client {
/**
* @param args
*/
public static void main(String[] args) {
LogHandler logHandler = new LogHandler();
     //这里返回的的是代理类,但是这个代理类里面已经做好了自己加入的切面方法, 类似 before() after() 这种.
UserManager userManager = (UserManager)logHandler.newProxyInstance(new UserManagerImpl());
//当我调用的时候就不是简单的调用了我的那个接口里面的方法了, 而是通过代理类产生的方法, 忽然就可以联想到spring 还有 hibernate 中用了好多这些例子.
userManager.findUser("0001");
}
}
上面这个例子其实真的非常非常像我们平时使用spring 的感觉, 但是spring 比上面这个更加的优秀更加的好用,同时也是更加的强大.

好了这里有了简单的aop 知识了之后就可以开始spring 中的源码分析了.

3.spring 中的AOP

在spring中的aop 是通过三个步骤实现的. 第一个是创建代理类,第二个就是拦截器的作用, 第三个是Aspect 编织的实现.
这里下面的部分内容转自书的原作者中的博客,如果有误可以参考< http://jiwenke.iteye.com/blog/494620>

引入几个概念 后面会用到.
  1. Advisor:充当Advice和Pointcut的适配器
  2. Advice:用于定义拦截行为
  3. Pointcut:用于定义拦截目标集合

这里从ProxyFactoryBean 的主线开始出发.
   
   
//getObject 中判断了一下是否是单例 如果是 就调用了下面的方法了.
private synchronized Object getSingletonInstance() {
if (this.singletonInstance == null) {
this.targetSource = freshTargetSource();
if (this.autodetectInterfaces && getProxiedInterfaces().length == 0 && !isProxyTargetClass()) {
// Rely on AOP infrastructure to tell us what interfaces to proxy.
Class<?> targetClass = getTargetClass();
if (targetClass == null) {
throw new FactoryBeanNotInitializedException("Cannot determine target class for proxy");
}
//这里看着就像调用反射来产生代理类.
setInterfaces(ClassUtils.getAllInterfacesForClass(targetClass, this.proxyClassLoader));
}
// Initialize the shared singleton instance.
super.setFrozen(this.freezeProxy);
             //这里使用了工厂来产生了我们需要的Proxy 类.
this.singletonInstance = getProxy(createAopProxy());
}
return this.singletonInstance;
}
//使用createAopProxy返回的AopProxy来得到代理对象
protected Object getProxy(AopProxy aopProxy) {
//这里的aopProxy 其实已经通过了拦截器来实现复杂的aop 了.下面
return aopProxy.getProxy(this.proxyClassLoader);
}
我们得到了代理类之后我们要看看拦截链,如果一层一层的将类加强的.
递归调用,找pointcut 匹配.
   
   
public Object proceed() throws Throwable {
//如果拦截器链中的拦截器迭代调用完毕,这里开始调用target的函数,这个函数是通过反射机制完成的,具体实现在:AopUtils.invokeJoinpointUsingReflection方法里面。
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
//这里沿着定义好的 interceptorOrInterceptionAdvice链进行处理。
Object interceptorOrInterceptionAdvice = this . interceptorsAndDynamicMethodMatchers . get (++ this . currentInterceptorIndex );
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
//这里对拦截器进行动态匹配的的判断,还记得我们前面分析的pointcut吗?这里是触发进行匹配的地方,如果和定义的pointcut匹配,那么这个advice将会得到执行。
InterceptorAndDynamicMethodMatcher dm = ( InterceptorAndDynamicMethodMatcher ) interceptorOrInterceptionAdvice ;
if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
return dm.interceptor.invoke(this);
}
else {
// //如果不匹配,那么这个proceed会被递归调用,直到所有的拦截器都被运行过为止。
return proceed();
}
}
else {
//如果是一个interceptor,直接调用这个interceptor对应的方法
return((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
最后的一步 编织. 这里举了一个例子 MethodBeforeAdviceInterceptor
   
   
public class MethodBeforeAdviceInterceptor implements MethodInterceptor, Serializable {
private MethodBeforeAdvice advice;
public MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) {
Assert.notNull(advice, "Advice must not be null");
this.advice = advice;
}
//这个invoke方法是拦截器的回调方法,会在代理对象的方法被调用的时候触发回调。
public Object invoke(MethodInvocation mi) throws Throwable {
this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() );
return mi.proceed();
}
}
通过MethodInterceptor 接口的方法实现了 拦截链前 的通知.
这里还需要去补一下.感觉还是不太清楚, 主要是 那三个概念不太了解,还有拦截的过程不太清楚明白.











  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值