Spring源码分析——Aop实现
1、Aop概念回顾
Aop是Aspect-Oriented Programming(面向切面编程)的简称,*对于它的解释如下:
Aspect是一种新的模块化机制,用来描述分布的对象,类或函数中的横切关注点,从关注点分离出横切关注点是面向切面的程序设计的核心概念。分离关注点使解决特定领域问题的代码从业务逻辑中独立出来,业务逻辑的代码中不再包含对特定领域问题代码的调用,业务逻辑中特定领域问题的关系通过切面来封装,维护,这样原本分散在整个应用中的变动就可以很好的管理起来。
有如下常见的Aop技术:
- AspectJ
- AspectWerkz
- JBoss-AOP
- BCEL
- Javassist
而在SpringAop实现中,使用Java语言实现增强对象与切面增强应用,并为这两者提供了配置环境,对于编织配置,可以使用IOC容器完成。但对于其他的AOP实现方案,可能需要使用特定的实现语言、配置环境甚至编译环境。
Aop是Spring平台和生态系统的核心功能模块之一,Aop与IOC的结合使用为应用开发与spring自身功能扩展提供了便利。SpringAop除了可以使用自身的Aop实现之外,还封装了业界优良的解决方案AspectJ模块以供使用。
本文主要针对Spring自身的Aop实现原理进行分析,Spring充分利用了IOC容器Proxy代理对象以及Aop拦截器的功能特性,通过对这些Aop基本功能的封装为用户提供了Aop的实现框架。
2、Spring Aop基本组件
2.1 Advice(通知)
Advice定义在连接点(Advisor)做什么,为切面增强提供织入接口。Advice是Aop联盟定义的一个接口,Spring使用了这个统一的接口,这个接口的定义如下:
/**
* Tag interface for Advice. Implementations can be any type
* of advice, such as Interceptors.
*
* @author Rod Johnson
* @version $Id: Advice.java,v 1.1 2004/03/19 17:02:16 johnsonr Exp $
*/
public interface Advice {
}
它有如下实现
这里我们主要关注MethodBeforeAdvice,AfterReturingAdvice与ThrowsAdvice与他们的实现类。
MethodBeforeAdvice
public interface MethodBeforeAdvice extends BeforeAdvice {
void before(Method method, Object[] args, @Nullable Object target) throws Throwable;
}
这个接口只有一个before需要实现,这个方法会在织入方法之前被调用。
AfterReturningAdvice
public interface AfterReturningAdvice extends AfterAdvice {
void afterReturning(@Nullable Object returnValue, Method method, Object[] args, @Nullable Object target) throws Throwable;
}
这个接口只有一个afterReturnibg方法需要实现,这个方法会在织入方法调用结束并成功返回时被调用。
ThrowsAdvice
public interface ThrowsAdvice extends AfterAdvice {
}
对于ThrowsAdvice并没有指定需要实现的接口方法,它在织入方法抛出异常时被回调。
从上面几个例子可以看出,不同的Advice的扩展接口的实现,会在织入方法的不同时期被调用,而如何感知方法的执行状态将会在第五部分通过源码讲解进行阐明。
2.2 PointCut(切点)
PointCut决定Advice通知应该作用于哪个连接点,也就是说PointCut定义了Advice增强的连接点的集合,这些集合的选取按照一定规则来完成(如正则表达式,方法名匹配等)。
Spring Aop提供了一下的切点类供用户使用:
我们先看看基础接口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类型的成员变量。其中getClassFilter
用于返回一个ClassFilter对需要织入Advice的类进行过滤,而getMethodMatcher
方法则更加重要,之前说的‘PointCut决定Advice通知应该作用于哪个连接点’就是通过这个方法返回的MethodMatcher对象完成的。既然说到了MethodMatcher,那我们就来看一看这个接口MethodMatcher
public interface MethodMatcher {
/**
* Perform static checking whether the given method matches.
* <p>If this returns {@code false} or if the {@link #isRuntime()}
* method returns {@code false}, no runtime check (i.e. no
* {@link #matches(java.lang.reflect.Method, Class, Object[])} call)
* will be made.
* @param method the candidate method
* @param targetClass the target class (may be {@code null}, in which case
* the candidate class must be taken to be the method's declaring class)
* @return whether or not this method matches statically
*/
boolean matches(Method method, @Nullable Class<?> targetClass);
/**
* Is this MethodMatcher dynamic, that is, must a final call be made on the
* {@link #matches(java.lang.reflect.Method, Class, Object[])} method at
* runtime even if the 2-arg matches method returns {@code true}?
* <p>Can be invoked when an AOP proxy is created, and need not be invoked
* again before each method invocation,
* @return whether or not a runtime match via the 3-arg
* {@link #matches(java.lang.reflect.Method, Class, Object[])} method
* is required if static matching passed
*/
boolean isRuntime();
/**
* Check whether there a runtime (dynamic) match for this method,
* which must have matched statically.
* <p>This method is invoked only if the 2-arg matches method returns
* {@code true} for the given method and target class, and if the
* {@link #isRuntime()} method returns {@code true}. Invoked
* immediately before potential running of the advice, after any
* advice earlier in the advice chain has run.
* @param method the candidate method
* @param targetClass the target class (may be {@code null}, in which case
* the candidate class must be taken to be the method's declaring class)
* @param args arguments to the method
* @return whether there's a runtime match
* @see MethodMatcher#matches(Method, Class)
*/
boolean matches(Method method, @Nullable Class<?> targetClass, Object... args);
/**
* Canonical instance that matches all methods.
*/
MethodMatcher TRUE = TrueMethodMatcher.INSTANCE;
}
这个接口的Java doc的第一句就是Part of a {@link Pointcut}: Checks whether the target method is eligible for advice
。说明这个接口以及其实现类就是为了检查advice是否应该织入该方法。而具体的判断逻辑由接口的两个matches方法实现。不同的实现类对应不同的实现。
以JdkRegexpMethodPointcut
举例JdkRegexpMethodPointcut
public class JdkRegexpMethodPointcut extends AbstractRegexpMethodPointcut {
/**
* Compiled form of the patterns.
*/
private Pattern[] compiledPatterns = new Pattern[0];
/**
* Compiled form of the exclusion patterns.
*/
private Pattern[] compiledExclusionPatterns = new Pattern[0];
/**
* Initialize {@link Pattern Patterns} from the supplied {@code String[]}.
*/
@Override
protected void initPatternRepresentation(String[] patterns) throws PatternSyntaxException {
this.compiledPatterns = compilePatterns(patterns);
}
/**
* Initialize exclusion {@link Pattern Patterns} from the supplied {@code String[]}.
*/
@Override
protected void initExcludedPatternRepresentation(String[] excludedPatterns) throws PatternSyntaxException {
this.compiledExclusionPatterns = compilePatterns(excludedPatterns);
}
/**
* 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();
}
/**
* Returns {@code true} if the exclusion {@link Pattern} at index {@code patternIndex}
* matches the supplied candidate {@code String}.
*/
@Override
protected boolean matchesExclusion(String candidate, int patternIndex) {
Matcher matcher = this.compiledExclusionPatterns[patternIndex].matcher(candidate);
return matcher.matches();
}
/**
* Compiles the supplied {@code String[]} into an array of
* {@link Pattern} objects and returns that array.
*/
private Pattern[] compilePatterns(String[] source) throws PatternSyntaxException {
Pattern[] destination = new Pattern[source.length];
for (int i = 0; i < source.length; i++) {
destination[i] = Pattern.compile(source[i]);
}
return destination;
}
}
它的matches方法的实现是依赖一个Pattern集合进行正则表达式的匹配的。
2.3 Advisor(通知器,又叫连接点)
完成对目标方法的Advice(通知)与Pointcut(切入点)设计之后,需要一个对象将两者连接起来,即在哪些Pointcut执行哪些Advice,而这个职责就交给了Advisor来实现。老规矩我们首先看看Advisor的顶层接口的设计Advisor
public interface Advisor {
/**
* Common placeholder for an empty {@code Advice} to be returned from
* {@link #getAdvice()} if no proper advice has been configured (yet).
* @since 5.0
*/
Advice EMPTY_ADVICE = new Advice() {};
/**
* Return the advice part of this aspect. An advice may be an
* interceptor, a before advice, a throws advice, etc.
* @return the advice that should apply if the pointcut matches
* @see org.aopalliance.intercept.MethodInterceptor
* @see BeforeAdvice
* @see ThrowsAdvice
* @see AfterReturningAdvice
*/
Advice getAdvice();
/**
* Return whether this advice is associated with a particular instance
* (for example, creating a mixin) or shared with all instances of
* the advised class obtained from the same Spring bean factory.
* <p><b>Note that this method is not currently used by the framework.</b>
* Typical Advisor implementations always return {@code true}.
* Use singleton/prototype bean definitions or appropriate programmatic
* proxy creation to ensure that Advisors have the correct lifecycle model.
* @return whether this advice is associated with a particular target instance
*/
boolean isPerInstance();
}
接口中只看到了关于getAdvice抽象方法的定义,那么从哪里获取Pointcut呢?不要急先看一下Advisor的类图
有一个PointcutAdvisor继承了该接口,看名字应该是我们想要的类了。点进去看一下接口定义。果不其然PointcutAdvisor
public interface PointcutAdvisor extends Advisor {
/**
* Get the Pointcut that drives this advisor.
*/
Pointcut getPointcut();
}
PointcutAdivisor有一个默认的实现类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(@Nullable 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() + "]";
}
}
基类AbstractGenericPointcutAdvisor
public abstract class AbstractGenericPointcutAdvisor extends AbstractPointcutAdvisor {
private Advice advice = EMPTY_ADVICE;
/**
* Specify the advice that this advisor should apply.
*/
public void setAdvice(Advice advice) {
this.advice = advice;
}
@Override
public Advice getAdvice() {
return this.advice;
}
@Override
public String toString() {
return getClass().getName() + ": advice [" + getAdvice() + "]";
}
}
可以看到默认的Advice与Pointcut分别是TruePointcut与EMPTY_ADVICE。并提供了两者的注入方法。
3、Spring Aop的整体设计
Aop模块是Spring的核心模块,虽然在Java社区中AspectJ是最完整的AOP框架,但Spring Aop中提供了另外一种实现。
Spring Aop的核心技术JDK的动态代理技术,以动态代理技术为基础设计出了一系列的Aop的横切实现比如前置通知,返回通知,异常通知等。同时Spring Aop还提了一系列的Pointcut来匹配切入点,可以使用现有的切入点来设计横切面也可以扩展Pointcut接口实现自定义的切入需求。
在Spring内部想要Aop起作用,需要为目标对象创建代理对象(AopProxy)
,这个代理对象可以使用JDK的Proxy完成,也可以使用第三方字节码生成器CGLIB实现。然后还需要启动代理对象的拦截器
来完成各种横切面的织入,这一系列的织入设计是通过一系列Adapter
实现的。通过一系列Adapter可以将对应的Advice在相应的方法的执行周期织入。
在Spring Aop模块中,一个主要的部分是代理对象的生成,对于Spring应用,主要是通过配置和调用ProxyFactoryBean完成这个任务的,以ProxyFactory的设计为中心,观察一下相关类的继承关系:
在这个类继承关系中可以看到完成Aop应用相关的类(底层的三个AspectJProxyFactory, ProxyFactory,ProxyFactoryBean)的共同基类都是ProxyConfig
,AdvisedSupport
与ProxyCreatorSupport
。ProxyConfig
* Convenience superclass for configuration used in creating proxies,
* to ensure that all proxy creators have consistent properties.
ProxyConfig可以被看做一个数据基类,为子类提供了配置属性
AdvisedSupport
AdvisedSupport封装了Aop对通知(Advice)和通知器(Advisor)的相关操作,这些操作对于不同的Aop的代理对象的生成都是一样的,因此将这一系列操作放在了父类当中。但对于具体的Aop代理对象的创建,AdvisedSupport把他们交给子类去完成。
ProxyCreatorSupport
* Base class for proxy factories.
* Provides convenient access to a configurable AopProxyFactory.
ProxyCreatorSupport可以看成子类创建Aop代理对象的一个辅助类。
对于需要使用AspectJ的Aop应用,AspectJProxyFactory
起到集成的作用,而对于使用原生Spring Aop的应用,ProxyFactoryBean和ProxyFactory都提供了对Aop功能的封装。这里我们主要分析ProxyFactoryBean的实现。
这里先看一段ProxyFactoryBean的配置
testAdvisor:连接点Bean,包含了Advice与Pointcut
testAop:定义ProxyFactoryBean。需要设定与Aop实现相关的重要属性。
- proxyInterfaces
- target:需要使用Aop通知器中的切面应用来增强的对象
- interceptorNames:要定义的连接点的集合
掌握这些配置后,在下一节我们将看到ProxyFactoryBean如何使用这些配置生成AopProxy代理对象。
4、建立AopProxy代理对象
4.1 从ProxyFactoryBean切入
ProxyFactoryBean实现了FactoryBean接口,对于这种特殊的Bean熟悉Spring IOC实现原理的同学一定不会陌生。那么我们分析的重点就应该放在这个接口所提供的getObject方法上ProxyFactoryBean:getObject
public Object getObject() throws BeansException {
// 初始化通知器链
initializeAdvisorChain();
// 根据不同的Bean类型生成不同的代理对象
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();
}
}
这里有三个很重要的操作,初始化通知器(Advisor)链以及根据Bean类型生成代理对象的getSingletonInstance与newPrototypeInstance方法。先分析initializeAdvisorChain。ProxyFactoryBean:initializeAdvisorChain
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 list进行遍历
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.
Object advice;
if (this.singleton || this.beanFactory.isSingleton(name)) {
// Add the real Advisor/Advice to the chain.
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.
advice = new PrototypePlaceholderAdvisor(name);
}
//将从Advisor中取出的Advice加入拦截器链中
addAdvisorOnChainCreation(advice, name);
}
}
}
this.advisorChainInitialized = true;
}
接下来看看Singleton类型的代理对象的生成方法:ProxyFactoryBean:
private synchronized Object getSingletonInstance() {
if (this.singletonInstance == null) {
this.targetSource = freshTargetSource();
if (this.autodetectInterfaces && getProxiedInterfaces().length == 0 && !isProxyTargetClass()) {
// 判断需要代理的target是否有接口
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);
// 注意createAopProxy方法
this.singletonInstance = getProxy(createAopProxy());
}
return this.singletonInstance;
}
AdvisedSupport:setInterface
public void setInterfaces(Class<?>... interfaces) {
Assert.notNull(interfaces, "Interfaces must not be null");
this.interfaces.clear();
for (Class<?> ifc : interfaces) {
addInterface(ifc);
}
}
ProxyCreatorSupport:createAopProxy
protected final synchronized AopProxy createAopProxy() {
if (!this.active) {
activate();
}
return getAopProxyFactory().createAopProxy(this);
}
可以看到最终创建AopProxy对象靠的是AopProxyFactory
。那么问题就转换为了在AopProxyFactory中怎么创建AopProxy的。
4.2 在AopProxyFactory中创建AopProxy对象
AopProxyFactory是一个接口,只有一个方法
public interface AopProxyFactory {
AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException;
}
这个接口有一个默认的实现类DefaultAopProxyFactory
public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {
@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
// 通过AdvisedSupport获取需要被代理的对象
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.");
}
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
// 代理类有接口的情况下使用动态代理的方式生成AopProxy
return new JdkDynamicAopProxy(config);
}
// 否则使用cglib
return new ObjenesisCglibAopProxy(config);
}
else {
return new JdkDynamicAopProxy(config);
}
}
/**
* Determine whether the supplied {@link AdvisedSupport} has only the
* {@link org.springframework.aop.SpringProxy} interface specified
* (or no proxy interfaces specified at all).
*/
private boolean hasNoUserSuppliedProxyInterfaces(AdvisedSupport config) {
Class<?>[] ifcs = config.getProxiedInterfaces();
return (ifcs.length == 0 || (ifcs.length == 1 && SpringProxy.class.isAssignableFrom(ifcs[0])));
}
}
在对createAopProxy的实现中我们主要关注这两个调用JdkDynamicAopProxy(config)
和ObjenesisCglibAopProxy(config)
。可以看到DefaultAopProxyFactory是比较高层次的生成代理对象的过程,但是具体使用动态代理或者cglib生成代理对象的过程,被封装进了上述两个类中。
JdkDynamicAopProxy的继承关系如下图所示
需要注意的是它实现了InvoketionHandler方法,这个信号告诉我们这个类对于invoke方法的实现将会是接下来分析的重点。
JdkDynamicAopProxy是如何生成代理对象的呢?主要逻辑在它的getProxy方法中JdkDynamicAopProxy:getProxy
@Override
public Object getProxy() {
return getProxy(ClassUtils.getDefaultClassLoader());
}
@Override
public Object getProxy(@Nullable ClassLoader classLoader) {
if (logger.isDebugEnabled()) {
logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());
}
Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
可以很清楚的看到使用的是jdk的动态代理,而在Proxy.newProxyInstance传入的InvoketionHandler类型的参数指向的是JdkDynamicAopProxy自身,也就是说所有代理逻辑都是在JdkDynamicAopProxy的invoke
方法中实现的。而我们下一节所要说的拦截器调用的入口也在这个方法中。
由于笔者对于cglib字节码框架并不熟悉所以省略了对于CglibAopProxy的分析。之后会补上缺失的部分。读者有兴趣也可以自行阅读源码进行分析。
5、SpringAop拦截器调用的实现
Aop的核心功能就是完成对目标对象或方法的增强,这些实现是封装在Aop拦截器中,由一个个具体的拦截器完成。之前说过拦截器的调用入口在invoke方法中,那我们接下来就来分析一下这个方法JdkDynamicAopProxy:invoke
@Override
@Nullable
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
MethodInvocation invocation;
Object oldProxy = null;
boolean setProxyContext = false;
TargetSource targetSource = this.advised.targetSource;
Object target = null;
try {
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
// The target does not implement the equals(Object) method itself.
return equals(args[0]);
}
else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
// The target does not implement the hashCode() method itself.
return hashCode();
}
else if (method.getDeclaringClass() == DecoratingProxy.class) {
// There is only getDecoratedClass() declared -> dispatch to proxy config.
return AopProxyUtils.ultimateTargetClass(this.advised);
}
else 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;
}
// Get as late as possible to minimize the time we "own" the target,
// in case it comes from a pool.
// 得到目标代理对象
target = targetSource.getTarget();
Class<?> targetClass = (target != null ? target.getClass() : null);
// Get the interception chain for this method.
// 通过AdvisedSupport获取定义好的拦截器链
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.
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
else {
// We need to create a method invocation...
// 创建一个ReflectiveMethodInvocation对象并调用它的proceed方法
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 != Object.class && 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);
}
}
}
分析源码可以看出,在有拦截器存在的情况下,对于拦截器的调用是通过ReflectiveMethodInvocation的proceed方法完成的。在proceed方法中会判断如果已经运行到拦截器末尾,则直接调用目标方法的实现,否则沿着拦截器链获取下一个拦截器,使用拦截器进行matches判断是否需要增强(有没有想到MethodMatcher接口)。如果是则从拦截器中取得通知器(MethodInterceptor
接口的实现类,这个接口继承自Advise
接口)并调用它的invoke方法。ReflectiveMethodInvocation:proceed
@Override
@Nullable
public Object proceed() throws Throwable {
// We start with an index of -1 and increment early.
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
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.
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.
return proceed();
}
}
else {
// It's an interceptor, so we just invoke it: The pointcut will have
// been evaluated statically before this object was constructed.
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
拦截器的配置问题
从proceed方法中看出拦截器是从一个名为interceptorsAndDynamicMethodMatchers的list集合中获取的一个元素。我们想要知道我们配置的拦截器是如何被程序获取的,就需要弄明白这个集合中的元素都是从哪里来的。
首先interceptorsAndDynamicMethodMatchers是在构造函数中作为形参chain的实参被传入的。回想一下我们在哪里调用过ReflectiveMethodInvocation的构造方法?相信记性比较好的小伙伴一下就会想起JdkDynamicProxy的invoke方法了。JdkDynamicProxy:invoke(片段)
// 通过AdvisedSupport获取定义好的拦截器链
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.
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
else {
// We need to create a method invocation...
// 创建一个ReflectiveMethodInvocation对象并调用它的proceed方法
invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// Proceed to the joinpoint through the interceptor chain.
retVal = invocation.proceed();
}
这样拦截器链的来源就水落石出了,是调用AdvisedSupport的getInterceptorsAndDynamicInterceptionAdvice方法获得的。那么我们有必要跟踪一下这个方法。AdvisedSupport:getInterceptorsAndDynamicInterceptionAdvice
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class<?> targetClass) {
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的getInterceptorsAndDynamicInterceptionAdvice
方法得到的,在AdvisedSupport中使用的AdvisorChainFactory的实现是DefaultAdvisorChainFactory,我们继续跟进看一下它的getInterceptorsAndDynamicInterceptionAdvice方法。DefaultAdvisorChainFactory:getInterceptorsAndDynamicInterceptionAdvice
@Override
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
Advised config, Method method, @Nullable Class<?> targetClass) {
// This is somewhat tricky... We have to process introductions first,
// but we need to preserve order in the ultimate list.
List<Object> interceptorList = new ArrayList<Object>(config.getAdvisors().length);
Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
boolean hasIntroductions = hasMatchingIntroductions(config, actualClass);
AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
for (Advisor advisor : config.getAdvisors()) {
if (advisor instanceof PointcutAdvisor) {
// Add it conditionally.
PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
// 根据Pointcut的ClassFilterp判断这个类是否符合增强的要求
if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
// 获取pointcut中的MethodMatcher
MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
// 使用MethodMatcher判断当前Method是否符合增强要求
if (MethodMatchers.matches(mm, method, actualClass, hasIntroductions)) {
// 注意,这里发现拦截器(MethodInterceptor)的获取需要通过AdvisorAdapterRegistry这个对象
MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
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(actualClass)) {
Interceptor[] interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}
}
else {
Interceptor[] interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}
}
return interceptorList;
}
整个方法的逻辑配合注释应该还是很容易看懂,这里我们需要重点关注MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
这一行代码,因为这里引入了一个新的AdvisorAdapterRegistry对象,而我们的拦截器正来源于这个对象的getInterceptors方法。对于AdvisorAdapterRegistry的分析我们先搁置一下,这里我们先弄清楚用于遍历的Advisors
的来源。
Advisors的来源
Advisors的获得调用了Advised接口的getAdvisors方法。而AdvisedSupport作为它的实现,在内部维护了一个Advisors的集合private List<Advisor> advisors = new ArrayList<>();
而ProxyFactoryBean继承了AdvisedSupport,并在它的initializeAdvisorChain方法中通过配置在xml文件中的interceptNames[]信息(回想一下我们之前对于ProxyFactoryBean的配置)。使用getBean方法向ioc容器索要Bean。具体的方法实现如下:ProxyFactoryBean:initializeAdvisorChain
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.
Object advice;
if (this.singleton || this.beanFactory.isSingleton(name)) {
// Add the real Advisor/Advice to the chain.
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.
advice = new PrototypePlaceholderAdvisor(name);
}
addAdvisorOnChainCreation(advice, name);
}
}
}
this.advisorChainInitialized = true;
}
那么方法里的使用的ioc容器来自哪里呢?其实看一看ProxyFactoryBean实现的接口就明白了
public class ProxyFactoryBean extends ProxyCreatorSupport implements FactoryBean<Object>, BeanClassLoaderAware, BeanFactoryAware
其中的BeanFactoryAware接口会回调setBeanFactory方法,也就是在此时将BeanFactory注入类中的beanFactory变量的
@Override
public void setBeanFactory(BeanFactory beanFactory) {
this.beanFactory = beanFactory;
checkInterceptorNames();
}
使用GlobalAdvisorAdapterRegistry完成对拦截器的注册于适配过程
我们继续分析getInterceptorsAndDynamicInterceptionAdvice中的MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
这一行代码。这行代码的功能就是将advisor转换为一个interceptor集合。而内部是依靠一系列的AdvisorAdapter组件完成这个任务的。话不多说我们直接看源码DefaultAdvisorAdapterRegistry:getInterceptors
@Override
public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {
List<MethodInterceptor> interceptors = new ArrayList<>(3);
// 从Advisor中获取通知对象
Advice advice = advisor.getAdvice();
if (advice instanceof MethodInterceptor) {
// 如果通知对象本身就是MethodInterceptor类型的则无需转换
interceptors.add((MethodInterceptor) advice);
}
for (AdvisorAdapter adapter : this.adapters) {
// 检查当前Adapter对于此种类型的advice是否支持,如果支持则转换然后加入interceptors集合
if (adapter.supportsAdvice(advice)) {
interceptors.add(adapter.getInterceptor(advisor));
}
}
if (interceptors.isEmpty()) {
throw new UnknownAdviceTypeException(advisor.getAdvice());
}
return interceptors.toArray(new MethodInterceptor[0]);
}
方法的逻辑很简单,从Advisor中取出的Advice会被一系列匹配的AdvisorAdapter转换为对应的MethodInterceptor。以AdvisorAdapter的一个实现类MethodBeforeAdviceAdapter为例MethodBeforeAdviceAdapter:getInterceptor
@Override
public MethodInterceptor getInterceptor(Advisor advisor) {
MethodBeforeAdvice advice = (MethodBeforeAdvice) advisor.getAdvice();
return new MethodBeforeAdviceInterceptor(advice);
}
可以看到MethodBeforeAdvice类型的Advice被包装成了MethodBeforeAdviceInterceptor类型的Interceptor,而正是这一系列的拦截器对象实现了advice通知在代理对象的织入功能(还记得MethodInterceptor的invoke方法吗?)
我们在之前的分析中已经知道了在ReflectiveMethodInvocation的proceed方法中会沿着过滤器链一直向下调用直到最后才会调用代理的原方法。那除了前置Advice以外的Advice不是就失效了吗?这当然不可能。注意在调用interceptors的invoke方法时,我们将ReflectiveMethodInvocation自身的this引用传递了进去,而这正是织入功能设计的精髓。我们以MethodBeforeAdviceInterceptor为例,看看它的invoke方法是怎么实现的MethodBeforeAdviceInterceptor:invoke
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
return mi.proceed();
}
在invoke方法中,首先调用的是当前interceptor持有的advice实例(这里当然就是BeforeAdvice了)的before方法,然后通过传入的MethodInvocation继续往下调用。而对于AfterReturningAdviceInterceptor,它的invoke方法是这样实现的AfterReturningAdviceInterceptor:invoke
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
Object retVal = mi.proceed();
this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
return retVal;
}
话不多说自己体会,反正博主对于这种精妙的设计还是相当佩服的哈哈。
6、总结
这篇博文只是分析了Spring Aop原生实现中使用JDK动态代理的那一部分,实际情况肯定更加繁杂,博主也算抛砖引玉吧。接下来会继续用博客记录一些Spring基础组件的源码分析。不定时更新(懒~)