AOP(Aspect-Oriented Programming)面向切面编程
为什么要使用AOP?
维基百科对AOP相关概念的叙述:Aspect是一种新的模块化机制,用来描述分散在对象、类或函数中的横切关注点。从关注点中分离出横切关注点是面向切面的程序设计的核心概念。分离关注点使解决特定问题的代码从业务逻辑中独立出来、业务逻辑的代码中不再含有针对特定领域问题代码的调用,业务逻辑同特定领域问题的关系通过切面来封装、维护,这样原本分散在整个应用程序中的变动就可以很好地管理起来。
我们在有一定的面向对象编程经验后发现,面向对象设计其实也是一种模块化的方法,他把相关的数据及其处理方法放在了一起。与单纯使用子函数进行封装相比,面向对象的模块化特性更完备,它体现了计算的一个基本原则——让计算尽可能靠近数据。这样一来,代码组织起来就更加整齐和清晰,进一步提高了开发效率。
后来在开发中可能又会发现一些问题。虽然利用面向对象的方法可以很好地组织代码,也可以通过继承关系实现代码重用,但是程序中总会出现一些重复的代码,而且不太方便使用继承的方法吧他们重用和管理起来。他们功能重复并且使用在不同的地方,虽然可以对这些代码做一些简单的封装,使之成为公共函数,但是在这种显式调用中,使用它们并不是很方便。例如,这个公共函数在什么情况下可以使用,能不能更灵活地使用等。
另外,在使用这些公共函数的时候,往往也需要进行一些逻辑设计,也就是需要代码实现来支持,而这些逻辑代码也是需要维护的。这时就是AOP大显身手的时候,使用AOP后,不仅可以将这些重复的代码抽取出来单独维护,在需要使用时统一调用,还可以为如何使用这些公共代码提供丰富灵活的手段。
Advice 通知
Advice(通知)定义在连接点做什么,为切面增强提供织入接口。在Spring AOP中,它主要描述Spring AOP围绕方法调用而注入的切面行为。Advice是AOP联盟定义的一个接口,具体的接口定义在org.aopalliance.aop.Advice中。在Spring AOP的实现中,使用了这个统一接口,并通过这个接口,为AOP切面增强的织入功能做了更多的细化和扩展,比如提供了更具体的通知类型,如BeforeAdvice、AfterAdvice、ThrowsAdvice等。
在BeforeAdvice的继承体系中,定义了为待增强的目标方法设置的前置增强接口MethodBeforeAdvice,使用这个前置接口需要实现一个回调函数:
void before(Method method, Object[] args, Object target) throws Throwable;
public interface MethodBeforeAdvice extends BeforeAdvice {
/**
* Callback before a given method is invoked.
* @param method method being invoked
* @param args arguments to the method
* @param target target of the method invocation. May be {@code null}.
* @throws Throwable if this object wishes to abort the call.
* Any exception thrown will be returned to the caller if it's
* allowed by the method signature. Otherwise the exception
* will be wrapped as a runtime exception.
*/
void before(Method method, Object[] args, Object target) throws Throwable;
}
作为回调函数,before方法的实现在Advice中被配置到目标方法后,会在调用目标方法时被回调。具体的调用参数有:Method对象,这个对象是目标方法的反射对象;Object[]对象数组,这个对象数组中包含目标对象的输入参数。
在Advice的实现体系中,Spring还提供了AfterAdvice这种通知类型。
public interface AfterReturningAdvice extends AfterAdvice {
/**
* Callback after a given method successfully returned.
* @param returnValue the value returned by the method, if any
* @param method method being invoked
* @param args arguments to the method
* @param target target of the method invocation. May be {@code null}.
* @throws Throwable if this object wishes to abort the call.
* Any exception thrown will be returned to the caller if it's
* allowed by the method signature. Otherwise the exception
* will be wrapped as a runtime exception.
*/
void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable;
}
在上图所示的AfterAdvice类接口体系中,可以看到一系列对AfterAdvice的实现和接口扩展。以AfterReturningAdvice通知为例,分析AfterAdvice通知类型的实现原理。在AfterReturningAdvice接口中定义了接口方法:
void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable;
afterReturning方法也是一个回调函数,AOP应用需要在这个接口实现中提供切面增强的具体设计,在这个Advice通知被正确配置以后,在目标方法调用结束并成功返回的时候,接口会被Spring AOP回调。对于回调参数,有目标方法的返回结果、反射对象以及调用参数(AOP把这些参数都封装在一个对象数组中传递进来)等。
我们看到BeforeAdvice和AfterAdvice它们的最终实现一个是在目标方法调用前实现切面增强,一个是在目标方法成功调用返回结果后实现切面增强。
我们还应注意到还有一种Advice通知,即ThrowsAdvice,对于ThrowsAdvice,并没有指定需要实现的接口方法,它在抛出异常时被回调,这个回调是AOP使用反射机制来完成的。
public interface ThrowsAdvice extends AfterAdvice {
}
Pointcut 切点
Pointcut (切点)决定Advice通知应该作用于哪个连接点,也就是说通过Pointcut来定义需要增强的方法的集合,这些集合的选取可以按一定的规则来完成。在这种情况下,Pointcut通常意味着标识方法,例如,这些需要增强的地方可以由某个正则表达式进行标识或根据某个方法名进行匹配等。
public interface Pointcut {
/**
* Return the ClassFilter for this pointcut.
* @return the ClassFilter (never {@code null})
*/
ClassFilter getClassFilter();
/**
* Return the MethodMatcher for this pointcut.
* @return the MethodMatcher (never {@code null})
*/
MethodMatcher getMethodMatcher();
/**
* Canonical Pointcut instance that always matches.
*/
Pointcut TRUE = TruePointcut.INSTANCE;
}
在Pointcut的基本接口定义中可以看到,需要返回一个MethodMatcher。对于Pointcut的匹配判断功能,具体是由这个返回的MethodMatcher来完成的,也就是说,由这个MethodMatcher来判断是否需要对当前方法进行增强,或者是否需要对当前调用方法应用配置好的Advice通知。在Pointcut的类继承体系中,以正则表达式切点JdkRegexpMethodPointcut的实现原理为例,具体了解切点Pointcut的工作原理。JdkRegexpMethodPointcut类完成通过正则表达式对方法名进行匹配的功能。在JdkRegexpMethodPointcut的基类StaticMethodMatcherPointcut的实现中可以看到,设置MethodMatcher为StaticMethodMatcher,同时JdkRegexpMethodPointcut也是这个MethodMatcher的子类,
可以看到,在Pointcut中,通过这样的类继承体系,MethodMatcher对象实际上是可以被配置成JdkRegexpMethodPointcut来完成方法的匹配判断的。在JdkRegexpMethodPointcut中,可以看到一个matcher方法是MethodMatcher定义的接口方法。在JdkRegexpMethodPointcut的实现中,这个matcher方法就是使用正则表达式来对方法名进行匹配的地方。
在对matcher方法的调用关系中可以看到,是在JdkDynamicAopProxy的invoke方法中触发了对matcher方法的调用,很明显,这个invoke方法应该就是Proxy对象进行代理回调的入口方法,这个invoke回调的实现是使用JDK动态代理完成AOP功能的一部分。
/**
* Returns {@code true} if the {@link Pattern} at index {@code patternIndex}
* matches the supplied candidate {@code String}.
*/
@Override
protected boolean matches(String pattern, int patternIndex) {
Matcher matcher = this.compiledPatterns[patternIndex].matcher(pattern);
return matcher.matches();
}
在JdkRegexpMethodPointcut中,通过JDK来实现正则表达式的匹配。
在Spring AOP中,还提供了其他的MethodPointcut,比如通过方法名进行匹配Advice匹配的NameMatchMethodPointcut。它的matches方法实现很简单,匹配的条件是方法名相同或者方法名相匹配。
@Override
public boolean matches(Method method, Class<?> targetClass) {
for (String mappedName : this.mappedNames) {
if (mappedName.equals(method.getName()) || isMatch(method.getName(), mappedName)) {
return true;
}
}
return false;
}
protected boolean isMatch(String methodName, String mappedName) {
return PatternMatchUtils.simpleMatch(mappedName, methodName);
}
Advisor 通知器
完成对目标方法的切面增强设计(Advice)和关注点的设计(Pointcut)以后,需要一个对象把他们结合起来,完成这个作用的就是Advisor(通知器)。通过Advisor,可以定义应该使用哪个通知并在哪个关注点使用它,也就是说通过Advisor,把Advice和Pointcut结合起来,这个结合为使用IoC容器配置AOP应用,或者说即开即用地使用AOP基础设施,提供了便利。在Spring AOP 中,我们以一个Advisor的实现(DefaultPointcutAdvisor)为例,来了解Advisor的工作原理,可以分别配置Advice和Pointcut,DefaultPointcutAdvisor的实现如下。
public class DefaultPointcutAdvisor extends AbstractGenericPointcutAdvisor implements Serializable {
private Pointcut pointcut = Pointcut.TRUE;
/**
* Create an empty DefaultPointcutAdvisor.
* <p>Advice must be set before use using setter methods.
* Pointcut will normally be set also, but defaults to {@code Pointcut.TRUE}.
*/
public DefaultPointcutAdvisor() {
}
/**
* Create a DefaultPointcutAdvisor that matches all methods.
* <p>{@code Pointcut.TRUE} will be used as Pointcut.
* @param advice the Advice to use
*/
public DefaultPointcutAdvisor(Advice advice) {
this(Pointcut.TRUE, advice);
}
/**
* Create a DefaultPointcutAdvisor, specifying Pointcut and Advice.
* @param pointcut the Pointcut targeting the Advice
* @param advice the Advice to run when Pointcut matches
*/
public DefaultPointcutAdvisor(Pointcut pointcut, Advice advice) {
this.pointcut = pointcut;
setAdvice(advice);
}
/**
* Specify the pointcut targeting the advice.
* <p>Default is {@code Pointcut.TRUE}.
* @see #setAdvice
*/
public void setPointcut(Pointcut pointcut) {
this.pointcut = (pointcut != null ? pointcut : Pointcut.TRUE);
}
@Override
public Pointcut getPointcut() {
return this.pointcut;
}
@Override
public String toString() {
return getClass().getName() + ": pointcut [" + getPointcut() + "]; advice [" + getAdvice() + "]";
}
}
在DefaultPointcutAdvisor中,pointcut默认被设置为Pointcut.True,这个Pointcut.True在Pointcut接口中被定义为:
Pointcut TRUE = TruePointcut.INSTANCE;
TruePointcut的INSTANCE是一个单件。在它的实现中,可以看到单件模式的具体应用和使用方法,如使用static类变量来持有单件实例,使用private私有构造器函数来确保除了当前单件实现中,单件不会被再次创建和实例化,从而保证它的”单件“特性。在TruePointcut的methodMatcher实现中,使用TrueMethodMatcher作为方法匹配器。这个方法匹配器对任何的方法匹配都要求返回true的结果,也就是说对任何方法名的匹配要求,他都会返回匹配成功的结果。和TruePoint一样,TrueMethod也是一个单件实现。他们的实现分别如下:
class TruePointcut implements Pointcut, Serializable {
public static final TruePointcut INSTANCE = new TruePointcut();
/**
* Enforce Singleton pattern.
*/
// 这里是单件模式的实现特点,设置私有的构造函数,使其不能直接被实例化
// 并设置一个静态的类变量来保证该实例是唯一的
private TruePointcut() {
}
@Override
public ClassFilter getClassFilter() {
return ClassFilter.TRUE;
}
@Override
public MethodMatcher getMethodMatcher() {
return MethodMatcher.TRUE;
}
/**
* Required to support serialization. Replaces with canonical
* instance on deserialization, protecting Singleton pattern.
* Alternative to overriding {@code equals()}.
*/
private Object readResolve() {
return INSTANCE;
}
@Override
public String toString() {
return "Pointcut.TRUE";
}
}
class TrueMethodMatcher implements MethodMatcher, Serializable {
public static final TrueMethodMatcher INSTANCE = new TrueMethodMatcher();
/**
* Enforce Singleton pattern.
*/
private TrueMethodMatcher() {
}
@Override
public boolean isRuntime() {
return false;
}
@Override
public boolean matches(Method method, Class<?> targetClass) {
return true;
}
@Override
public boolean matches(Method method, Class<?> targetClass, Object[] args) {
// Should never be invoked as isRuntime returns false.
throw new UnsupportedOperationException();
}
/**
* Required to support serialization. Replaces with canonical
* instance on deserialization, protecting Singleton pattern.
* Alternative to overriding {@code equals()}.
*/
private Object readResolve() {
return INSTANCE;
}
@Override
public String toString() {
return "MethodMatcher.TRUE";
}
}
Spring AOP的设计与实现
JVM的动态代理特性
我们了解代理模式的类结构的话,会知道其是通过设置一个接口和目标对象一致的代理对象Proxy,它们都实现了同一个接口,在这种情况下,对目标对象的特定方法的调用,往往就被代理对象给拦截了,通过这种拦截,为目标对象的方法操作做了铺垫,所以称为代理模式。而这一系列的处理对于目标对象来说是透明的,目标对象对这些处理可以毫不知情。
JDK中已经实现了这个Proxy模式,在基于Java虚拟机设计应用程序时,只需要直接使用这个特性就可以了。在JAVA的reflection包中看到Proxy对象,这个对象生成后,所起的作用就类似于Proxy模式中的Proxy对象,在使用时,还需要为代理对象(Proxy)设计一个回调方法,这个会调方法的作用是,在其中加入了作为代理需要额外处理的动作。这个回调方法,如果在JDK中实现,需要实现下面所示的InvocationHandler接口:
public interface InvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
}
在这个接口方法中,只声明了一个invoke方法,这个invoke方法的第一个参数是代理对象实例,第二个参数是Method对象,代表的是当前Proxy被调用的方法,最后一个参数是被调用的方法中的参数。至于怎样让invoke方法和Proxy挂上勾,只要在实现通过调用Proxy.newIntance方法生成具体Porxy对象时把InvocationHandler设置到参数里面就可以了,剩下的由java虚拟机来完成。
Spring AOP的设计
为了让AOP起作用,需要完成一系列过程,比如,需要为目标对象建立代理对象,这个代理对象可以通过使用JDK的Proxy来完成,也可以通过第三方的类生成器CGLIB来完成。然后,还需要启动代理对象的拦截器来完成各种横切面的织入,这一系列的织入设计是通过一系列Adapter来实现的。通过一系列Adapter的设计,可以把AOP的横切面设计和Proxy模式有机地结合起来,从而实现在AOP中定义好的各种织入方式。
建立AopProxy 代理对象
在Spring的AOP模块中,一个主要的部分是代理对象的生成,面对与Spring应用,可以看到,是通过配置和调用Spring的ProxyFactoryBean来完成这个任务的。在ProxyFactoryBean中,封装了主要代理对象的生成过程。在这个生成过程中,可以使用JDK的Proxy和CGLIB两种生成方式。
在这个类继承体系中,可以看到完成AOP应用的类,比如AspectJProxyFactory、ProxyFactory和ProxyFactoryBean,他们都在同一个类的继承体系下,都是ProxyConfig、AdvisedSupport和ProxyCreatorSupport的子类。作为共同基类,可以将ProxyConfig看成是一个数据基类,这个数据基类为ProxyFactoryBean这样的子类提供了配置属性;在另一个基类AdvisedSupport的实现中,封装了AOP对通知和通知器的相关操作,这些操作对于不同的AOP代理对象的生成都是一样的,但对于具体的AOP代理对象的创建,AdvisedSupport把它交给他的子类们去完成;对于ProxyCreatorSupport,可以将它看成是其子类创建AOP代理对象的一个辅助类。通过继承以上提到的基类的功能的实现,具体的AOP代理对象的生成。对于需要使用AspectJ的AOP应用,AspectJProxyFactory起到集成Spring和AspectJ的作用;对于使用Spring AOP的应用,ProxyFactoryBean和ProxyFactory都提供了AOP功能的封装,只是使用proxyFactoryBean,可以在IoC容器中完成声明式配置,而使用ProxyFactory,则需要编程式地使用Spring AOP的功能。
配置ProxyFactoryBean
在分析Spring AOP的实现原理中,主要以ProxyFactoryBean的实现作为例子和实现的基本线索进行分析。这是因为ProxyFactoryBean是在Spring IoC环境中创建了AOP应用的底层方法,也是最灵活的方法,Spring通过它完成了对AOP使用的封装。
在基于XML配置Spring的Bean时,需要一系列的配置步骤来使用ProxyFactoryBean和AOP
1. 定义使用的通知器Advisor,这个通知器应该作为一个Bean来定义。这个通知器的实现定义了需要对目标对象进行增强的切面行为,也就是Advice通知。
2. 定义ProxyFactoryBean,把它作为另一个Bean来定义,它是封装AOP功能的主要类,在配置ProxyFactoryBean时,需要设定与AOP实现相关的重要属性,比如proxyInterface、interceptorNames和target等。从属性名称可以看出,interceptorNames属性的值往往设置为需要定义的通知器,因为这些通知器在ProxyFactoryBean的AOP配置下,是通过使用代理对象的拦截器机制起作用的。
3. 定义target属性,作为target属性注入的Bean,是需要用AOP通知器中的切面应用来增强的对象,也就是前面提到的base对象。
ProxyFactoryBean生成AopProxy代理对象
在ProxyFactoryBean中,通过interceptorNames属性来配置已经定义好的通知器Advisor。虽然名字为interceptorNames,但实际上却是供AOP应用配置通知器的地方。在ProxyFactoryBean中,需要为target目标对象生成Proxy代理对象,从而为AOP横切面的编程做好准备工作。
ProxyFactoryBean的AOP实现需要依赖JDK或者CGLIB提供的Proxy特性。从FactoryBean中获取对象,是以getObject()方法作为入口完成的;ProxyFactoryBean实现中的getObject方法,是FactoryBean需要实现的接口。对ProxyFactoryBean来说,把需要对target目标对象增强处理,都通过getObject方法进行封装了,这些增强处理是为AOP功能的实现提供服务的。getObject的实现如下。getObject方法首先对通知器链进行初始化,通知器链封装了一系列的拦截器,这些拦截器都要从配置中读取,然后为代理对象的生成做好准备。在生成代理对象时,因为Spring中有singleton类型和prototype类型这两种不同的Bean,所以要对代理对象的生成做一个区分。
public Object getObject() throws BeansException {
//初始化通知器链
initializeAdvisorChain();
//这里对singleton和prototype的类型进行区分,生成对应的proxy
if (isSingleton()) {
return getSingletonInstance();
}
else {
if (this.targetName == null) {
logger.warn("Using non-singleton proxies with singleton targets is often undesirable. " +
"Enable prototype proxies by setting the 'targetName' property.");
}
return newPrototypeInstance();
}
}
为Proxy代理对象配置Advisor链是在initializeAdvisorChain方法中完成的,如下代码所示。这个初始化过程中有一个标志位advisorChainInitialized,这个标志用来表示通知器链是否已经初始化。如果已经初始化,那么这里就不会再初始化,而是直接返回。也就是说,这个初始化工作发生在应用第一次通过ProxyFactoryBean去获取代理对象的时候。在完成这个初始化之后,接着会读取配置中出现的所有通知器,这个取得通知器的过程也比较简单,把通知器的名字交给容器的getBean方法就可以了,这是通过对IoC容器实现的一个回调来完成的。然后把从IoC容器中取得的通知器加入拦截器链中这个动作是由addAdvisorOnChainCreation方法来实现的。
private synchronized void initializeAdvisorChain() throws AopConfigException, BeansException {
if (this.advisorChainInitialized) {
return;
}
if (!ObjectUtils.isEmpty(this.interceptorNames)) {
if (this.beanFactory == null) {
throw new IllegalStateException("No BeanFactory available anymore (probably due to serialization) " +
"- cannot resolve interceptor names " + Arrays.asList(this.interceptorNames));
}
// Globals can't be last unless we specified a targetSource using the property...
if (this.interceptorNames[this.interceptorNames.length - 1].endsWith(GLOBAL_SUFFIX) &&
this.targetName == null && this.targetSource == EMPTY_TARGET_SOURCE) {
throw new AopConfigException("Target required after globals");
}
// Materialize interceptor chain from bean names.
// 这里添加Advisor链的调用,是通过interceptorNames属性进行配置的
for (String name : this.interceptorNames) {
if (logger.isTraceEnabled()) {
logger.trace("Configuring advisor or advice '" + name + "'");
}
if (name.endsWith(GLOBAL_SUFFIX)) {
if (!(this.beanFactory instanceof ListableBeanFactory)) {
throw new AopConfigException(
"Can only use global advisors or interceptors with a ListableBeanFactory");
}
addGlobalAdvisor((ListableBeanFactory) this.beanFactory,
name.substring(0, name.length() - GLOBAL_SUFFIX.length()));
}
else {
// If we get here, we need to add a named interceptor.
// We must check if it's a singleton or prototype.
/*
* 如果程序在这里被调用,那么需要加入命名的拦截器advice,并且需要检查这个
* Bean是singleton还是prototype类型
*/
Object advice;
// 如果是singleton类型Bean
if (this.singleton || this.beanFactory.isSingleton(name)) {
// Add the real Advisor/Advice to the chain.
// 加入advice或者advisor
advice = this.beanFactory.getBean(name);
}
else {
// It's a prototype Advice or Advisor: replace with a prototype.
// Avoid unnecessary creation of prototype bean just for advisor chain initialization.
// 对prototype类型Bean的处理
advice = new PrototypePlaceholderAdvisor(name);
}
addAdvisorOnChainCreation(advice, name);
}
}
}
this.advisorChainInitialized = true;
}
生成singleton的代理对象在getSingletonInstance()的代码中完成,这个方法是ProxyFactoryBean生成AopProxy代理对象的调用入口。代理对象会封装对target目标对象的调用,也就是说针对target对象的方法调用行为会被这里生成的代理对象所拦截。具体的生成过程是,首先读取ProxyFactoryBean中的配置,为生成代理对象做好必要的准备,比如设置代理的方法调用接口方法等。Spring通过AopProxy类来具体生成代理对象。对于getSingletonInstance()方法中代理对象的生成过程,如下:
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.
// 根据AOP框架来判断需要代理的接口
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);
// 这里的方法会使用ProxyFactory来生成需要的Proxy
this.singletonInstance = getProxy(createAopProxy());
}
return this.singletonInstance;
}
// 通过createAopProxy返回AopProxy来得到代理对象
protected Object getProxy(AopProxy aopProxy) {
return aopProxy.getProxy(this.proxyClassLoader);
}
这里出现了AopProxy类型的对象,Spring利用这个AopProxy接口类把AOP代理对象的实现与框架的其他部分有效地分离开来。AopProxy是一个接口,它由两个子类实现,一个是CglibAopProxy,另一个是JdkDuynamicProxy。顾名思义,对这两个AopProxy接口的子类的实现,Spring分别通过CGLIB和JDK来生成需要的Proxy代理对象。
具体的代理对象的生成,是在ProxyFactoryBean的基类AdvisedSupport的实现中借助AopProxyFactory完成的,这个代理对象要么从JDK中生成,要么借助CGLIB获得。因为ProxyFactoryBean本身就是AdvisedSupport的子类,所以在ProxyFactoryBean中获得AopProxy是很方便的,可以在ProxyCreatorupport中看到,具体的AopProxy是通过AopProxyFactory来生成的。需要什么样的代理对象,所有信息都封装在AdvisedSupport里,这个对象也是生成AopProxy的方法的输入参数,这里设置为thsi本身,因为ProxyCreatorSupport本身就是Advisedupport的子类。在ProxyCreatorSupport中生成代理对象的入口,如下:
protected final synchronized AopProxy createAopProxy() {
if (!this.active) {
activate();
}
// 通过定义AopProxyFactory取得AopProxy,这个AopProxyFactory是在初始化函数中定义的
// 使用的是DefaultAopProxyFactory
return getAopProxyFactory().createAopProxy(this);
}
关于AopProxy代理对象的生成,需要考虑使用哪种生成方式,如果目标对象是接口类,那么适合使用JDK来生成代理对象,否则Spring会使用CGLIB来生成目标对象的代理对象。我们可以在DefaultAopProxyFactory中看到相应的实现。
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
Class<?> targetClass = config.getTargetClass();
if (targetClass == null) {
throw new AopConfigException("TargetSource cannot determine target class: " +
"Either an interface or a target is required for proxy creation.");
}
// 如果targetClass是接口类,使用JDK来生成Proxy
if (targetClass.isInterface()) {
return new JdkDynamicAopProxy(config);
}
// 如果不是接口类要生成Proxy,那么使用CGLIB来生成
return new ObjenesisCglibAopProxy(config);
}
else {
return new JdkDynamicAopProxy(config);
}
}
JDK生成AopProxy代理对象
ProxyFactoryBean在AopProxy代理对象和IoC容器配置之间起到了桥梁的作用,这个桥梁作用体现在它为代理对象的最终生成做好了准备。AopProxy代理对象可以由JDK或CGLIB来生成,而JdkDynamicAopProxy和CglibAopProxy实现的都是通过AopProxy接口,他们的层次关系如图。
在AopProxy的接口下,设计了CglibAopProxy和JdkDynamicAopProxy两种Proxy代理对象的实现,而AopProxy的接口设计也很简单,就是获得Proxy代理对象。获得Proxy代理对象的方式有两种,一种是需要指定ClassLoader,另一种方式则不需要指定。
在JdkDynamicAopProxy中,用了JDK的Proxy类来生成代理对象,在生成Proxy对象之前,首先需要通过从advised对象中取得代理对象的代理接口配置,然后调用Proxy的newProxyInstance方法,最终得到对应的Proxy代理对象。在生成代理对象时,需要指明三个参数,一个是类加载器,一个是代理接口,另一个就是Proxy回调方法所在的对象,这个对象需要实现InvocationHandler接口。这个InvocationHandler接口定义了invoke方法,提供代理对象的回调入口。对于JdkDynamicAopProxy,它本身实现了InvocationHandler接口和invoke方法,这个invoke方法是Proxy代理对象的回调方法,所以可以使用this来把JdkDynamicAopProxy指派给Proxy对象,也就是说JdkDynamicAopProxy对象本身,在Proxy代理的接口方法被调用时,会触发invoke方法的回调,这个回调方法完成了AOP在编织实现的封装。
public Object getProxy(ClassLoader classLoader) {
if (logger.isDebugEnabled()) {
logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());
}
Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised);
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
// 这是调用JDK生成Proxy的
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
CGLIB生成AopProxy代理对象
public Object getProxy(ClassLoader classLoader) {
if (logger.isDebugEnabled()) {
logger.debug("Creating CGLIB proxy: target source is " + this.advised.getTargetSource());
}
// 从advised中取得在IoC容器中配置的target对象
try {
Class<?> rootClass = this.advised.getTargetClass();
Assert.state(rootClass != null, "Target class must be available for creating a CGLIB proxy");
Class<?> proxySuperClass = rootClass;
if (ClassUtils.isCglibProxyClass(rootClass)) {
proxySuperClass = rootClass.getSuperclass();
Class<?>[] additionalInterfaces = rootClass.getInterfaces();
for (Class<?> additionalInterface : additionalInterfaces) {
this.advised.addInterface(additionalInterface);
}
}
// Validate the class, writing log messages as necessary.
validateClassIfNecessary(proxySuperClass);
// Configure CGLIB Enhancer...
// 验证代理对象的接口设置
// 创建并配置CGLIB的Enhancer,这个Enhancer对象是CGLIB的主要操作类
Enhancer enhancer = createEnhancer();
if (classLoader != null) {
enhancer.setClassLoader(classLoader);
if (classLoader instanceof SmartClassLoader &&
((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
enhancer.setUseCache(false);
}
}
// 设置Enhancer对象,包括设置代理接口,回调方法
// 来自advised的IoC配置,比如使用AOP的DynamicAdvisedInterceptor拦截器
enhancer.setSuperclass(proxySuperClass);
enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
enhancer.setStrategy(new UndeclaredThrowableStrategy(UndeclaredThrowableException.class));
Callback[] callbacks = getCallbacks(rootClass);
Class<?>[] types = new Class<?>[callbacks.length];
for (int x = 0; x < types.length; x++) {
types[x] = callbacks[x].getClass();
}
// fixedInterceptorMap only populated at this point, after getCallbacks call above
enhancer.setCallbackFilter(new ProxyCallbackFilter(
this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
enhancer.setCallbackTypes(types);
// Generate the proxy class and create a proxy instance.
// 通过Enhancer生成代理对象
return createProxyClassAndInstance(enhancer, callbacks);
}
catch (CodeGenerationException ex) {
throw new AopConfigException("Could not generate CGLIB subclass of class [" +
this.advised.getTargetClass() + "]: " +
"Common causes of this problem include using a final class or a non-visible class",
ex);
}
catch (IllegalArgumentException ex) {
throw new AopConfigException("Could not generate CGLIB subclass of class [" +
this.advised.getTargetClass() + "]: " +
"Common causes of this problem include using a final class or a non-visible class",
ex);
}
catch (Exception ex) {
// TargetSource.getTarget() failed
7 throw new AopConfigException("Unexpected AOP exception", ex);
}
}
我们在上述代码中可以看到对CGLIB的使用,如对Enhancer对象的配置,以及通过Enhancer对象生成代理对象的过程。需要注意的是对Enhancer对象callback回调的设置,正是这些回调封装了Spring AOP的实现,就像前面介绍的JDK的Proxy对象的invoke回调方法一样。在Enhancer的callback回调设置中,实际上是通过设置DynamicAdvisedInterceptor拦截器来完成AOP功能的,我们可以在getCallbacks方法实现中看到回调DynamicAdvisedInterceptor的设置。
Callback aopInterceptor = new DynamicAdvisedInterceptor(this.advised);
这样,通过使用AopProxy对象封装target目标对象之后,ProxyFactoryBean的getObject方法得到的对象就不是一个普通的java对象了,而是一个AopProxy代理对象。在ProxyFactoryBean中配置的target目标对象,这时已经不会让应用直接调用其它方法实现,而是作为AOP实现的一部分。对target目标对象的方法调用会首先被Aopproxy代理对象拦截,对于不同的AopProxy代理对象的生成方式,会使用不同的拦截器回调入口。如,对于JDK的AopProxy代理对象,使用的是InvocationHandler的invoke回调入口;而对于CGLIB的AopProxy代理对象,使用的是设置好的callback回调,这是由于对CGLIB的使用来决定的。在这些callback回调中,对于AOP的实现,是通过DynamicAdvisedInterceptor来完成的,而DynamicAdvisedInterceptor的回调入口是interceptor方法。在这个基础上,AOP的Advisor已经可以通过AopProxy代理对象的拦截机制,对需要它进行增强的target目标对象发挥切面的威力了。
可以把AOP的实现部分看成由基础设施准备和AOP运行辅助这两个部分组成,这里的AopProxy代理对象的生成,可以看成是一个静态的AOP基础设施的建立过程。通过这个准备过程,把代理对象、拦截器这些待调用的部分准备好,等待着AOP运行过程中对这些基础设施的使用。对于应用触发的AOP应用,会涉及AOP框架的运行和对AOP基础设施的使用。这些动态的运行部分,是从前面提到的拦截器回调入口开始的,这些拦截器调用的实现原理和AopProxy代理对象生成一样。
Spring AOP拦截器调用的实现
在Spring AOP通过JDK的Proxy方式或CGLIB方式生成代理对象的时候,相关的拦截器已经配置到代理对象中去了,拦截器在代理对象中起作用是通过对这些方法的回调来完成的。
JdkDynamicAopProxy的invoke拦截
在JdkDynamicAopProxy中生成Proxy对象时,我们看一下它的AopProxy代理对象的生成调用,如下:
Proxy.newProxyInstance(classLoader, proxiedInterface, this);
这里的this参数对应的是InvocationHandler对象,InvocationHandler是JDK定义的反射类的一个接口,这个接口定义了invoke方法,而这个invoke方法是作为JDK Proxy代理对象进行拦截的回调入口出现的。在JDKDynamicAopProxy中实现了InvocationHandler接口,也就是说当Proxy对象的代理方法被调用时,JdkDynamicAopProxy的invoke方法作为Proxy对象的回调函数被触发,从而通过invoke的具体实现,来完成对目标对象方法调用的拦截。JdkDynamicAopProxy的invoke方法实现了如下代码。从下面的代码中可以看到,对Proxy对象的代理设置是在invoke方法中完成的,这些设置包括获取目标对象、拦截器链,同时把这些对象作为输入,创建了ReflectiveMethodInvocation对象,通过这个ReflectiveMethodInvocation对象来完成对AOP功能实现的封装。在这个invoke方法中,包含了一个完整的拦截器链对目标对象的拦截过程,比如获得拦截器并对拦截器链中的拦截器进行配置,逐个运行拦截器链里的拦截增强,直到最后对目标对象方法的运行。
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
MethodInvocation invocation;
Object oldProxy = null;
boolean setProxyContext = false;
TargetSource targetSource = this.advised.targetSource;
Class<?> targetClass = null;
Object target = null;
try {
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
// The target does not implement the equals(Object) method itself.
// 如果目标对象没有实现Object类的基本方法:equals
return equals(args[0]);
}
if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
// The target does not implement the hashCode() method itself.
// 如果目标对象没有实现Object类的基本方法:hashCode
return hashCode();
}
if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
method.getDeclaringClass().isAssignableFrom(Advised.class)) {
// Service invocations on ProxyConfig with the proxy config...
// 根据代理对象的配置来调用服务
return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
}
Object retVal;
if (this.advised.exposeProxy) {
// Make invocation available if necessary.
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// May be null. Get as late as possible to minimize the time we "own" the target,
// in case it comes from a pool.
// 得到目标对象的地方
target = targetSource.getTarget();
if (target != null) {
targetClass = target.getClass();
}
// Get the interception chain for this method.
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
// Check whether we have any advice. If we don't, we can fallback on direct
// reflective invocation of the target, and avoid creating a MethodInvocation.
// 如果没有设定拦截器,那么就直接调用target的对应方法
if (chain.isEmpty()) {
// We can skip creating a MethodInvocation: just invoke the target directly
// Note that the final invoker must be an InvokerInterceptor so we know it does
// nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, args);
}
else {
// We need to create a method invocation...
// 如果有拦截器的设定,那么需要调用拦截器之后才调用目标对象的相应方法
// 通过构造一个ReflectiveMethodInvocation来实现
invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// Proceed to the joinpoint through the interceptor chain.
// 沿着拦截器链继续前进
retVal = invocation.proceed();
}
// Massage return value if necessary.
Class<?> returnType = method.getReturnType();
if (retVal != null && retVal == target && returnType.isInstance(proxy) &&
!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
// Special case: it returned "this" and the return type of the method
// is type-compatible. Note that we can't help if the target sets
// a reference to itself in another returned object.
retVal = proxy;
} else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
throw new AopInvocationException("Null return value from advice does not match primitive return type for: " + method);
}
return retVal;
}
finally {
if (target != null && !targetSource.isStatic()) {
// Must have come from TargetSource.
targetSource.releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);
}
}
}
CglibAopProxy的interceptor拦截
我们知道对于AOP的拦截调用,其回调是 在DynamicAdvisedInterceptor对象中实现的,这个回调的实现在interceptor方法中,如下代码所示。CglibAopProxy的interceptor回调方法的实现和JdkDynamicAopProxy的回调时非常类似的,只是在CglibAopProxy中构造CglibMethodInvocation对象来完成拦截器链的调用,而在JdkDynamicAopProxy中是通过构造ReflectiveMethodInvocation对象来完成这个功能的。
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
Class<?> targetClass = null;
Object target = null;
try {
if (this.advised.exposeProxy) {
// Make invocation available if necessary.
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// May be null. Get as late as possible to minimize the time we
// "own" the target, in case it comes from a pool...
target = getTarget();
if (target != null) {
targetClass = target.getClass();
}
// 从advised中取得配置好的AOP通知
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
Object retVal;
// Check whether we only have one InvokerInterceptor: that is,
// no real advice, but just reflective invocation of the target.
// 如果没有AOP通知配置,那么直接调用target对象的调用方法
if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
// We can skip creating a MethodInvocation: just invoke the target directly.
// Note that the final invoker must be an InvokerInterceptor, so we know
// it does nothing but a reflective operation on the target, and no hot
// swapping or fancy proxying.
retVal = methodProxy.invoke(target, args);
}
else {
// We need to create a method invocation...
// 通过CglibMethodInvocation来启动advice通知
retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
}
retVal = processReturnType(proxy, target, method, retVal);
return retVal;
}
finally {
if (target != null) {
releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);
}
}
}
目标对象方法的调用
如果没有设置拦截器,那么会对目标对象的方法直接进行调用。对于JdkDynamicAopProxy代理对象,这个对目标对象的方法调用是通过AopUtils使用反射机制在AopUtils.invokeJoinpointUsingReflection的方法中实现的,如下代码。在这个调用中,首先得到调用方法的反射对象,然后使用invoke启动对方法反射对象的调用。
public static Object invokeJoinpointUsingReflection(Object target, Method method, Object[] args)
throws Throwable {
// Use reflection to invoke the method.
// 使用反射调用target对象方法的地方
try {
ReflectionUtils.makeAccessible(method);
return method.invoke(target, args);
}
catch (InvocationTargetException ex) {
// Invoked method threw a checked exception.
// We must rethrow it. The client won't see the interceptor.
// 抛出AOP异常,对异常进行转换
throw ex.getTargetException();
}
catch (IllegalArgumentException ex) {
throw new AopInvocationException("AOP configuration seems to be invalid: tried calling method [" +
method + "] on target [" + target + "]", ex);
}
catch (IllegalAccessException ex) {
throw new AopInvocationException("Could not access method [" + method + "]", ex);
}
}
对于使用CglibAopProxy的代理对象,它对目标对象的调用是通过CGLIB的MethodProxy对象来直接完成的,这个对象的使用是由CGLIB的设计来决定的。具体的调用在DynamicAdvisedinterceptor的interceptor方法中可以看到,使用的是CGLIB封装好的功能,相对JdkDynamicAopProxy的实现来说,形式较为简单,但他们的功能却是一样的,都是完成对目标对象方法的调用,代码如下:
retVal = methodProxy.invoke(target, args);
AOP拦截器链的调用
AOP是怎样完成对目标对象的增强的?这些实现封装在AOP拦截器链中,由一个个具体的拦截器来完成。
使用JDK和CGLIB会生成不同的AopProxy代理对象,从而构造了不同的回调方法来启动对拦截器链的调用,虽然它们使用了不同的AopProxy代理对象,但最终对AOP拦截的处理可谓殊途同归:他们对拦截器链的调用都是在ReflectiveMethodInvocation中proceed方法实现的。在proceed方法中,会逐个运行拦截器的拦截方法。在运行拦截器的拦截方法之前,需要对代理对象方法完成一个匹配判断,通过这个匹配判断来决定拦截器是否满足切面增强的要求。前面提到,在pointcut切点中需要进行matches的匹配过程,即matches调用方法进行匹配判断,来决定是否需要实行通知增强。以下看到的调用就是进行matches的地方,具体的处理过程在ReflectiveMethodInvocation的proceed方法中,如下代码,在proceed方法中,先进行判断,如果现在已经运行到拦截器链的末尾,那么就会直接调用目标对象的实现方法;否则,沿着拦截器链继续进行,得到下一个拦截器,通过这个拦截器进行matches判断,判断是否适用于横切增强的场合,如果是,从拦截器中得到通知器,并启动通知器的invoke方法进行切面增强。在这个过程结束以后,会迭代调用proceed方法,直到拦截器链中的拦截器都完成以上的拦截过程为止。
public Object proceed() throws Throwable {
// We start with an index of -1 and increment early.
// 从索引为-1的拦截器开始调用,并按序递增
// 如果拦截器链中的拦截器迭代调用完毕,这里开始调用target的函数
// 这个函数是通过反射机制完成的,具体实现在AopUtils.invokeJoinpointUsingReflection方法中
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
// 这里沿着定义好的interceptorOrInterceptionAdvice链进行处理
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
// Evaluate dynamic method matcher here: static part will already have
// been evaluated and found to match.
// 这里对拦截器进行动态匹配的判断,前面分析的pointcut,这里是触发进行匹配的地方,如果和定义的Pointcut匹配
// 那么这个advice将会得到执行
InterceptorAndDynamicMethodMatcher dm =
(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
return dm.interceptor.invoke(this);
}
else {
// Dynamic matching failed.
// Skip this interceptor and invoke the next in the chain.
// 如果不匹配,那么proceed会被递归调用,直到所有的拦截器都被运行过为止
return proceed();
}
}
else {
// It's an interceptor, so we just invoke it: The pointcut will have
// been evaluated statically before this object was constructed.
// 如果是一个interceptor,直接调用这个interceptor对应的方法
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
以上就是整个拦截器及target目标对象方法被调用的过程。我们已经看到了对advice通知的调用入口了。下面我们就会围绕它进行分析。
配置通知器
在整个AopProxy代理对象的拦截回调过程中,先回到ReflectiveMethodInvocation类的proceed方法。在这个方法里,可以看到得到了配置的interceptorOrInterceptionAdvice,如下:
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
这个interceptedptorOrInterceptionAdvice是获得的拦截器,他通过拦截器机制对目标对象的行为增强起作用。这个拦截器来自interceptorsAndDynamicMethodMatchers,具体来说,它是interceptorsAndDynamicMethodMatchers持有的List中的一个元素。关于如何配置拦截器的问题,就转化为这个List中的拦截器元素是从哪里来的,在哪里配置的问题。接着对invoke调用进行回放,回到JdkDynamicAopProxy中的invoke方法中,可以看到这个List中的interceptors是在哪个调用中获取的。对于CglibAopProxy,这个过程是在DynamicAdvisedInterceptor的interceptor回调中实现的,如下:
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
在上面的代码中可以看到,获取interceptors的操作是由advised对象完成的,这个advised是一个AdvisedSupport对象,从类的继承关系上看,这个AdvisedSupport类同时也是ProxyFactoryBean的基类。从AdvisedSupport的代码中可以看到getInterceptorsAndDynamicInterceptionAdvice的实现,如下,在这个方法中取得了拦截器链,在取得拦截器链的时候,为提高取得拦截器链的效率,还为这个拦截器链设置了缓存。
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, Class<?> targetClass) {
// 这里使用了cache,利用cache去获取已有的interceptor链,但是第一次还是需要自己动手生成的
// 这个interceptor链的生成是由advisorChainFactory完成的
// 在这里使用的是DefaultAdvisorChainFactory
MethodCacheKey cacheKey = new MethodCacheKey(method);
List<Object> cached = this.methodCache.get(cacheKey);
if (cached == null) {
cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
this, method, targetClass);
this.methodCache.put(cacheKey, cached);
}
return cached;
}
取得拦截器链的工作是由配置好的advisorChainFactory来完成的,从名字上可以猜到,它是一个生成通知器链的工厂。在这里,advisorChainFactory被配置为一个DafaultAdvisorChainFactory对象,在DefaultAdvisorChainFactory中实现了interceptor链的获取过程,如下代码所示。在这个获取过程中,首先设置了一个List。其长度是由配置的通知器的个数来决定的,这个配置就是在XML中对ProxyFactoryBean做的interceptNames属性的配置。然后,DefaultAdvisorChainFactory会通过一个AdvisorAdapterRegistry来实现拦截器的注册,AdvisorAdapterRegisty对advice通知的织入功能起了很大的作用。有了AdvisorAdapterRegistry注册器,利用它来对从ProxyFactoryBean配置中得到的通知进行适配,从而获得相应的拦截器,再把它加入前面设置好的List中去,完成所谓的拦截器注册过程。在拦截器适配和注册过程完成以后,List中的拦截器会被JDK生成的AopProxy代理对象的invoke方法或者CGLIB代理对象的intercept拦截方法取得,并启动拦截器的invoke调用,最终会触发通知的切面增强。
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
Advised config, Method method, Class<?> targetClass) {
// This is somewhat tricky... we have to process introductions first,
// but we need to preserve order in the ultimate list.
// advisor链已经在config中持有了,这里可以直接使用
List<Object> interceptorList = new ArrayList<Object>(config.getAdvisors().length);
boolean hasIntroductions = hasMatchingIntroductions(config, targetClass);
AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
for (Advisor advisor : config.getAdvisors()) {
if (advisor instanceof PointcutAdvisor) {
// Add it conditionally.
PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(targetClass)) {
// 拦截器链是通过AdvisorAdapterRegistry来加入的,这个AdvisorAdapterRegistry
// 对advice织入起了很大的作用
MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
// 使用MethodMatchers的matches方法进行匹配判断
if (MethodMatchers.matches(mm, method, targetClass, hasIntroductions)) {
if (mm.isRuntime()) {
// Creating a new object instance in the getInterceptors() method
// isn't a problem as we normally cache created chains.
for (MethodInterceptor interceptor : interceptors) {
interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
}
}
else {
interceptorList.addAll(Arrays.asList(interceptors));
}
}
}
}
else if (advisor instanceof IntroductionAdvisor) {
IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
if (config.isPreFiltered() || ia.getClassFilter().matches(targetClass)) {
Interceptor[] interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}
}
else {
Interceptor[] interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}
}
return interceptorList;
}
/**
* Determine whether the Advisors contain matching introductions.
*/
// 判断Advisor是否符合配置要求
private static boolean hasMatchingIntroductions(Advised config, Class<?> targetClass) {
for (int i = 0; i < config.getAdvisors().length; i++) {
Advisor advisor = config.getAdvisors()[i];
if (advisor instanceof IntroductionAdvisor) {
IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
if (ia.getClassFilter().matches(targetClass)) {
return true;
}
}
}
return false;
}
事实上,这里的advisor通知器是从AdvisorSupport中取得的,从对它的调用中可以清楚的看到。
在ProxyFactoryBean的getObject方法中对advisor进行初始化时,从XML配置中获取了advisor通知器。在ProxyFactoryBean中,对advisor进行初始化的代码实现如下所示。在这个初始化的advisor中,可以看到对IoC容器的一个getBean回调,通过对这个IoC容器的getBean调用来得到配置好的advisor通知器。
private synchronized void initializeAdvisorChain() throws AopConfigException, BeansException {
if (this.advisorChainInitialized) {
return;
}
if (!ObjectUtils.isEmpty(this.interceptorNames)) {
if (this.beanFactory == null) {
throw new IllegalStateException("No BeanFactory available anymore (probably due to serialization) " +
"- cannot resolve interceptor names " + Arrays.asList(this.interceptorNames));
}
// Globals can't be last unless we specified a targetSource using the property...
if (this.interceptorNames[this.interceptorNames.length - 1].endsWith(GLOBAL_SUFFIX) &&
this.targetName == null && this.targetSource == EMPTY_TARGET_SOURCE) {
throw new AopConfigException("Target required after globals");
}
// Materialize interceptor chain from bean names.
for (String name : this.interceptorNames) {
if (logger.isTraceEnabled()) {
logger.trace("Configuring advisor or advice '" + name + "'");
}
if (name.endsWith(GLOBAL_SUFFIX)) {
if (!(this.beanFactory instanceof ListableBeanFactory)) {
throw new AopConfigException(
"Can only use global advisors or interceptors with a ListableBeanFactory");
}
addGlobalAdvisor((ListableBeanFactory) this.beanFactory,
name.substring(0, name.length() - GLOBAL_SUFFIX.length()));
}
else {
// If we get here, we need to add a named interceptor.
// We must check if it's a singleton or prototype.
// 需要对Bean的类型进行判断,是单件类型还是prototype类型
Object advice;
if (this.singleton || this.beanFactory.isSingleton(name)) {
// Add the real Advisor/Advice to the chain.
// 这里是取得advisor的地方,是通过beanFactory取得的
// 把interceptorNames这个List中的interceptor名字
// 交给beanFactory,然后通过调用BeanFactory的getBean去获取
advice = this.beanFactory.getBean(name);
}
else {
// It's a prototype Advice or Advisor: replace with a prototype.
// Avoid unnecessary creation of prototype bean just for advisor chain initialization.
// 如果Bean的类型是prototype类型
advice = new PrototypePlaceholderAdvisor(name);
}
addAdvisorOnChainCreation(advice, name);
}
}
}
this.advisorChainInitialized = true;
}
advisor通知器的取得是委托给IoC容器完成的,但是在ProxyFactoryBean中如何获得IoC容器,然后通过回调IoC容器的getBean方法来得到需要的通知器advisor的呢?这涉及到IoC容器的实现原理,在使用DefaultListableBeanFactory作为IoC容器的时候,它的基类是AbstractAutowireCapableBeanFactory,在这个基类中可以看到一个对Bean进行初始化的initializeBean方法。在这个Bean 的初始化过程中,对IoC容器在Bean中的回调进行了设置。这个设置为,首先,判断这个Bean 的类型是不是实现了BeanFactoryAware接口,如果是,那么它一定实现了BeanFactoryAware定义的接口方法,通过这个接口方法,可以吧IoC容器设置到Bean自身定义的一个属性中去。这样,在这个Bean的自身实现中,就能够得到他所在的IoC容器,从而调用IoC容器的getBean方法,完成对IoC容器的回调,就像一个有特异功能的Bean一样,除了使用为自己设计的功能之外,还可以去调用它所在的容器的功能,如下:
if (bean instanceof BeanFactoryAware) {
((BeanFactoryAware) bean).setBeanFactory((BeanFactory) this);
}
对于IoC容器的使用,如果需要回调容器,前提是当前的Bean需要实现BeanFactoryAware接口,这个接口只需要实现一个接口方法setBeanFactory,同时设置一个属性来持有BeanFactory的IoC容器,就可以在Bean中取得IoC容器进行回调了。在IoC容器对Bean进行初始化的时候,会对Bean 的类型进行判断,如果这是一个BeanFactoryAware的Bean类型,那么IoC容器会调用这个Bean 的setBeanFactory方法,完成对这个BeanFactory在Bean中的设置。具体为,ProxyFactoryBean实现了这个接口,所以在它的初始化完成以后,可以在Bean中使用容器进行回调。这里设置的this对象,就是Bean所在的IoC容器,一般是DefaultListableBeanFactory对象,在得到这个设置好的BeanFactory以后,ProxyFactoryBean就可以通过回调容器的getBean去获取配置在Bean定义文件中的通知器了,获取通知器就是想IoC容器回调getBean的过程。这个getBean是IoC容器一个非常基本的方法。在调用时,ProxyFactoryBean需要给出通知器的名字,而这些名字都是在interceptorNames的List中已经配置好的,在IoC对FactoryBean进行依赖注入时,会直接注入到FactoryBean 的interceptorNames属性中。完成这个过程以后,ProxyFactoryBean就获得了配置的通知器,为完成切面增强做好准备。
Advice通知的实现
经过前面的分析,我们看到在AopProxy代理对象生成时,其拦截器也同样建立起来了,但是,对于AOP实现的重要部分,Spring AOP定义的通知是怎样实现对目标对象的增强的呢?在为AopProxy代理对象配置拦截器的实现中,有一个取得拦截器的配置过程,这个过程是由DefaultAdvisorChainFactory实现的,而这个工厂类负责生产拦截器链,在它的getInterceptorsAndDynamicInterceptionAdvice方法中,有一个适配和注册过程,在这个适配和注册过程中,通过配置Spring预先设计好的拦截器,Spring加入了它对AOP实现的处理。为详细了解这个过程,我们先从DefaultAdvisorChainFactory的实现开始,如下代码,可以看到,在DefaultAdvisorChainFactory的实现中,首先构造了一个GlobalAdvisorAdapterRegistry单件,然后,对配置的Advisor通知器进行逐个遍历,这些通知器链都是配置在interceptorNames中的,从getInterceptorsAndDynamicInterceptionAdvice传递进来的advised参数对象中,可以方便地取得配置的通知器,有了这些通知器,接着就是一个由GlobalAdvisorAdapterRegistry来完成的拦截器的适配和注册过程。
//得到注册器GlobalAdvisorAdapterRegistry,这是一个单件模式的实现
AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
for (Advisor advisor : config.getAdvisors()) {
if (advisor instanceof PointcutAdvisor) {
// Add it conditionally.
PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(targetClass)) {
MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
if (MethodMatchers.matches(mm, method, targetClass, hasIntroductions)) {
if (mm.isRuntime()) {
// Creating a new object instance in the getInterceptors() method
// isn't a problem as we normally cache created chains.
// 在getInterceptors()方法中创建新的对象实例
for (MethodInterceptor interceptor : interceptors) {
interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
}
}
else {
interceptorList.addAll(Arrays.asList(interceptors));
}
}
}
}
}
看如下代码,GlobalAdvisorAdapterRegistry的实现很简洁,起到的基本上是一个适配器的作用,但同时它也是一个单件模式的应用,为Spring AOP模块提供了一个DefaultAdvisorAdapterRegistry单件,这个DefaultAdvisorAdapterRegistry由他来完成各种通知的适配和注册工作。
public abstract class GlobalAdvisorAdapterRegistry {
private static AdvisorAdapterRegistry instance = new DefaultAdvisorAdapterRegistry();
public static AdvisorAdapterRegistry getInstance() {
return instance;
}
static void reset() {
instance = new DefaultAdvisorAdapterRegistry();
}
}
可以看出,GlobalAdvisorAdapterRegistry是一个标准的单件模式的实现,它配置了一个静态的final变量instance,这个对象是在加载类的时候就生成的,而且GlobalAdvisorAdapterRegistry还是一个抽象类,不能被实例化,这样就保证了instance对象的唯一性。在使用这个instance的时候,也是通过一个静态方法getInstnce()来完成的,这样就保证了这个instance唯一对象的获取。
在DefaultAdvisorAdapterRegistry中,设置了一系列的adapter适配器,正是这些adapter适配器的实现,为Spring AOP的advice提供编织能力。我们可以看一下DefaultAdvisorAdapterRegistry中究竟发生了什么?如下代码,首先,我们看到了一系列在AOP应用中与用到的Spirng AOP的advice通知相对应的adapter适配实现,并看到了对这些adapter的具体使用。具体来说,对他们的使用主要体现在以下两个方面:一是调用adapter的support方法,通过这个方法来判断取得的advice属于什么类型的advice通知,从而根据不同的advice类型来注册不同的AdviceInterceptor,也就是前面看到的那些拦截器;另一方面,这些AdviceInterceptor都是Spring AOP框架设计好的,是为了实现不同的advice来设计AOP应用。也就是说,正是这些AdviceInterceptor最终实现了advice通知在AopProxy代理对象中的织入功能。
public class DefaultAdvisorAdapterRegistry implements AdvisorAdapterRegistry, Serializable {
// 持有一个AdvisorAdapter的List,这个List中的Adapter是与实现
// spring AOP的advice增强功能相对应的
private final List<AdvisorAdapter> adapters = new ArrayList<AdvisorAdapter>(3);
/**
* Create a new DefaultAdvisorAdapterRegistry, registering well-known adapters.
*/
// 这里把已有的advice实现的Adapter加入进来,有非常熟悉的
// MethodBeforeAdvice、AfterReturningAdvice、ThrowsAdvice
// 这些AOP的advice封装实现
public DefaultAdvisorAdapterRegistry() {
registerAdvisorAdapter(new MethodBeforeAdviceAdapter());
registerAdvisorAdapter(new AfterReturningAdviceAdapter());
registerAdvisorAdapter(new ThrowsAdviceAdapter());
}
@Override
public Advisor wrap(Object adviceObject) throws UnknownAdviceTypeException {
if (adviceObject instanceof Advisor) {
return (Advisor) adviceObject;
}
if (!(adviceObject instanceof Advice)) {
throw new UnknownAdviceTypeException(adviceObject);
}
Advice advice = (Advice) adviceObject;
if (advice instanceof MethodInterceptor) {
// So well-known it doesn't even need an adapter.
return new DefaultPointcutAdvisor(advice);
}
for (AdvisorAdapter adapter : this.adapters) {
// Check that it is supported.
if (adapter.supportsAdvice(advice)) {
return new DefaultPointcutAdvisor(advice);
}
}
throw new UnknownAdviceTypeException(advice);
}
@Override
// 这里是在DefaultAdvisorChainFactory中启动的getInterceptors方法
public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {
List<MethodInterceptor> interceptors = new ArrayList<MethodInterceptor>(3);
// 从Advisor通知器中取得advice通知
Advice advice = advisor.getAdvice();
// 如果通知是MethodInterceptor类型的通知,直接加入interceptors的List中,不需要适配
if (advice instanceof MethodInterceptor) {
interceptors.add((MethodInterceptor) advice);
}
// 对通知进行适配,使用已经配置好的Adapter:MethodBeforeAdviceAdapter
// AfterReturningAdviceAdapter以及ThrowsAdviceAdapter
// 然后从对应的adapter中取出封装好AOP编织功能的拦截器
for (AdvisorAdapter adapter : this.adapters) {
if (adapter.supportsAdvice(advice)) {
interceptors.add(adapter.getInterceptor(advisor));
}
}
if (interceptors.isEmpty()) {
throw new UnknownAdviceTypeException(advisor.getAdvice());
}
return interceptors.toArray(new MethodInterceptor[interceptors.size()]);
}
@Override
public void registerAdvisorAdapter(AdvisorAdapter adapter) {
this.adapters.add(adapter);
}
}
以MethodBeforeAdviceAdapter为例,它的具体实现如以下代码所示,这个MethodBeforeAdviceAdapter的实现并不复杂,它实现了AdvisorAdapter的两个接口方法:一个是supportsAdvice,这个方法对advice的类型进行判断,如果advice是MethodBeforeAdvice的实例,那么返回值为true;另一个是对getInterceptor接口方法的实现,这个方法把advice通知从通知器中取出,然后创建一个MethodBeforeAdviceInterceptor对象,通过这个对象把取得的advice通知包装起来,然后返回。
class MethodBeforeAdviceAdapter implements AdvisorAdapter, Serializable {
@Override
public boolean supportsAdvice(Advice advice) {
return (advice instanceof MethodBeforeAdvice);
}
@Override
public MethodInterceptor getInterceptor(Advisor advisor) {
MethodBeforeAdvice advice = (MethodBeforeAdvice) advisor.getAdvice();
return new MethodBeforeAdviceInterceptor(advice);
}
}
Spring AOP为了实现advice的织入,设计了特定的拦截器对这些功能进行了封装。虽然应用不会直接用到这些拦截器,但却是advice发挥作用必不可少的准备。以MethodBeforeAdviceInterceptor为例,看看它是怎样完成advice的封装的,如下所示。MethodBeforeAdviceInterceptor完成的是对MethodBeforeAdvice通知的封装,可以在MethodBeforeAdviceInterceptor设计的invoke回调方法中,看到首先触发了advice的before回调,然后才是MethodInvocation的proceed方法调用。看到这里,就和前面在ReflectiveMethodInvocation的proceed分析中联系起来了。在AopProxy代理对象触发的ReflectiveMethodInvocation的proceed方法中,在取得拦截器以后,启动了对拦截器invoke方法的调用。按照AOP的配置规则,ReflectiveMethodInvocation触发的拦截器invoke方法,最终会根据不同的advice类型,触发Spring 对不同的advice的拦截器封装,比如对MethodBeforeAdvice,最终会触发MethodBeforeAdviceInterceptor的invoke方法。在MethodBeforeAdviceInterceptor方法中,会先调用advice的before方法,这就是MethodBeforeAdvice所需要的对目标对象的增强效果:在方法调用之前完成通知增强。
public class MethodBeforeAdviceInterceptor implements MethodInterceptor, Serializable {
private MethodBeforeAdvice advice;
/**
* Create a new MethodBeforeAdviceInterceptor for the given advice.
* @param advice the MethodBeforeAdvice to wrap
*/
// 为指定的Advice创建对应的MethodBeforeAdviceInterceptor对象
public MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) {
Assert.notNull(advice, "Advice must not be null");
this.advice = advice;
}
@Override
// 这个invoke方法是拦截器的回调方法,会在代理对象的方法被调用时触发回调
public Object invoke(MethodInvocation mi) throws Throwable {
this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() );
return mi.proceed();
}
}
对于其他的advice通知的实现就可以举一反三,比如AfterReturningAdviceInterceptor的实现,它和MethodBeforeAdviceInterceptor实现不同的地方,就是在AfterReturningAdviceInterceptor的invoke方法中,先完成了MethodInvocation的proceed调用,也就是目标对象的方法调用,然后再启动advice通知的afterReturning回调,这些实现原理在代码中可以很清楚看到,如下:
public class AfterReturningAdviceInterceptor implements MethodInterceptor, AfterAdvice, Serializable {
private final AfterReturningAdvice advice;
/**
* Create a new AfterReturningAdviceInterceptor for the given advice.
* @param advice the AfterReturningAdvice to wrap
*/
// 为指定的advice创建AfterReturningAdviceInterceptor对象
public AfterReturningAdviceInterceptor(AfterReturningAdvice advice) {
Assert.notNull(advice, "Advice must not be null");
this.advice = advice;
}
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
Object retVal = mi.proceed();
this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
return retVal;
}
}
ThrowsAdvice的实现,和上面两种情况非常相似,也是封装在对应的AdviceInterceptor中实现的,如下代码,只是相对于MethodBeforeAdvice和AfterReturningAdvice的回调方法调用,ThrowsAdvice的回调方法调用要复杂一些,他维护了一个exceptionHandlerMap来对应不同的方法调用场景,这个exceptionHandlerMap中handler的取得是与触发ThrowsAdvice增强的异常相关的。
public class ThrowsAdviceInterceptor implements MethodInterceptor, AfterAdvice {
private static final String AFTER_THROWING = "afterThrowing";
private static final Log logger = LogFactory.getLog(ThrowsAdviceInterceptor.class);
private final Object throwsAdvice;
/** Methods on throws advice, keyed by exception class */
private final Map<Class<?>, Method> exceptionHandlerMap = new HashMap<Class<?>, Method>();
/**
* Create a new ThrowsAdviceInterceptor for the given ThrowsAdvice.
* @param throwsAdvice the advice object that defines the exception
* handler methods (usually a {@link org.springframework.aop.ThrowsAdvice}
* implementation)
*/
public ThrowsAdviceInterceptor(Object throwsAdvice) {
Assert.notNull(throwsAdvice, "Advice must not be null");
this.throwsAdvice = throwsAdvice;
// 配置ThrowsAdvice的回调方法
Method[] methods = throwsAdvice.getClass().getMethods();
for (Method method : methods) {
if (method.getName().equals(AFTER_THROWING) &&
(method.getParameterTypes().length == 1 || method.getParameterTypes().length == 4) &&
Throwable.class.isAssignableFrom(method.getParameterTypes()[method.getParameterTypes().length - 1])
) {
// Have an exception handler
// 配置异常处理
this.exceptionHandlerMap.put(method.getParameterTypes()[method.getParameterTypes().length - 1], method);
if (logger.isDebugEnabled()) {
logger.debug("Found exception handler method: " + method);
}
}
}
if (this.exceptionHandlerMap.isEmpty()) {
throw new IllegalArgumentException(
"At least one handler method must be found in class [" + throwsAdvice.getClass() + "]");
}
}
public int getHandlerMethodCount() {
return this.exceptionHandlerMap.size();
}
/**
* Determine the exception handle method. Can return null if not found.
* @param exception the exception thrown
* @return a handler for the given exception type
*/
private Method getExceptionHandler(Throwable exception) {
Class<?> exceptionClass = exception.getClass();
if (logger.isTraceEnabled()) {
logger.trace("Trying to find handler for exception of type [" + exceptionClass.getName() + "]");
}
Method handler = this.exceptionHandlerMap.get(exceptionClass);
while (handler == null && !exceptionClass.equals(Throwable.class)) {
exceptionClass = exceptionClass.getSuperclass();
handler = this.exceptionHandlerMap.get(exceptionClass);
}
if (handler != null && logger.isDebugEnabled()) {
logger.debug("Found handler for exception of type [" + exceptionClass.getName() + "]: " + handler);
}
return handler;
}
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
// 把对目标对象的方法调用放入try/catch中,并在catch中触发
// ThrowsAdvice的回调
// 把异常接着向外抛,不做过多处理
try {
return mi.proceed();
}
catch (Throwable ex) {
Method handlerMethod = getExceptionHandler(ex);
if (handlerMethod != null) {
invokeHandlerMethod(mi, ex, handlerMethod);
}
throw ex;
}
}
// 通过反射启动对ThrowsAdvice回调方法的调用
private void invokeHandlerMethod(MethodInvocation mi, Throwable ex, Method method) throws Throwable {
Object[] handlerArgs;
if (method.getParameterTypes().length == 1) {
handlerArgs = new Object[] { ex };
}
else {
handlerArgs = new Object[] {mi.getMethod(), mi.getArguments(), mi.getThis(), ex};
}
try {
method.invoke(this.throwsAdvice, handlerArgs);
}
catch (InvocationTargetException targetEx) {
throw targetEx.getTargetException();
}
}
}