您的位置:首页 > 编程语言 > Java开发

这一次搞懂Spring代理创建及AOP链式调用过程

websocket 2020-06-27 18:33 169 查看 https://www.cnblogs.com/yewy/p
@[toc] # 前言 AOP,也就是面向切面编程,它可以将公共的代码抽离出来,动态的织入到目标类、目标方法中,大大提高我们编程的效率,也使程序变得更加优雅。如事务、操作日志等都可以使用AOP实现。这种织入可以是**在运行期动态生成代理对象**实现,也可以在**编译期**、**类加载时期**静态织入到代码中。而Spring正是通过第一种方法实现,且在代理类的生成上也有两种方式:JDK Proxy和CGLIB,默认当类实现了接口时使用前者,否则使用后者;另外Spring AOP只能实现对方法的增强。 # 正文 ## 基本概念 AOP的术语很多,虽然不清楚术语我们也能很熟练地使用AOP,但是要理解分析源码,术语就需要深刻体会其含义。 - 增强(Advice):就是我们想要额外增加的功能 - 目标对象(Target):就是我们想要增强的目标类,如果没有AOP,我们需要在每个目标对象中实现日志、事务管理等非业务逻辑 - 连接点(JoinPoint):程序执行时的特定时机,如方法执行前、后以及抛出异常后等等。 - 切点(Pointcut):连接点的导航,我们如何找到目标对象呢?切点的作用就在于此,在Spring中就是匹配表达式。 - 引介(Introduction):引介是一种特殊的增强,它为类添加一些属性和方法。这样,即使一个业务类原本没有实现某个接口,通过AOP的引介功能,我们可以动态地为该业务类添加接口的实现逻辑,让业务类成为这个接口的实现类。 - 织入(Weaving):即如何将增强添加到目标对象的连接点上,有动态(运行期生成代理)、静态(编译期、类加载时期)两种方式。 - 代理(Proxy):目标对象被织入增强后,就会产生一个代理对象,该对象可能是和原对象实现了同样的一个接口(JDK),也可能是原对象的子类(CGLIB)。 - 切面(Aspect、Advisor):切面由切点和增强组成,包含了这两者的定义。 ## 代理对象的创建 在熟悉了AOP术语后,下面就来看看Spring是如何创建代理对象的,是否还记得上一篇提到的AOP的入口呢?在**AbstractAutowireCapableBeanFactory**类的**applyBeanPostProcessorsAfterInitialization**方法中循环调用了**BeanPostProcessor**的**postProcessAfterInitialization**方法,其中一个就是我们创建代理对象的入口。这里是Bean实例化完成去创建代理对象,理所当然应该这样,但实际上在Bean实例化之前调用了一个**resolveBeforeInstantiation**方法,这里实际上我们也是有机会可以提前创建代理对象的,这里放到最后来分析,先来看主入口,进入到**AbstractAutoProxyCreator**类中: ```java public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) { if (bean != null) { Object cacheKey = getCacheKey(bean.getClass(), beanName); if (!this.earlyProxyReferences.contains(cacheKey)) { return wrapIfNecessary(bean, beanName, cacheKey); } } return bean; } protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) { //创建当前bean的代理,如果这个bean有advice的话,重点看 // Create proxy if we have advice. Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null); //如果有切面,则生成该bean的代理 if (specificInterceptors != DO_NOT_PROXY) { this.advisedBeans.put(cacheKey, Boolean.TRUE); //把被代理对象bean实例封装到SingletonTargetSource对象中 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; } ``` 先从缓存中拿,没有则调用**wrapIfNecessary**方法创建。在这个方法里面主要看两个地方:**getAdvicesAndAdvisorsForBean**和**createProxy**。简单一句话概括就是先扫描后创建,问题是扫描什么呢?你可以先结合上面的概念思考下,换你会怎么做。进入到子类**AbstractAdvisorAutoProxyCreator**的**getAdvicesAndAdvisorsForBean**方法中: ```java protected Object[] getAdvicesAndAdvisorsForBean( Class beanClass, String beanName, @Nullable TargetSource targetSource) { //找到合格的切面 List
标签: