欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

spring基本使用(13)-springAOP的使用以及原理3 springAOP的自动代理创建器AbstractAutoProxyCreator

程序员文章站 2022-03-26 14:38:01
1、在前面一篇文章中我们讲了ProxyFactory、ProxyFacoryBean、AspectJProxyFactory三种用于创建代理类以及代理实例的非自动代理创建器,在Spring中其实也为我们提供了自动创建代理器。自动代理创建器的作用就是,自动解析到SpringIOC容器中的切面,根据切面的定义找到所有的Target目标类,在SpringIOC容器装载阶段为其织入切面定义中的增强。2、非自动代理构建器 与 自动代理构建器的区别 非自动代理构建器使用繁琐,组要我们配置(目标类......

1、在前面一篇文章中我们讲了ProxyFactory、ProxyFacoryBean、AspectJProxyFactory三种用于创建代理类以及代理实例的非自动代理创建器,在Spring中其实也为我们提供了自动创建代理器。自动代理创建器的作用就是,自动解析到SpringIOC容器中的切面,根据切面的定义找到所有的Target目标类,在SpringIOC容器装载阶段为其织入切面定义中的增强。

 

2、非自动代理构建器 与 自动代理构建器的区别

      非自动代理构建器使用繁琐,组要我们配置(目标类+配置增强)或者配置切面,在小型的项目中这样做倒是可以接受,但是大型项目中,如果需要配置的很多这种方式就比较鸡肋。而自动代理构建器我们只需要配置一个代理构建器就好,这个代理构建器就会解析SpringIOC容器中的所有切面定义,根据切面的定义找到所有的Target目标类,在SpringIOC容器装载阶段为其织入切面定义中的增强。

 

3、Spring中的自动代理创建器AbstractAutoProxyCreator 类图:

         spring基本使用(13)-springAOP的使用以及原理3 springAOP的自动代理创建器AbstractAutoProxyCreator

        主要的实现有:

            1、BeanNameAutoProxyCreator : 作用就是需要我们指定切面以及beanNames来生成代理类,跟非自动的比较类似,使用案例入下:这种方式相对于非自动代理构建器的却别就是目标类可以配置多个。

         <bean id="dog" class="com.wzy.springstudy.aop.AutoProxyCreator.Dog"/>
         <bean id="cat" class="com.wzy.springstudy.aop.AutoProxyCreator.Cat"/>
         <bean id="sayHelloBeforeAdvice" 
               class="com.wzy.springstudy.aop.AutoProxyCreator.SayHelloBeforeAdvice"/>
         <!--切面我们就定位目标类的run方法。-->
         <bean id="sayHelloAdvisor" 
              class="com.wzy.springstudy.aop.AutoProxyCreator.SayHelloAdvisor"
              p:advice-ref="sayHelloBeforeAdvice"/>
         <!--配置BeanNameAutoProxyCreator 自动创建代理器-->
         <bean id="beanNameAutoProxyCreator" 
             class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
            <property name="interceptorNames" value="sayHelloAdvisor"/>
            <property name="proxyTargetClass" value="true"/>
            <!--指定bean name-->
            <property name="beanNames" value="cat,dog"/>
            <property name="optimize" value="true"/>
         </bean>

                      测试代码:

          @Test
          public void testBeanNameAutoProxyCreator(){
             ApplicationContext ctx = new ClassPathXmlApplicationContext("spring-context-aopAutoCreator.xml");
             com.wzy.springstudy.aop.AutoProxyCreator.Cat cat = (Cat) ctx.getBean("cat");
             cat.run();
          }


          输出:
            哈喽。。。          输出此句表示增强织入成功
            猫在跑。。。

 

           2、DefaultAdvisorAutoProxyCreator : 默认的切面自动代理构造器,作用就是查找容器中所有类型为Advisor的切面,解析切面的目标类+增强然后进行代理生成。

          <bean id="dog2" class="com.wzy.springstudy.aop.AutoProxyCreator.Dog"/>
          <bean id="cat2" class="com.wzy.springstudy.aop.AutoProxyCreator.Cat"/>
          <bean id="sayHelloDefaultAdvisorAutoProxyAdvice"
             class="com.wzy.springstudy.aop.AutoProxyCreator.SayHelloBeforeAdvice"/>

          <bean id="sayHahahaDefaultAdvisorAutoProxyAdvice"
             class="com.wzy.springstudy.aop.AutoProxyCreator.SayHahahaBeforeAdvice"/>

          <bean id="regexpMethodPointcutAdvisor" 
             class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
            <property name="advice" ref="sayHelloDefaultAdvisorAutoProxyAdvice"/>
            <!--RegexpMethodPointcutAdvisor 的ClassFilter 为TrueClassFilter.INSTANCE 默认匹配所有的类 此处配置patterns=.*run.* , 就表示为所有bena的以run结尾的方法进行增强。-->
            <property name="patterns" value=".*run.*"/>
          </bean>
          <bean id="staticNamePointcutAdvisor" 
              class="com.wzy.springstudy.aop.AutoProxyCreator.SayHahahaAdvisor">
            <property name="advice" ref="sayHahahaDefaultAdvisorAutoProxyAdvice"/>
          </bean>
          <!--会容器中所有的Advisor织入到匹配的连接点中-->
          <bean id="defaultAdvisorAutoProxyCreator"
      class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>

                      测试代码:

           @Test
            public void testDefaultAdvisorAutoProxyCreator(){
               ApplicationContext ctx = new ClassPathXmlApplicationContext("spring-context-aopAutoCreator.xml");
               com.wzy.springstudy.aop.AutoProxyCreator.Dog dog = (Dog) ctx.getBean("dog2");
               dog.run();
            } 
 
            输出:
                哈喽。。。          织入成功
                Hahaha...          织入成功
                狗在跑。。。

          

             3、AnnotationAwareAspectJAutoProxyCreator(重要指数5颗星) : AspectJ注解代理自动构建器,作用有两个:

                    1、完成查找容器中所有类型为Advisor的切面,解析切面的目标类+增强然后进行代理生成。没毛病AnnotationAwareAspectJAutoProxyCreator也能完成DefaultAdvisorAutoProxyCreator干的事情。

                    2、解析AspectJ定义的切面,然后根据切面定义将增强织入目标类中。

              AnnotationAwareAspectJAutoProxyCreator是SpringAOP对AspectJ语法做支持的产物,下面介绍使用案例:

              @Aspect切面定义:

        @Component
        @Aspect
        public class AspectJTestBean {
            @Before(value = "execution(* com.wzy.springstudy.aop.AutoProxyCreator.*.*())")
            public void before(){
               System.out.println("before");
            }
        } 

               我们还是使用之前定义的一些切面,只是将代理自动构造器修改为AnnotationAwareAspectJAutoProxyCreator

           <bean id="dog2" class="com.wzy.springstudy.aop.AutoProxyCreator.Dog"/>
           <bean id="cat2" class="com.wzy.springstudy.aop.AutoProxyCreator.Cat"/>
           <bean id="sayHelloDefaultAdvisorAutoProxyAdvice"
               class="com.wzy.springstudy.aop.AutoProxyCreator.SayHelloBeforeAdvice"/>

           <bean id="sayHahahaDefaultAdvisorAutoProxyAdvice"
               class="com.wzy.springstudy.aop.AutoProxyCreator.SayHahahaBeforeAdvice"/>

           <bean id="regexpMethodPointcutAdvisor" 
                  class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
              <property name="advice" ref="sayHelloDefaultAdvisorAutoProxyAdvice"/>
              <!--RegexpMethodPointcutAdvisor 的ClassFilter 为TrueClassFilter.INSTANCE 默认匹配所有的类此处配置patterns=.*run.* , 就表示为所有bena的以run结尾的方法进行增强。-->
              <property name="patterns" value=".*run.*"/>
          </bean>
          <bean id="staticNamePointcutAdvisor" 
               class="com.wzy.springstudy.aop.AutoProxyCreator.SayHahahaAdvisor">
             <property name="advice" ref="sayHahahaDefaultAdvisorAutoProxyAdvice"/>
          </bean>
          <!--会容器中所有的Advisor+Aspect语法定义的切面织入到匹配的连接点中-->
           <bean id="annotationAwareAspectJAutoProxyCreator"          
 class="org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator" 
 p:exposeProxy="true"/>

                      测试代码:

          @Test
          public void testDefaultAdvisorAutoProxyCreator(){
              ApplicationContext ctx = new ClassPathXmlApplicationContext("spring-context-aopAutoCreator.xml");
              com.wzy.springstudy.aop.AutoProxyCreator.Dog dog = (Dog) ctx.getBean("dog2");
              dog.run();
          }


          输出:
              哈喽。。。
              Hahaha...
              before                AspectJ定义的切面也织入成功
              狗在跑。。。

              使用 <aop:aspectj-autoproxy proxy-target-class="true" expose-proxy="true"/>来简化AnnotationAwareAspectJAutoProxyCreator配置。我们可以使用<aop:aspectj-autoproxy proxy-target-class="true" expose-proxy="true"/>来指定配置一个AnnotationAwareAspectJAutoProxyCreator实例。

 

4、AbstractAutoProxyCreator的实现原理分析:

      从AbstractAutoProxyCreator的类图我们可以看出来AbstractAutoProxyCreator实现了InstantiationAwareBeanPostProcessor以及BeanPostProcessor接口,这个接口在Spring的bean生命周期中是非常重要的这个接口的方法列表如下:

      4.1、InstantiationAwareBeanPostProcessor接口方法列表:

           Ⅰ:Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException; 此方法在SpringIOC装载阶段执行,执行时机是bean实例化之前,也就是说在装载某个bean的时候,实例化bean之前会调用此方法,如果在此方法中生成代理并返回,那么容器中的bean对应的实例就是当前的代理实例。

           Ⅱ:boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException; 此方法是在装载bean的时候执行,执行时机是bean实例化之后,返回的boolean类型,此时bean的实例已经实例化好了,我们可以在此处给bean进行装饰。

           Ⅲ:PropertyValues postProcessPropertyValues( PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException; 在给bean的属性进行赋值之前执行,我们可以在此处给bean的属性进行修改。

      

      4.2、BeanPostProcessor接口方法列表:

            Ⅰ:Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;此方法是在装载bean的阶段执行,执行时机是bean初始化之前执行,我们可以在此处进行bean的装饰或替换。比如根据原来的bean作为target来生成代理实例。

            Ⅱ:Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;此方法也是在装载bean的阶段执行,执行时机是bean初始化之后执行,我们也可以在此处对bean实例进行装饰或替换。比如根据原来的bean作为target来生成代理实例。

      4.3、那么我们的AbstractAutoProxyCreator是在那个方法里面进行代理类生成呢????

              我们知道AOP的两个核心条件就是目标类target+连接点的方位信息(切点)以及需要织入的代码(Advice)。

              我们代理肯定需要目标实例,这个是肯定的,但是SpringAOP提供了两个地方来进行代理实例生成,那就是InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation 没看错,就是实例化之前,问题来了此时bean还没有实例化,怎么能够生成代理呢,查看其源码我们能够发现,原来SpronAOP允许我们给IOC容器中的bean配置一个TargetSource,如果配置了这个TargetSource,那么就会使用这个TargetSource来作为代理的目标类来进行代理生成。

    @Override
	public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
		Object cacheKey = getCacheKey(beanClass, beanName);

		if (beanName == null || !this.targetSourcedBeans.contains(beanName)) {
			if (this.advisedBeans.containsKey(cacheKey)) {
				return null;
			}
			if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
				this.advisedBeans.put(cacheKey, Boolean.FALSE);
				return null;
			}
		}

		// Create proxy here if we have a custom TargetSource.
		// Suppresses unnecessary default instantiation of the target bean:
		// The TargetSource will handle target instances in a custom fashion.
		if (beanName != null) {
                        如果给当前的bean配置了TargetSource实例,就使用当前的TargetSource作为代理目标类来进行代理生成。
			TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
			if (targetSource != null) {
				this.targetSourcedBeans.add(beanName);
                                获取到代理的拦截就是获取其切面。
				Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);  
                                生成代理实例
				Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
				this.proxyTypes.put(cacheKey, proxy.getClass());
				return proxy;
			}
		}

		return null;
	}

                   上面的配置了TargetSource这种的方式不是很实用,因此SpringAOP还在BeanPostProcessor.postProcessAfterInitialization bean初始化之后来进行代理生成,这种方式才是最实用的,我们查看其源码:

	@Override
	public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		if (bean != null) {
			Object cacheKey = getCacheKey(bean.getClass(), beanName);
			if (!this.earlyProxyReferences.contains(cacheKey)) {
                                包装bean
				return wrapIfNecessary(bean, beanName, cacheKey);
			}
		}
		return bean;
	}


    包装bean的方法
    protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
		if (beanName != null && this.targetSourcedBeans.contains(beanName)) {
			return 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;
		}

		// Create proxy if we have advice.
                找到切面从而得到增强,此处是一个抽象方法,其实现在之前列举的代理自动构建器中都有实现。
		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;
	}

                  AbstractAdvisorAutoProxyCreator抽象的切面代理自动构建器实现的getAdvicesAndAdvisorsForBean

	@Override
	protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, 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) {
                获取SpringIOC容器中类型为Advisor的实例(会实例化+初始化所有的Advisor实例),
                  注意在AspectJAwareAdvisorAutoProxyCreator代理自动构建器中复写了 
                  findCandidateAdvisors方法,复写的逻辑是先调用父类的此方法实现,然后在解析AspectJ的切面定义,将两者的合集作为最终的切面列表。
		List<Advisor> candidateAdvisors = findCandidateAdvisors();
        
                找出当前bean符合的切面,也就是使用切面的切点进行ClassFilter跟MethodMatcher来进行匹配,如果匹配成功,说明见当前bean需要织入当前切面的增强逻辑。
		List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);

                扩展满足条件的切面,在AspectJAwareAdvisorAutoProxyCreator中有实现,其他暂无
		extendAdvisors(eligibleAdvisors);
		if (!eligibleAdvisors.isEmpty()) {
                        对切面进行排序(Ordered可定义切面顺序,此顺序就是切面的增强的执行顺序)
			eligibleAdvisors = sortAdvisors(eligibleAdvisors);
		}
		return eligibleAdvisors;
	}

 

本文地址:https://blog.csdn.net/qq_34978129/article/details/107313274

相关标签: spring spring