因为springAOP会使用springIOC来管理Bean,所以对springIOC不太了解的同学可以参考我前篇 springIOC源码深度解析 。
本文采用的源码版本是5.2.x。为了我们更好地理解springAOP,我们使用的是xml的方式,实际开发中大部分都是是用注解的方式,经验告诉我,从理解源码的角度上来讲,xml配置是最好不过了。
阅读建议:把spring官网的源码给拉下来,对照着我的解析看,这样学习效率是最高的,而不是走马观花。
本文分为两大部分,第一部分对spring AOP 的一些前置知识进行介绍,这部分的目的是让对springAOP不太了解的读者能了解springAOP的一些基本知识。第二部分就是我们本文的重点,这部分会对springAOP源码进行深入的解析。
所谓的连接点是指那些被拦截到的点。在spring中,这些点指的是方法,因为spring只支持方法类型的连接点
对应的类:
public interface Joinpoint { // 执行拦截器链中的下一个拦截器逻辑 Object proceed() throws Throwable; Object getThis(); AccessibleObject getStaticPart(); } 复制代码
所谓的切入点,是指我们要对哪些Joinpoint进行拦截的定义
对应的类:
public interface Pointcut { //返回一个类型过滤器 ClassFilter getClassFilter(); // 返回一个方法匹配器 MethodMatcher getMethodMatcher(); Pointcut TRUE = TruePointcut.INSTANCE; } 复制代码
对应的ClassFilter和MethodMatcher接口:
public interface ClassFilter { boolean matches(Class<?> clazz); ClassFilter TRUE = TrueClassFilter.INSTANCE; } public interface MethodMatcher { boolean matches(Method method, Class<?> targetClass); boolean matches(Method method, Class<?> targetClass, Object... args); boolean isRuntime(); MethodMatcher TRUE = TrueMethodMatcher.INSTANCE; } 复制代码
我们写AOP代码的时候,一般是同切入点表达式进行对连接点进行选择,切入点表达式处理类: AspectJExpressionPointcut,这个类的继承关系图如下:
可以看到AspectJExpressionPointcut继承了ClassFilter和MethodMatcher接口,拥有了matches方法,所以它可以对连接点进行选择。
所谓的通知就是指拦截到Jointpoint之后所要做的事情就是通知,通知分为前置通知(AspectJMethodBeforeAdvice),后置通知(AspectJAfterReturningAdvice),异常通知(AspectJAfterThrowingAdvice),最终通知(AspectAfterAdvice),环绕通知(AspectJAroundAdvice)
引介是一种特殊的通知在不修改类代码的前提下,Introduction可以在运行期为类动态地添加一些方法或Field。
代理的目标对象,比如UserServiceImpl类
是指把增强应用到目标对象来创建新的代理对象的过程。spring是通过实现后置处理器BeanPostProcessor接口来实现织入的。也就是在bean完成初始化之后,通过给目标对象生成代理对象,并交由springIOC容器来接管,这样再去容器中获取到的目标对象就是已经增强过的代理对象。
一个类被AOP织入增强后,就产生一个结果代理类
和Aspect很相似
是切入点和通知的结合,对应于spring中的PointcutAdvisor,既可以获取到切入点又可以获取到通知。如下面类所示:
public interface Advisor { Advice getAdvice(); boolean isPerInstance(); } public interface PointcutAdvisor extends Advisor { Pointcut getPointcut(); } 复制代码
对上面的知识点,通过下面的图来总结一下,希望能够帮助读者记忆。
AOP为Aspect Oriented Programming的缩写,意为:面向 切面 编程。具体的请读者查资料看相关定义
原理如下图所示:
可能这样讲还是有些抽象,下面写个例子辅助理解:
创建一个 Person 接口:
public interface Person { public void eat(); } 复制代码
创建接口实现类: PersonImpl
public class PersonImpl implements Person { @Override public void eat() { System.out.println("我要吃饭"); } } 复制代码
小时候妈妈告诉我们吃饭前要洗手,怎么使用代码进行实现呢?
定义一个EatHandler,实现 InvocationHandler
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class EatHandler implements InvocationHandler { // 要代理的目标对象 private Object target; public EatHandler(Object target) { this.target = target; } public Object proxyInstance() { // 第一个参数就是要加载代理对象的类加载器, // 第二个参数就是要代理类实现的接口 // 第三个参数就是EatHandler return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("吃饭前要洗手"); Object result = method.invoke(this.target, args); System.out.println("吃饭后要洗碗"); return result; } } 复制代码
来个测试类:
public class ProxyMain { public static void main(String[] args) { EatHandler eatHandler = new EatHandler(new PersonImpl()); Person person = (Person) eatHandler.proxyInstance(); person.eat(); } } 复制代码
输出:
吃饭前要洗手 我要吃饭 吃饭后要洗碗 复制代码
可以看到,在“我要吃饭”前后我们已经插入了“吃饭前要洗手”,“吃饭后要洗碗”的功能
是怎么插入的呢?
原理就是JDK帮我们创建了目标对象(EatHandler)的代理类,这个代理类插入了我们想要的功能,当我们调用person.eat();时,操作的是代理类而不是原对象,从而实现了插入我们想要功能的需求。这样应该可以理解了。下面贴下生成的代理对象:
import java.lang.reflect.UndeclaredThrowableException; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; // // Decompiled by Procyon v0.5.36 // public final class PersonImpl$Proxy1 extends Proxy implements Person { private static Method m1; private static Method m3; private static Method m2; private static Method m0; public PersonImpl$Proxy1(final InvocationHandler h) { super(h); } public final boolean equals(final Object o) { try { return (boolean)super.h.invoke(this, PersonImpl$Proxy1.m1, new Object[] { o }); } catch (Error | RuntimeException error) { throw; } catch (Throwable undeclaredThrowable) { throw new UndeclaredThrowableException(undeclaredThrowable); } } public final void eat() { try { super.h.invoke(this, PersonImpl$Proxy1.m3, null); } catch (Error | RuntimeException error) { throw; } catch (Throwable undeclaredThrowable) { throw new UndeclaredThrowableException(undeclaredThrowable); } } public final String toString() { try { return (String)super.h.invoke(this, PersonImpl$Proxy1.m2, null); } catch (Error | RuntimeException error) { throw; } catch (Throwable undeclaredThrowable) { throw new UndeclaredThrowableException(undeclaredThrowable); } } public final int hashCode() { try { return (int)super.h.invoke(this, PersonImpl$Proxy1.m0, null); } catch (Error | RuntimeException error) { throw; } catch (Throwable undeclaredThrowable) { throw new UndeclaredThrowableException(undeclaredThrowable); } } static { try { PersonImpl$Proxy1.m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object")); // 利用反射获取目标对象的Method方法 PersonImpl$Proxy1.m3 = Class.forName("Person").getMethod("eat", (Class<?>[])new Class[0]); PersonImpl$Proxy1.m2 = Class.forName("java.lang.Object").getMethod("toString", (Class<?>[])new Class[0]); PersonImpl$Proxy1.m0 = Class.forName("java.lang.Object").getMethod("hashCode", (Class<?>[])new Class[0]); } catch (NoSuchMethodException ex) { throw new NoSuchMethodError(ex.getMessage()); } catch (ClassNotFoundException ex2) { throw new NoClassDefFoundError(ex2.getMessage()); } } } 复制代码
我们看到JDK确实是为我们生成了一个代理对象,这个代理对象继承了Proxy对象,实现了Person接口。我们看到代理对象中生成了equals()、toString()、hashCode()以及我们的eat()方法。看到eat方法中有这样的代码super.h.invoke(this, PersonImpl$Proxy1.m3, null); 其中,h就是我们定义的EatHandle。我们看到当我们调用person.eat()的时候,实际上是调用这个代理对象的eat()方法,先是调用EatHandle中的invoke方法,这里有我们加入的增强代码,这就实现了代理的作用了。这样应该懂了吧。
如下图所示:
有了前面基础知识的铺垫,现在终于可以进入到源码解析阶段了。让我们来验证一下我们的想法吧。请读者打开spring源码。
这个阶段分为三个步骤:
我们要完成下面配置文件的解析:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <!-- 配置目标对象 --> <bean class="com.sjc.spring.aop.target.UserServiceImpl"></bean> <!-- 配置通知类 --> <bean id="myAdvice" class="com.sjc.spring.aop.advice.MyAdvice"></bean> <!-- AOP配置 --> <aop:config> <!-- <aop:advisor advice-ref="" /> --> <aop:pointcut expression="" id="" /> <aop:aspect ref="myAdvice"> <aop:before method="before" pointcut="execution(* *..*.*ServiceImpl.*(..))" /> <aop:after method="after" pointcut="execution(* *..*.*ServiceImpl.*(..))" /> </aop:aspect> </aop:config> </beans> 复制代码
入口:DefaultBeanDefinitionDocumentReader#parseBeanDefinitions
我们在上一篇解析SpringIOC源码的时候也也分析过这一步, 让我们进入到
delegate.parseCustomElement(ele);
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) { // 加载的Document对象是否使用了Spring默认的XML命名空间(beans命名空间) if (delegate.isDefaultNamespace(root)) { // 获取Document对象根元素的所有子节点(bean标签、import标签、alias标签和其他自定义标签context、aop等) NodeList nl = root.getChildNodes(); for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); if (node instanceof Element) { Element ele = (Element) node; // bean标签、import标签、alias标签,则使用默认解析规则 if (delegate.isDefaultNamespace(ele)) { parseDefaultElement(ele, delegate); } else { //像context标签、aop标签、tx标签,则使用用户自定义的解析规则解析元素节点 delegate.parseCustomElement(ele); } } } } else { delegate.parseCustomElement(root); } } 复制代码
我们进入到:BeanDefinitionParserDelegate#parseCustomElement
这个方法主要做两件事:
public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) { // 获取命名空间URI(就是获取beans标签的xmlns:aop或者xmlns:context属性的值) // http://www.springframework.org/schema/aop String namespaceUri = getNamespaceURI(ele); if (namespaceUri == null) { return null; } // 根据不同的命名空间URI,去匹配不同的NamespaceHandler(一个命名空间对应一个NamespaceHandler) // 此处会调用DefaultNamespaceHandlerResolver类的resolve方法 // 两步操作:查找NamespaceHandler 、调用NamespaceHandler的init方法进行初始化(针对不同自定义标签注册相应的BeanDefinitionParser) NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri); if (handler == null) { error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele); return null; } return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd)); } 复制代码
我们进入到NamespaceHandlerSupport#parse
这个方法我们主要关心的是parser.parse()方法,findParserForElement可以作为一个分支去了解,如果读者感兴趣的话。
public BeanDefinition parse(Element element, ParserContext parserContext) { // NamespaceHandler里面初始化了大量的BeanDefinitionParser来分别处理不同的自定义标签 // 从指定的NamespaceHandler中,匹配到指定的BeanDefinitionParser BeanDefinitionParser parser = findParserForElement(element, parserContext); // 调用指定自定义标签的解析器,完成具体解析工作 return (parser != null ? parser.parse(element, parserContext) : null); } 复制代码
BeanDefinitionParser有很多的实现类,这里我们配置文件是由ConfigBeanDefinitionParser来实现的。
我们进入到ConfigBeanDefinitionParser#parse();
这个方法主要产生三个我们比较关心的分支:
configureAutoProxyCreator(parserContext, element);
主要是生成AspectJAwareAdvisorAutoProxyCreator类的BeanDefinition,并注册到IOC容器,这个类用来创建AOP代理对象
parsePointcut(elt, parserContext);
产生一个AspectJExpressionPointcut的BeanDefinition对象,并注册。这个AspectJExpressionPointcut用来解析我们的切入点表达式,读者可以看开头我们介绍的AspectJExpressionPointcut类关系图。
这一步主要是将解析的 aop:aspect 标签进行进行封装。 我们主要来看看这个分支。
public BeanDefinition parse(Element element, ParserContext parserContext) { CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(element.getTagName(), parserContext.extractSource(element)); parserContext.pushContainingComponent(compositeDef); // 向IoC容器中注册 AspectJAwareAdvisorAutoProxyCreator 类的BeanDefinition:(用于创建AOP代理对象的) // BeanPostProcessor可以对实例化之后的bean进行一些操作 // AspectJAwareAdvisorAutoProxyCreator 实现了BeanPostProcessor接口,可以对目标对象实例化之后,创建对应的代理对象 configureAutoProxyCreator(parserContext, element); // 获取<aop:config>标签的子标签<aop:aspect>、<aop:advisor> 、<aop:pointcut> List<Element> childElts = DomUtils.getChildElements(element); for (Element elt: childElts) { // 获取子标签的节点名称或者叫元素名称 String localName = parserContext.getDelegate().getLocalName(elt); if (POINTCUT.equals(localName)) { // 解析<aop:pointcut>标签 // 产生一个AspectJExpressionPointcut的BeanDefinition对象,并注册 parsePointcut(elt, parserContext); } else if (ADVISOR.equals(localName)) { // 解析<aop:advisor>标签 // 产生一个DefaultBeanFactoryPointcutAdvisor的BeanDefinition对象,并注册 parseAdvisor(elt, parserContext); } else if (ASPECT.equals(localName)) { // 解析<aop:aspect>标签 // 产生了很多BeanDefinition对象 // aop:after等标签对应5个BeanDefinition对象 // aop:after标签的method属性对应1个BeanDefinition对象 // 最终的AspectJPointcutAdvisor BeanDefinition类 parseAspect(elt, parserContext); } } parserContext.popAndRegisterContainingComponent(); return null; } 复制代码
我们进入到ConfigBeanDefinitionParser#parseAspect
这个方法开始解析 aop:aspect 标签,
我们主要关心parseAdvice方法
private void parseAspect(Element aspectElement, ParserContext parserContext) { // 获取<aop:aspect>标签的id属性值 String aspectId = aspectElement.getAttribute(ID); // 获取<aop:aspect>标签的ref属性值,也就是增强类的引用名称 String aspectName = aspectElement.getAttribute(REF); try { this.parseState.push(new AspectEntry(aspectId, aspectName)); List<BeanDefinition> beanDefinitions = new ArrayList<>(); List<BeanReference> beanReferences = new ArrayList<>(); // 处理<aop:aspect>标签的<aop:declare-parents>子标签 List<Element> declareParents = DomUtils.getChildElementsByTagName(aspectElement, DECLARE_PARENTS); for (int i = METHOD_INDEX; i < declareParents.size(); i++) { Element declareParentsElement = declareParents.get(i); beanDefinitions.add(parseDeclareParents(declareParentsElement, parserContext)); } // We have to parse "advice" and all the advice kinds in one loop, to get the // ordering semantics right. // 获取<aop:aspect>标签的所有子标签 NodeList nodeList = aspectElement.getChildNodes(); boolean adviceFoundAlready = false; for (int i = 0; i < nodeList.getLength(); i++) { Node node = nodeList.item(i); // 判断是否是<aop:before>、<aop:after>、<aop:after-returning>、<aop:after-throwing method="">、<aop:around method="">这五个标签 if (isAdviceNode(node, parserContext)) { if (!adviceFoundAlready) { adviceFoundAlready = true; if (!StringUtils.hasText(aspectName)) { parserContext.getReaderContext().error( "<aspect> tag needs aspect bean reference via 'ref' attribute when declaring advices.", aspectElement, this.parseState.snapshot()); return; } beanReferences.add(new RuntimeBeanReference(aspectName)); } // 解析<aop:before>等五个子标签 // 方法主要做了三件事: // 1、根据织入方式(before、after这些)创建RootBeanDefinition,名为adviceDef即advice定义 // 2、将上一步创建的RootBeanDefinition写入一个新的RootBeanDefinition,构造一个新的对象,名为advisorDefinition,即advisor定义 // 3、将advisorDefinition注册到DefaultListableBeanFactory中 AbstractBeanDefinition advisorDefinition = parseAdvice( aspectName, i, aspectElement, (Element) node, parserContext, beanDefinitions, beanReferences); beanDefinitions.add(advisorDefinition); } } AspectComponentDefinition aspectComponentDefinition = createAspectComponentDefinition( aspectElement, aspectId, beanDefinitions, beanReferences, parserContext); parserContext.pushContainingComponent(aspectComponentDefinition); List<Element> pointcuts = DomUtils.getChildElementsByTagName(aspectElement, POINTCUT); for (Element pointcutElement : pointcuts) { parsePointcut(pointcutElement, parserContext); } parserContext.popAndRegisterContainingComponent(); } finally { this.parseState.pop(); } } 复制代码
我们进入到ConfigBeanDefinitionParser#parseAdvice
这个方法主要做的是:解析 aop:before 等五个子标签
1、根据织入方式(before、after这些)创建RootBeanDefinition,名为adviceDef即advice定义 2、将上一步创建的RootBeanDefinition写入一个新的RootBeanDefinition,构造一个新的对象,名为advisorDefinition,即advisor定义 3、将advisorDefinition注册到DefaultListableBeanFactory中
private AbstractBeanDefinition parseAdvice( String aspectName, int order, Element aspectElement, Element adviceElement, ParserContext parserContext, List<BeanDefinition> beanDefinitions, List<BeanReference> beanReferences) { try { this.parseState.push(new AdviceEntry(parserContext.getDelegate().getLocalName(adviceElement))); // create the method factory bean // 创建方法工厂Bean的BeanDefinition对象:用于获取Advice增强类的Method对象, <aop:brefore method="before">中的method RootBeanDefinition methodDefinition = new RootBeanDefinition(MethodLocatingFactoryBean.class); // 设置MethodLocatingFactoryBean的targetBeanName为advice类的引用名称,也就是<aop:aspect ref="myAdvice">中的myAdvice methodDefinition.getPropertyValues().add("targetBeanName", aspectName); // 设置MethodLocatingFactoryBean的methodName为<aop:after>标签的method属性值(也就是method="before"中的before,作为advice方法名称) methodDefinition.getPropertyValues().add("methodName", adviceElement.getAttribute("method")); methodDefinition.setSynthetic(true); // create instance factory definition // 创建实例工厂BeanDefinition:用于创建增强类的实例,也就是<aop:aspect ref="myAdvice">中的myAdvice RootBeanDefinition aspectFactoryDef = new RootBeanDefinition(SimpleBeanFactoryAwareAspectInstanceFactory.class); // 设置SimpleBeanFactoryAwareAspectInstanceFactory的aspectBeanName为advice类的引用名称 aspectFactoryDef.getPropertyValues().add("aspectBeanName", aspectName); aspectFactoryDef.setSynthetic(true); //以上的两个BeanDefinition的作用主要是通过反射调用Advice对象的指定方法 // method.invoke(obj,args) // register the pointcut // 通知增强类的BeanDefinition对象(核心),也就是一个<aop:before>等对应一个adviceDef AbstractBeanDefinition adviceDef = createAdviceDefinition( adviceElement, parserContext, aspectName, order, methodDefinition, aspectFactoryDef, beanDefinitions, beanReferences); // configure the advisor // 通知器类的BeanDefinition对象, 对应<aop:aspect> RootBeanDefinition advisorDefinition = new RootBeanDefinition(AspectJPointcutAdvisor.class); advisorDefinition.setSource(parserContext.extractSource(adviceElement)); // 给通知器类设置Advice对象属性值 advisorDefinition.getConstructorArgumentValues().addGenericArgumentValue(adviceDef); if (aspectElement.hasAttribute(ORDER_PROPERTY)) { advisorDefinition.getPropertyValues().add( ORDER_PROPERTY, aspectElement.getAttribute(ORDER_PROPERTY)); } // register the final advisor // 将advisorDefinition注册到IoC容器中 parserContext.getReaderContext().registerWithGeneratedName(advisorDefinition); return advisorDefinition; } finally { this.parseState.pop(); } } 复制代码
至此对标签的解析完毕
分析AOP代理对象创建之前,我们先来看下类的继承结构图:
我们来看AbstractAutoProxyCreator类,里面有这些方法:
postProcessBeforeInitialization postProcessAfterInitialization----AOP功能入口 postProcessBeforeInstantiation postProcessAfterInstantiation postProcessPropertyValues 复制代码
我们找到分析入口:AbstractAutoProxyCreator#postProcessAfterInitialization
@Override public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) { if (bean != null) { Object cacheKey = getCacheKey(bean.getClass(), beanName); if (this.earlyProxyReferences.remove(cacheKey) != bean) { // 使用动态代理技术,产生代理对象 // bean : 目标对象 // beanName :目标对象名称 return wrapIfNecessary(bean, beanName, cacheKey); } } return bean; } 复制代码
进入AbstractAutoProxyCreator#wrapIfNecessary
这个方法主要做三件事:
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) { if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) { return bean; } if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) { return bean; } // Advice/Pointcut/Advisor/AopInfrastructureBean接口的beanClass不进行代理以及对beanName为aop内的切面名也不进行代理 // 此处可查看子类复写的shouldSkip()方法 if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) { this.advisedBeans.put(cacheKey, Boolean.FALSE); return bean; } // Create proxy if we have advice. // 查找对代理类相关的advisor对象集合,此处就与point-cut表达式有关了 Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null); // 对相应的advisor不为空才采取代理 if (specificInterceptors != DO_NOT_PROXY) { this.advisedBeans.put(cacheKey, Boolean.TRUE); // 通过jdk动态代理或者cglib动态代理,产生代理对象 Object proxy = createProxy( bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean)); // 放入代理类型缓存 this.proxyTypes.put(cacheKey, proxy.getClass()); return proxy; } this.advisedBeans.put(cacheKey, Boolean.FALSE); return bean; } 复制代码
我们接着进入AbstractAutoProxyCreator#createProxy
protected Object createProxy(Class<?> beanClass, @Nullable String beanName, @Nullable Object[] specificInterceptors, TargetSource targetSource) { if (this.beanFactory instanceof ConfigurableListableBeanFactory) { AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass); } // 创建代理工厂对象 ProxyFactory proxyFactory = new ProxyFactory(); proxyFactory.copyFrom(this); //如果没有使用CGLib代理 if (!proxyFactory.isProxyTargetClass()) { // 是否可能使用CGLib代理 if (shouldProxyTargetClass(beanClass, beanName)) { proxyFactory.setProxyTargetClass(true); } else { // 查看beanClass对应的类是否含有InitializingBean.class/DisposableBean.class/Aware.class接口 // 无则采用JDK动态代理,有则采用CGLib动态代理 evaluateProxyInterfaces(beanClass, proxyFactory); } } // 获得所有关联的Advisor集合(该分支待补充) Advisor[] advisors = buildAdvisors(beanName, specificInterceptors); proxyFactory.addAdvisors(advisors); // 此处的targetSource一般为SingletonTargetSource proxyFactory.setTargetSource(targetSource); // 空的实现 customizeProxyFactory(proxyFactory); proxyFactory.setFrozen(this.freezeProxy); // 是否设置预过滤模式,此处针对本文为true if (advisorsPreFiltered()) { proxyFactory.setPreFiltered(true); } // 获取使用JDK动态代理或者cglib动态代理产生的对象 return proxyFactory.getProxy(getProxyClassLoader()); } 复制代码
我们进入ProxyFactory#getProxy
public Object getProxy(@Nullable ClassLoader classLoader) { // 1、创建JDK方式的AOP代理或者CGLib方式的AOP代理 // 2、调用具体的AopProxy来创建Proxy代理对象 return createAopProxy().getProxy(classLoader); } 复制代码
我们选择jdk方式创建代理,因为我们是通过接口实现代理的。
我们进入:JdkDynamicAopProxy#getProxy
这个方法主要做两件事:
public Object getProxy(@Nullable ClassLoader classLoader) { if (logger.isTraceEnabled()) { logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource()); } // 获取完整的代理接口 Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true); findDefinedEqualsAndHashCodeMethods(proxiedInterfaces); // 调用JDK动态代理方法 return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this); } 复制代码
至此生成代理类对象分析完毕
我们来看一下JdkDynamicAopProxy,它实现了InvocationHandler,所以代理对象执行流程分析的入口我们已经找到了
入口:JdkDynamicAopProxy#invoke
这个方法主要做以下事情:
获取针对该目标对象的所有增强器(advisor)
这些Advisor都是有顺序的,他们会按照顺序进行链式调用
如果调用链为空,则直接通过反射调用目标对象的方法,也就是不对方法进行任何的增强
创建ReflectiveMethodInvocation实例对调用链进行调用,开始执行AOP的拦截过程
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object oldProxy = null; boolean setProxyContext = false; TargetSource targetSource = this.advised.targetSource; Object target = null; try { //...省略若干代码 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. // 获取针对该目标对象的所有增强器(advisor), 这些advisor都是有顺序的,他们会按照顺序进行链式调用 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. // 检查是否我们有一些通知。如果我们没有,我们可以直接对目标类进行反射调用,避免创建MethodInvocation类 // 调用目标类的方法 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... //我们需要创建一个方法调用 // proxy:生成的动态代理对象 // target:目标方法 // args: 目标方法参数 // targetClass:目标类对象 // chain: AOP拦截器执行链,是一个MethodInterceptor的集合 MethodInvocation invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain); // Proceed to the joinpoint through the interceptor chain. // 通过拦截器链进入连接点 // 开始执行AOP的拦截过程 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); } } 复制代码
我们来看获取调用链的过程:
进入到:AdvisedSupport#getInterceptorsAndDynamicInterceptionAdvice
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class<?> targetClass) { // 创建以方法为单位的缓存key MethodCacheKey cacheKey = new MethodCacheKey(method); // 从缓存中获取指定方法的advisor集合 List<Object> cached = this.methodCache.get(cacheKey); if (cached == null) { // 获取目标类中指定方法的MethodInterceptor集合,该集合是由Advisor转换而来 cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice( this, method, targetClass); this.methodCache.put(cacheKey, cached); } return cached; } 复制代码
我们进入获取MethodInterceptor集合:
DefaultAdviceChainFactory#getInterceptorsAndDynamicInterceptionAdvice
这里主要做:
创建DefaultAdvisorAdapterRegistry实例,并创建MethodBeforeAdviceAdapter、AfterReturningAdviceAdapter、ThrowsAdviceAdapter适配器
这里为啥需要适配器呢?我们来看下面的类关系图:
有些Advice和拦截器MethodInterceptor根本就没有关系,此时就需要适配器将他们之间产生关系。这里用了适配器模式,打个比方,我们买了好多型号的电脑,使用的电压都不一样,我们家的电压是220v,那怎么样才能使我们的电脑能充上电呢,纳米就需要电源适配器了。这样讲应该懂了吧
2.变量所有的Advisor集合,使用Pointcut类的ClassFilter().matches()进行匹配,还有使用Pointcut().getMethodMatcher()进行匹配,如果匹配上则将advisor转成MethodInterceptor,
3.如果需要根据参数动态匹配(比如重载)则拦截器链中新增InterceptorAndDynamicMethodMatcher
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. // advice适配器注册中心 // MethodBeforeAdviceAdapter:将Advisor适配成MethodBeforeAdvice // AfterReturningAdviceAdapter:将Advisor适配成AfterReturningAdvice // ThrowsAdviceAdapter: 将Advisor适配成ThrowsAdvice AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance(); Advisor[] advisors = config.getAdvisors(); // 返回值集合,里面装的都是Interceptor或者它的子类接口MethodInterceptor List<Object> interceptorList = new ArrayList<>(advisors.length); // 获取目标类的类型 Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass()); // 是否有引介 Boolean hasIntroductions = null; // 去产生代理对象的过程中,针对该目标方法获取到的所有合适的Advisor集合 for (Advisor advisor : advisors) { if (advisor instanceof PointcutAdvisor) { // Add it conditionally. PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor; // 如果该Advisor可以对目标类进行增强,则进行后续操作 if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) { // 获取方法适配器,该方法匹配器可以根据指定的切入点表达式进行方法匹配 MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher(); boolean match; if (mm instanceof IntroductionAwareMethodMatcher) { if (hasIntroductions == null) { hasIntroductions = hasMatchingIntroductions(advisors, actualClass); } match = ((IntroductionAwareMethodMatcher) mm).matches(method, actualClass, hasIntroductions); } else { match = mm.matches(method, actualClass); } if (match) { // 将advisor转成MethodInterceptor MethodInterceptor[] interceptors = registry.getInterceptors(advisor); // MethodMatcher接口通过重载定义了两个matches()方法 // 两个参数的matches() 被称为静态匹配,在匹配条件不是太严格时使用,可以满足大部分场景的使用 // 称之为静态的主要是区分为三个参数的matches()方法需要在运行时动态的对参数的类型进行匹配 // 两个方法的分界线就是boolean isRuntime()方法 // 进行匹配时先用两个参数的matches()方法进行匹配,若匹配成功,则检查boolean isRuntime()的返回值若为 // true, 则调用三个参数的matches()方法进行匹配(若两个参数的都匹配不中,三个参数的必定匹配不中) // 需要根据参数动态匹配(比如重载) 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; } 复制代码
我们返回到JdkDynamicAopProxy#invoke
进入到ReflectiveMethodInvocation#proceed()中:
这个是调用链的执行过程
如果执行到链条的末尾,则直接调用连接点,即直接调用目标方法
最终会调用MethodInterceptor的invoke方法,本文配置文件会调用AspectJAfterAdvice、MethodBeforeAdviceInterceptor
我们来看AspectJAfterAdvice:里面的方法调用是这样,又继续调用调用链
public Object invoke(MethodInvocation mi) throws Throwable { try { return mi.proceed(); } finally { invokeAdviceMethod(getJoinPointMatch(), null, null); } } 复制代码
我们看:MethodBeforeAdviceInterceptor(前置通知拦截器)
public Object invoke(MethodInvocation mi) throws Throwable { this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis()); return mi.proceed(); } 复制代码
是先执行目标方法然后再调用下一个调用链
这就保证了调用的顺序符号前置通知在目标方法前调用,最终通知是在目标方法执行后通知,同时也说明了配置文件中<aop:before />
、<aop:after method="after"/>的顺序不会影响最终执行的顺序,顺序是通过调用链来保证的。
public Object proceed() throws Throwable { // We start with an index of -1 and increment early. // 如果执行到链条的末尾, 则直接调用连接点方法 即直接调用目标方法 if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) { return invokeJoinpoint(); } // 获取集合中的MethodInterceptor Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex); // 如果是InterceptorAndDynamicMethodMatcher类型(动态匹配) if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) { // Evaluate dynamic method matcher here: static part will already have // been evaluated and found to match. InterceptorAndDynamicMethodMatcher dm = (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice; Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass()); // 这里每一次都去匹配是否适用于这个目标方法 if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) { // 如果匹配则直接调用MethodInterceptor的invoke方法 // 注意这里传入的参数是this,我们下面看一下ReflectiveMethodInvocation的类型 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. // 说明是适用于此目标方法的,直接调用MethodInterceptor的invoke方法 // 传入this即ReflectiveMethodInvocation实例 // 传入this进入 这样就可以形成一个调用的链条了 return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this); } } 复制代码
经过长久的书写,终于成文,由于水平有限,不能详尽各个方面,忘读者见谅,可以和我交流。