【二】Spring AOP 最全源码详解之创建代理对象
目录
前在《【九】Spring IoC 最全源码详解之initializeBean》中提到过创建Spring AOP代理对象的留下就在执行bean后置处理器的postProcessAfterInitialization方法中。更具体一点是执行AnnotationAwareAspectJAutoProxyCreator处理器的父类AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsAfterInitialization的方法中完成的。
[code]protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) { if (System.getSecurityManager() != null) { AccessController.doPrivileged((PrivilegedAction<Object>) () -> { invokeAwareMethods(beanName, bean); return null; }, getAccessControlContext()); } else { invokeAwareMethods(beanName, bean); } Object wrappedBean = bean; if (mbd == null || !mbd.isSynthetic()) { wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); } invokeInitMethods(beanName, wrappedBean, mbd); if (mbd == null || !mbd.isSynthetic()) { wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); } return wrappedBean; }
我们具体来看看它的方法实现:
[code]public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) { if (bean != null) { // 如果是普通bean,则返回beanName,如果是FactoryBean,则返回加上前缀&的&beanName Object cacheKey = getCacheKey(bean.getClass(), beanName); // earlyProxyReferences中缓存的是已经创建好的代理对象 if (!this.earlyProxyReferences.contains(cacheKey)) { return wrapIfNecessary(bean, beanName, cacheKey); } } return bean; }
getCacheKey的作用是:如果是对于普通bean,则返回beanName,如果是FactoryBean,则返回加上前缀&的&beanName。然后根据cacheKey去earlyProxyReferences这个缓存中看看该代理对象是否已经被创建过了,如果创建过直接返回bean。否则进入wrapIfNecessary方法。
1. 判断是否需要被代理
[code]protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) { // 也是看看有没有缓存,有缓存对象就直接返回了。 if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) { return bean; } // 如果该bean不需要被代理,则直接返回原始的bean对象 if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) { return bean; } // if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) { this.advisedBeans.put(cacheKey, Boolean.FALSE); return bean; } Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null); if (specificInterceptors != DO_NOT_PROXY) { this.advisedBeans.put(cacheKey, Boolean.TRUE); 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; }
首先也是看看有没有缓存,有缓存对象就直接返回了。然后尝试再advisedBeans缓存中获取要代理的原始对象,如果它不需要被代理的话也直接返回原始对象。值得注意的是在IOC启动过程中,第一次进入advisedBeans这个缓存中是没有值的。isInfrastructureClass和shouldSkip在上一篇文章已经分析过,这里不再赘述。其对应的if分支是不会进入。重点放在方法getAdvicesAndAdvisorsForBean,该方法又主要委托findEligibleAdvisors来实现寻找advisor的逻辑,所以我们直接来看findEligibleAdvisors
[code]protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) { // 获取所有已经解析完成的advisor List<Advisor> candidateAdvisors = findCandidateAdvisors(); // 根据beanClass过滤candidateAdvisors中的advisor List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName); extendAdvisors(eligibleAdvisors); if (!eligibleAdvisors.isEmpty()) { eligibleAdvisors = sortAdvisors(eligibleAdvisors); } return eligibleAdvisors; }
findCandidateAdvisors将找到的advisor放入到candidateAdvisors中(详细分析请见上一篇文章)。随后在findEligibleAdvisors中根据beanClass过滤除适用的advisor。最终执行的方法是在AopUtils#findAdvisorsThatCanApply
[code]public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) { if (candidateAdvisors.isEmpty()) { return candidateAdvisors; } List<Advisor> eligibleAdvisors = new ArrayList<>(); for (Advisor candidate : candidateAdvisors) { if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) { eligibleAdvisors.add(candidate); } } boolean hasIntroductions = !eligibleAdvisors.isEmpty(); for (Advisor candidate : candidateAdvisors) { if (candidate instanceof IntroductionAdvisor) { // already processed continue; } if (canApply(candidate, clazz, hasIntroductions)) { eligibleAdvisors.add(candidate); } } return eligibleAdvisors; }
Advisor分为IntroductionAdvisor和PointcutAdvisor两种,我们使用的绝大部分Advisor都是PointcutAdvisor。canApply方法可以用来确认所给定的类上advisor是否可以被应用。最后返回过滤后可以被应用在给定类上的advisors。以OperationUtil.class为例,OperationAop.class中的三个Advice都可以被作用在OperationUtil.class上;而其余的类则一个也没有。
返回到findEligibleAdvisors中执行extendAdvisors方法,该方法会添加一个DefaultPointcutAdvisor到eligibleAdvisors中。如果使用AspectJ的切点表达式,则会使用AspectJExpressionPointcutAdvisor;如果使用名称匹配切点的方式,则用NameMatchMethodPointcutAdvisor;如果使用正则匹配切点的方式,则使用RegexpMethodPointcutAdvisor;如果使用其他方式,比如用户自定义切点的方式,那么就使用DefaultPointcutAdvisor。随后的排序会将刚刚添加进入的DefaultPointcutAdvisor排到第一个位置。
最终wrapIfNecessary方法Object[] specificInterceptors得到的结果就是刚刚返回的eligibleAdvisors。如果specificInterceptors不为null,就advisedBeans.put(cacheKey, Boolean.TRUE),将对应的bean添加到全局的advisedBeans中,并且value是true,代表该bean需要被代理。接下来就是通过createProxy方法创建代理类了。
2. 创建代理类createProxy
[code]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); if (!proxyFactory.isProxyTargetClass()) { if (shouldProxyTargetClass(beanClass, beanName)) { proxyFactory.setProxyTarget 20000 Class(true); } else { evaluateProxyInterfaces(beanClass, proxyFactory); } } // 就是把specificInterceptors中的advisors和commonInterceptors中的拦截器合并(如果有的话)在一起封装成Advisor返回 Advisor[] advisors = buildAdvisors(beanName, specificInterceptors); // 将advisors和源对象设置到proxyFactory上 proxyFactory.addAdvisors(advisors); proxyFactory.setTargetSource(targetSource); customizeProxyFactory(proxyFactory); proxyFactory.setFrozen(this.freezeProxy); if (advisorsPreFiltered()) { proxyFactory.setPreFiltered(true); } // 真正去创建代理对象了 return proxyFactory.getProxy(getProxyClassLoader()); }
exposeTargetClass这个步骤看了很久才明白Spring的意思。下面简单说下我的理解:
走到这里就已经能肯定代理类是会创建的了,所以可以提前“曝光”它的原始类。expose一词是公之于众的意思,在这里也就是告诉其他bean:大家来看看啊,当前正在创建的bean(比如是OperationUtil)即将要青蛙变王子了!
怎么做到公之于众呢?Spring的做法是在方法内部在正常创建的bean的bd(全写是BeanDefinition)中设置上一个属性<"originalTargetClass", OperationUtil.class>。而bd是存放在bdmap中,bdmap又是由bean工厂直接管理。创建bean必须要有bean工厂的参与,这样就意味着只要在bd中增加一个属性就相当于对其他bean可见了。
接下来创建一个ProxyFactory,并从当前bean后置处理器AnnotationAwareAspectJAutoProxyCreator中获取参数初始化自身。然后确定代理方式是通过接口代理还是类继承代理。通过接口代理使用JDK自身提供的动态代理就能实现,而其他的代理只能通过Cglib实现动态代理。proxyTargetClass默认是false使用JDK代理,如果是true则使用Cglib。
接下来的buildAdvisors是把specificInterceptors中的advisors和commonInterceptors中的拦截器合并(如果有的话)在一起封装成Advisor返回。随后在proxyFactory对象上进行设置。这里targetSource就是被代理的bean对象。
最后就到了执行真正的创建逻辑了。
[code]public Object getProxy(@Nullable ClassLoader classLoader) { return createAopProxy().getProxy(classLoader); } public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException { if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) { // 获得被代理对象的类型 Class<?> targetClass = config.getTargetClass(); // 如果对象类型是接口,或者是JAVA的动态代理类,那么就调用JDK的动态代理方法生成代理对象 if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) { return new JdkDynamicAopProxy(config); } // 否则使用CGLIB生成代理对象 return new ObjenesisCglibAopProxy(config); } else { return new JdkDynamicAopProxy(config); } } // JDK动态代理 public Object getProxy(@Nullable ClassLoader classLoader) { Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true); findDefinedEqualsAndHashCodeMethods(proxiedInterfaces); return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this); }
从config中拿出被代理对象的类型,然后判断该对象是否是接口或者是java的动态代理类。如果是则创建JdkDynamicAopProxy工厂,否则创建Cglib的ObjenesisCglibAopProxy工厂。随后调用对应Proxy工厂的getProxy方法创建代理对象。以创建JDK动态代理为例,最终会调用JAVA提供的Proxy.newProxyInstance动态代理方法代理对象后返回。
到此,Spring AOP的代理对象创建过程源码就分析的差不多了。总结一下:在bean的创建过程中,先实例化完成被代理对象并完成依赖注入后,进行到初始化bean的阶段。利用bean后置处理器AnnotationAwareAspectJAutoProxyCreator的applyBeanPostProcessorsAfterInitialization方法实现对目标对象的代理任务。任务进行过程中大致可以分为2步:1.获取之前已经解析好的advisors,逐个判断目标代理对象是否可以适用。2.如果使用则创建代理工厂,然后判断代理类型是通过接口还是通过类,如果是通过接口就由JDK动态代理生成代理对象,否则使用 Cglib来做这件事。
3. 附录:本工程项目文件
[code]@Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface HodayDouble { }
[code]@Aspect @Component public class OperationAop { @Pointcut("@annotation(com.Hodey.analyseaop.anno.HodayDouble)") public void doCut(){} @Around("doCut()") public int doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable { Object[] args = proceedingJoinPoint.getArgs(); int i = (int) args[0]; int j = (int) args[1]; System.out.println("入参:i:" + i); System.out.println("入参:j:" + j); System.out.println("before around"); int result = (int) proceedingJoinPoint.proceed(); System.out.println("after around"); System.out.println("原始结果:" + result); result = result * 2; System.out.println("代理结果:" + result); return result; } @Before("doCut()") public void doBefore(){ System.out.println("@Before print"); } @After("doCut()") public void doAfter(){ System.out.println("@After print"); } }
[code]@Service("service") public class OperationService { @Autowired private OperationUtil ops; public int add(int i , int j){ return ops.add(i,j); } }
[code]@Component public class OperationUtil { @HodayDouble public int add(int i, int j){ int result = i + j; return result; } }
[code]@ComponentScan("com.Hodey") @EnableAutoConfiguration public class AnalyseAopApplication { public static void main(String[] args) { AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(AnalyseAopApplication.class); OperationService opsService = (OperationService) ctx.getBean("service"); int result = opsService.add(2,3); System.out.println("最终结果:" + result); } }
执行结果:
[code]入参:i:2 入参:j:3 before around @Before print after around 原始结果:5 代理结果:10 @After print 最终结果:10
- Spring源码阅读4.2-Aspecjt AOP之代理对象的创建
- Spring AOP源码分析(三):基于JDK动态代理和CGLIB创建代理对象的实现原理
- Spring AOP 源码分析——创建代理对象
- 【Spring源码--AOP的实现】(一)AopProxy代理对象的创建
- Spring AOP 源码分析 - 创建代理对象
- Spring AOP高级——源码实现(3)AopProxy代理对象之JDK动态代理的创建过程
- Spring源码之创建AOP代理(补)
- Spring Aop(十四)——Aop自动创建代理对象的原理
- SpringAOP源码解析之代理创建篇
- Spring 源码分析(三) —— AOP(五)创建代理
- Spring3.1.0实现原理分析(九).AOP之创建代理对象的过程
- spring 源码探索 -- aop 标签解析和创建代理
- Spring3.1.0实现原理分析(九).AOP创建代理对象的过程
- Spring AOP源码分析(生成代理对象)
- spring技术内幕8-创建AOP代理对象并对目标对象切面拦截
- Spring源码分析----建立AopProxy代理对象和AOP拦截器的调用
- Spring Aop(十三)——ProxyFactoryBean创建代理对象
- Spring 源码分析(三) —— AOP(五)创建代理
- Spring进阶之路(9)-Spring AOP面向切面编程概念以及通过JDK代理生成AOP代理对象
- 深入理解SpringAOP之代理对象