当前位置: 移动技术网 > IT编程>开发语言>Java > spring基本使用(13)-springAOP的使用以及原理3 springAOP的自动代理创建器AbstractAutoProxyCreator

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

2020年07月17日  | 移动技术网IT编程  | 我要评论
1、在前面一篇文章中我们讲了ProxyFactory、ProxyFacoryBean、AspectJProxyFactory三种用于创建代理类以及代理实例的非自动代理创建器,在Spring中其实也为我们提供了自动创建代理器。自动代理创建器的作用就是,自动解析到SpringIOC容器中的切面,根据切面的定义找到所有的Target目标类,在SpringIOC容器装载阶段为其织入切面定义中的增强。2、非自动代理构建器 与 自动代理构建器的区别 非自动代理构建器使用繁琐,组要我们配置(目标类...

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

 

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

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

 

3、Spring中的自动代理创建器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

如您对本文有疑问或者有任何想说的,请点击进行留言回复,万千网友为您解惑!

相关文章:

验证码:
移动技术网