文章导航
目录
文章导航
前言
正文
方法1:postProcessAfterInitialization
方法2:wrapIfNecessary
方法3:shouldSkip
方法4:getAdvicesAndAdvisorsForBean
方法5:findAdvisorsThatCanApply
方法6:extendAdvisors
方法7:createProxy
方法8:getProxy
方法9:createAopProxy
总结
前言
上篇文章讲解了AOP解析工作,将配置文件解析并封装成beanDefinition,由于配置文件中有5个通知方法,before、after、around、after-returning、after-throwing,这里会将其解析成5个advisor通知类。
<?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: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/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <bean id="accountAdvice" class="service.impl.AccountAdvice" ></bean> <bean id="myAccount" class="service.impl.MyAccount" ></bean> <aop:config> <aop:pointcut id="pointCut" expression="execution(* service.impl.*.*())"/> <aop:aspect ref="accountAdvice"> <aop:after method="after" pointcut-ref="pointCut"></aop:after> <aop:before method="before" pointcut-ref="pointCut"></aop:before> <aop:around method="around" pointcut-ref="pointCut"></aop:around> <aop:after-returning method="afterReturn" pointcut-ref="pointCut"></aop:after-returning> <aop:after-throwing method="afterThrow" pointcut-ref="pointCut"></aop:after-throwing> </aop:aspect> </aop:config> </beans>
解析后的BeanDefinitions集合信息:
正文
之前Spring IOC文章讲解过Bean的实例化过程,在实例化Bean之后会进行属性填充(populateBean)、执行初始化方法(initializeBean)。而代理类的生成就在执行初始化方法(initializeBean)中,在该方法中会执行beanPostProcessor方法,如果该bean需要代理,则会进行代理工作。
本章案例中需要被代理的类是myAccount,所以我们来到myAccount实例化过程中的initializeBean方法中;
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) { // 如果安全管理器不为空 if (System.getSecurityManager() != null) { // 以特权的方式执行回调bean中的Aware接口方法 AccessController.doPrivileged((PrivilegedAction<Object>) () -> { invokeAwareMethods(beanName, bean); return null; }, getAccessControlContext()); } else { // Aware接口处理器,调用BeanNameAware、BeanClassLoaderAware、beanFactoryAware invokeAwareMethods(beanName, bean); } Object wrappedBean = bean; //如果mdb不为null || mbd不是"synthetic"。一般是指只有AOP相关的prointCut配置或者Advice配置才会将 synthetic设置为true if (mbd == null || !mbd.isSynthetic()) { // 将BeanPostProcessors应用到给定的现有Bean实例,调用它们的postProcessBeforeInitialization初始化方法。 // 返回的Bean实例可能是原始Bean包装器 wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); } try { //调用初始化方法,先调用bean的InitializingBean接口方法,后调用bean的自定义初始化方法 invokeInitMethods(beanName, wrappedBean, mbd); } catch (Throwable ex) { //捕捉调用初始化方法时抛出的异常,重新抛出Bean创建异常:调用初始化方法失败 throw new BeanCreationException( (mbd != null ? mbd.getResourceDescription() : null), beanName, "Invocation of init method failed", ex); } //如果mbd为null || mbd不是"synthetic" if (mbd == null || !mbd.isSynthetic()) { // 将BeanPostProcessors应用到给定的现有Bean实例,调用它们的postProcessAfterInitialization方法。 // 返回的Bean实例可能是原始Bean包装器 wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); } //返回包装后的Bean return wrappedBean; }
AOP的代理类生成过程在BeanPostProcessor的after方法中调用
applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName),见方法1详解
方法1:postProcessAfterInitialization
进入到AspectJAwareAdivsorAutoProxyCreator类中的postProcessAfterInitialization方法;
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) { if (bean != null) { // 获取当前bean的key:如果beanName不为空,则以beanName为key,如果为FactoryBean类型则beanName名称前面会加上“&”符号 Object cacheKey = getCacheKey(bean.getClass(), beanName); // 判断当前bean是否正在被代理,如果正在被代理则不进行代理操作 if (this.earlyProxyReferences.remove(cacheKey) != bean) { // 如果它需要被代理,则需要封装指定的bean return wrapIfNecessary(bean, beanName, cacheKey); } } return bean; }
wrapIfNecessary(bean, beanName, cacheKey),见方法2详解
方法2:wrapIfNecessary
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) { // 判断是否已经处理过,处理过则直接返回 if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) { return bean; } // 这里advisedBeans缓存了已经进行了代理流程处理的bean,如果缓存中存在,则可以直接返回 //这里存在两种bean,一种是不需要代理的bean,一种是真正需要代理的,避免下次判断时可以直接返回,不走下面处理逻辑 if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) { return bean; } // 这里isInfrastructureClass()用于判断当前bean是否为Spring系统自带的bean,如:Advice、Pointcut、Advisor、AopInfrastructureBean的实现类 // 不用进行代理的;shouldSkip()则用于判断当前bean是否应该被略过 if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) { // 对当前bean进行缓存 this.advisedBeans.put(cacheKey, Boolean.FALSE); return bean; } // Create proxy if we have advice. // 尝试获取能够匹配当前被代理类的通知类信息 Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null); // 如果找到合适的通知类,则进行代理操作 if (specificInterceptors != DO_NOT_PROXY) { // 对当前bean的代理状态进行缓存 this.advisedBeans.put(cacheKey, Boolean.TRUE); // 根据获取到的Advices和Advisors为当前bean生成代理对象 Object proxy = createProxy( bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean)); // 缓存生成的代理bean的类型,并且返回生成的代理bean this.proxyTypes.put(cacheKey, proxy.getClass()); return proxy; } this.advisedBeans.put(cacheKey, Boolean.FALSE); return bean; }
shouldSkip(bean.getClass(), beanName),见方法3详解
getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null),见方法4详解
createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean)),见方法7详解
方法3:shouldSkip
protected boolean shouldSkip(Class<?> beanClass, String beanName) { // TODO: Consider optimization by caching the list of the aspect names //尝试从beanFacotry工厂中获取配置文件中定义好的五个通知方法,它们被封装成了advisor对象,所以这里能获取到5个 List<Advisor> candidateAdvisors = findCandidateAdvisors(); for (Advisor advisor : candidateAdvisors) { //判断通知类中的切面类名称,如果当前bean是切面类,则不应该被代理,会跳过 if (advisor instanceof AspectJPointcutAdvisor && ((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) { return true; } } return super.shouldSkip(beanClass, beanName); }
方法4:getAdvicesAndAdvisorsForBean
protected Object[] getAdvicesAndAdvisorsForBean( Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) { // 找合适的增强器对象 List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName); // 若为空表示没找到 if (advisors.isEmpty()) { return DO_NOT_PROXY; } return advisors.toArray(); }
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) { // 将当前系统中所有的切面类的切面逻辑进行封装,从而得到目标Advisor List<Advisor> candidateAdvisors = findCandidateAdvisors(); // 对获取到的所有Advisor进行判断,判断其中的表达式是否能够匹配上要被代理的类 List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName); // 提供的hook方法,用于对目标Advisor进行扩展 extendAdvisors(eligibleAdvisors); if (!eligibleAdvisors.isEmpty()) { // 对需要代理的Advisor按照一定的规则进行排序 eligibleAdvisors = sortAdvisors(eligibleAdvisors); } return eligibleAdvisors; }
findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName),见方法5详解
extendAdvisors(eligibleAdvisors),见方法6详解
方法5:findAdvisorsThatCanApply
protected List<Advisor> findAdvisorsThatCanApply( List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) { ProxyCreationContext.setCurrentProxiedBeanName(beanName); try { // 从候选的通知器中找到合适正在创建的实例对象的通知器 return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass); } finally { ProxyCreationContext.setCurrentProxiedBeanName(null); } }
public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) { // 若候选的增强器集合为空 直接返回 if (candidateAdvisors.isEmpty()) { return candidateAdvisors; } // 定义一个合适的增强器集合对象 List<Advisor> eligibleAdvisors = new ArrayList<>(); // 循环我们候选的通知类对象 for (Advisor candidate : candidateAdvisors) { // 判断我们的通知类对象是不是实现了IntroductionAdvisor if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) { eligibleAdvisors.add(candidate); } } // 判断是否有合适的通知类 boolean hasIntroductions = !eligibleAdvisors.isEmpty(); for (Advisor candidate : candidateAdvisors) { // 判断我们的通知类对象是不是实现了IntroductionAdvisor if (candidate instanceof IntroductionAdvisor) { // already processed // 在上面已经处理过,不需要处理 continue; } // 真正的判断增强器是否合适当前类型,这里会通过切入点表达式进行判断是否适用于当前类 if (canApply(candidate, clazz, hasIntroductions)) { eligibleAdvisors.add(candidate); } } return eligibleAdvisors; }
方法6:extendAdvisors
protected void extendAdvisors(List<Advisor> candidateAdvisors) { AspectJProxyUtils.makeAdvisorChainAspectJCapableIfNecessary(candidateAdvisors); }
public static boolean makeAdvisorChainAspectJCapableIfNecessary(List<Advisor> advisors) { // Don't add advisors to an empty list; may indicate that proxying is just not required if (!advisors.isEmpty()) { boolean foundAspectJAdvice = false; for (Advisor advisor : advisors) { // Be careful not to get the Advice without a guard, as this might eagerly // instantiate a non-singleton AspectJ aspect... //判断是否是通知类,并将其属性打上标签 if (isAspectJAdvice(advisor)) { foundAspectJAdvice = true; break; } } //这里会往advisors缓存中添加ExposeInvocationInterceptor对象,该对象为后续代理类调用过程中的拦截链做准备 if (foundAspectJAdvice && !advisors.contains(ExposeInvocationInterceptor.ADVISOR)) { advisors.add(0, ExposeInvocationInterceptor.ADVISOR); return true; } } return false; }
方法7:createProxy
protected Object createProxy(Class<?> beanClass, @Nullable String beanName, @Nullable Object[] specificInterceptors, TargetSource targetSource) { // 给bean定义设置暴露属性 if (this.beanFactory instanceof ConfigurableListableBeanFactory) { AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass); } // 创建代理工厂 ProxyFactory proxyFactory = new ProxyFactory(); // 获取当前类中相关属性 proxyFactory.copyFrom(this); // 决定对于给定的bean是否应该使用targetClass而不是他的接口代理,检查proxyTargetClass设置以及preserverTargetClass属性 if (!proxyFactory.isProxyTargetClass()) { // 判断是 使用jdk动态代理 还是cglib代理 //如果被代理类有preserveTargetClass,则设置ProxyTargetClass为true,尝试使用Cglib进行代理 if (shouldProxyTargetClass(beanClass, beanName)) { proxyFactory.setProxyTargetClass(true); } else { // 判断是否有实现接口,如果没有实现接口则设置setProxyTargetClass为true,尝试使用Cglib进行代理 evaluateProxyInterfaces(beanClass, proxyFactory); } } // 将被代理类名称及其适配的通知对象构建通知类 Advisor[] advisors = buildAdvisors(beanName, specificInterceptors); proxyFactory.addAdvisors(advisors); // 设置到要代理的类 proxyFactory.setTargetSource(targetSource); //空方法,用于子类拓展实现 customizeProxyFactory(proxyFactory); // 控制代理工程被配置之后,是否还允许修改通知,默认值是false proxyFactory.setFrozen(this.freezeProxy); if (advisorsPreFiltered()) { proxyFactory.setPreFiltered(true); } // 真正创建代理对象 return proxyFactory.getProxy(getProxyClassLoader()); }
proxyFactory.getProxy(getProxyClassLoader()),见方法8详解
方法8:getProxy
public Object getProxy(@Nullable ClassLoader classLoader) { // createAopProxy() 用来创建我们的代理工厂 return createAopProxy().getProxy(classLoader); }
protected final synchronized AopProxy createAopProxy() { if (!this.active) { // 监听调用AdvisedSupportListener实现类的activated方法 activate(); } // 通过AopProxyFactory获得AopProxy,这个AopProxyFactory是在初始化函数中定义的,使用的是DefaultAopProxyFactory return getAopProxyFactory().createAopProxy(this); }
getAopProxyFactory().createAopProxy(this),见方法9详解
方法9:createAopProxy
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException { // 这段代码用来判断选择哪种创建代理对象的方式 // config.isOptimize() 是否对代理类的生成使用策略优化 其作用是和isProxyTargetClass是一样的 默认为false // config.isProxyTargetClass() 是否使用Cglib的方式创建代理对象 默认为false // hasNoUserSuppliedProxyInterfaces目标类是否有接口存在 且只有一个接口的时候接口类型是SpringProxy类型 if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) { // 上面的三个方法有一个为true的话,则进入到这里 // 从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."); } // 判断目标类是否是接口 如果目标类是接口的话,则还是使用JDK的方式生成代理对象 // 如果目标类是Proxy的子类或其实现类时,使用JDK动态代理 if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) { return new JdkDynamicAopProxy(config); } // 配置了使用Cglib进行动态代理或者目标类没有接口,那么使用Cglib的方式创建代理对象 return new ObjenesisCglibAopProxy(config); } else { // 使用JDK的提供的代理方式生成代理对象 return new JdkDynamicAopProxy(config); } }
JDK动态代理根Cglib动态代理在前面的文章中我们讲解过其源码实现过程,可以看这两篇文章进行学习,过程跟Spring AOP过程差不多。
总结
1.当切面类指定了proxy-target-class="true"属性时,代表要使用Cglib(proxyTargetClass属性会为true),此时有机会是Cglib代理。
2.条件1不满足时,看被代理类是否有preserverTargetClass属性,且值为true时,会将proxyTargetClass属性设置为true,此时有机会是Cglib代理。
3.optimize为true时,此时有机会是Cglib代理。
4.被代理类只有一个接口,并且该接口是SpringProxy类型,此时有机会是Cglib代理。
5.被代理类没有实现接口,此时会将proxyTargetClass属性设置为true,此时有机会是Cglib代理。
以上5个条件满足其中1个,且被代理类不是接口或不是Proxy的子类或者实现类时使用Cglib代理。
因此,我们可以得出结论:
被代理类没有接口时不一定使用Cglib进行代理,因为可能被代理类是一个接口或者是Proxy的子类或者实现类
被代理类有接口时不一定使用JDK进行代理:
有可能切面类指定了proxyTargetClass为true
有可能被代理类的只有一个接口且是SpringProxy类型
有可能代理工厂的optimize属性为true