1、Advice通知、Pointcut切点、Advisor通知器
Advice(通知)定义在连接点做什么,为切面增强提供织入接口。Spring AOP提供了BeforeAdvice、AfterAdvice、ThrowsAdvice等。MethodBeforeAdvice接口继承自BeforeAdvice,提供了void before(Method method, Object[] args, Object target) throws Throwable方法,在Advice中被配置到目标方法后,会在调用目标方法是被回调。method是目标方法的反射对象。AfterReturingAdvice在方法调用结束并成功返回的时候被回调,也可以进行调用次数统计。ThrowsAdvice在抛出异常时被回调。
PointCut(切点)决定Advice通知应该作用于哪些连接点,定义需要增强的方法的集合。PointCut接口定义了ClassFilter getClassFilter()和MethodMatcher getMethodMatcher()两个方法,MethodMatcher接口定义了matches方法。典型的PointCut有JdkRegexpMethodPointCut,通过正则表达式对方法进行匹配;NameMatchMethodPointCut。
Advisor通知器定义了应该使用哪个Advice并在哪个PointCut使用,结合了Advice和PointCut。在DefaultPointCutAdvisor中就有advice和pointcut两个属性。
AOP需要为目标对象生成代理对象,使用JDK的动态代理(实现InvocationHandler接口,在method.invoke前后插入逻辑处理),或者使用CGLIB生成代理对象。还需要启动代理对象的拦截器来完成各种横切面的织入,通过一系列Adapter实现。
2、建立AopProxy代理对象
Spring主要通过配置和调用ProxyFactoryBean生成代理对象。对于需要使用AspectJ的AOP应用,AspectJProxyFactory集成了Spring和AspectJ;对于使用Spring AOP的应用,ProxyFactoryBean和ProxyFactory都提供了AOP功能的封装,ProxyFactoryBean是声明式,ProxyFactory是编程式的。使用ProxyFactoryBean时,需要定义使用的Advisor,并把ProxyFactoryBean作为一个Bean定义,包括proxyInterface、interceptorNames和target属性。
对ProxyFactoryBean来说,把需要对taget目标对象增加的增强处理,都通过getObject方法进行封装了,首先对通知器链进行初始化,通知器链封装了一系列的拦截器,这些拦截器从配置中读取,如下。
在第一次通过ProxyFactoryBean获取代理对象时,会进行调用initializeAdvisorChain()进行初始化,读取配置中出现的所有Advisor,把Advisor的BeanName交给容器getBean就可以了,再通过addAdvisorOnChainCreation(advice, name)将通知器加入拦截器链,如下,是initializeAdvisorChain()中的一部分。
生成singleton代理对象在getSingletonInstance()中完成,是ProxyFactoryBean生成AopProxy代理对象的调用入口,在getSingletonInstance()中设置了代理对象的接口,时序图如下。
AopProxy接口有Cglib2AopProxy和JdkDynamicProxy两个子类来生成代理对象,具体的生成是在ProxyFactoryBean的积累AdvisedSupport中借助AopProxyFactory生成,默认是DefaultAopProxyFactory,对接口类使用动态代理,否则使用CGLIB,在createAopProxy()中判断使用哪种策略,isInterface() or createCglibProxy(),默认使用动态代理。
使用JDK动态代理时:Proxy.newProxyInstance(classLoader, proxiedInterfaces, invocationHandler),在Proxy代理的接口方法被调用时,会触发invocationHandler的invoke回调。使用CGLIB时,创建并配置Enhancer,是CGLIB的主要操作类,通过Enhancer设置代理接口、回调方法,生成代理对象。在Enhancer的callback回调中,通过设置DynamicAdvisedInterceptor拦截器来实现AOP。通过这两种方法,使用AopProxy封装了target目标对象,ProxyFactoryBean.getObject()得到的不是一个普通的Java对象,而是一个AopProxy代理对象。对于不同的代理对象生成方式,使用不同的拦截回调入口,动态代理使用invoke,CGLIB使用配置好的callback回调。
3、Spring AOP拦截器调用的实现
下图截取了JdkDynamicAopProxy的invoke()方法中的主要部分,构造了ReflectiveMethodInvacation来完成拦截器链的调用,proceed()方法类似责任链,沿着拦截器链前进,逐个运行拦截器的拦截方法。Cglib2AopProxy与之类似,只不过构造CglibMethodInvocation来完成拦截器链的调用。
如果chain.isEmpty() == true,调用invokeJoinpointUsingReflection(),使用反射完成目标对象的方法调用,如下。
在proceed()方法中,如果运行到拦截器末尾,调用目标对象的方法实现,否则沿着拦截器链前行,通过拦截器进行matches判断,为true则从Interceptor中得到Advisor,启动Advisor的invoke()方法,再迭代调用proceed()。
前面的代码中有一句List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass),获取interceptors由advised完成,advised是一个AdvisedSupport对象,也是ProxyFactoryBean的基类,它调用advisorChainFactory获得拦截器链,默认是DefaultAdvisorChainFactory,通过AdvisorAdapterRegistry实现拦截器的注册。在拦截器的适配和注册完成之后,拦截器被AopProxy调用,如下是DefaultAdvisorChainFactory生成拦截器链的部分代码。其中拦截器链从AdvisorAdapterRegistry中取得,是在ProxyFactoryBean.getObject()里,初始化了拦截器链(ProxyFactoryBean实现了BeanFactoryAware接口,getBean注入Advisor),并加入到AdvisorAdapterRegistry中。
下面看一下DefaultAdvisorAdapterRegistry的实现,从容器getBean获取的是Advisor,如何将Advisor转化为上图需要的MethodInterceptor,这里用到了适配器模式。给出了三种AdviceAdapter,适配了supportAdvice(Advice),判断Advice类型;适配了getInterceptor(Advisor),注册不同的AdviceInterceptor。
如下分别是MethodBeforeAdviceInterceptor和AfterReturningAdviceInterceptor的实现,ThrowsAdviceInterceptor更复杂一些,维护了Map<Class, Method> exceptionHandlerMap,针对不同异常调用对应的Method。
4、高级特性
如果需要使用原始对象(不是增强过的),可以实现TargetSource接口,有一个实现类HotSwappableTargetSource可以提供热交换的功能,在使用时把HotSwappableTargetSource配置到ProxyFactoryBean的target属性就可以,调用HotSwappableTargetSource的swap方法切换到原始对象。