当前位置: 代码迷 >> 综合 >> springboot9--->spring-boot自动配置springAOP原理分析
  详细解决方案

springboot9--->spring-boot自动配置springAOP原理分析

热度:38   发布时间:2023-10-24 15:07:58.0

1、在spring专栏里面我仔细的分析了在spring中是如何使用SpringAOP的,以及SpringAOP的核心原理,那么我们来会回忆一下,在spring中是如何使用SpringAOP的:

      方式1:基于code,使用ProxyFactory或者AspectJProxyFactory

                   Ⅰ、ProxyFactory

public static void main(String[] args) {UserService userService = new UserServiceImpl();BeforeAdvice beforeAdvice = new UserServiceRegistryBeforeAdvice();AfterReturningAdvice afterReturningAdvice = new UserviceRegistryAfetrReturnAdvice();ProxyFactory proxyFactory = new ProxyFactory();/*可添加多个增强,形成增强链,调用顺序跟添加顺序一致,也可以使用proxyFactory.addAdvice(1, beforeAdvice);来指定位置。*/proxyFactory.addAdvice(1, beforeAdvice);proxyFactory.addAdvice(beforeAdvice);proxyFactory.addAdvice(afterReturningAdvice);proxyFactory.setTarget(userService);/*设置接口类型的话,将会默认使用jdk的动态代理JdkDynamicAopProxy来创建代理对象。否在会使用CGLIB动态代理ObjenesisCglibAopProxy来创建代理类,虽然是使用ObjenesisCglibAopProxy来创建代理类,但是核心还是 其父类CglibAopProxy来控制,只是使用ObjenesisCglibAopProxy提供的Objenesis创建对象的技术来创建代理类而已。!!!!!!!!!*/proxyFactory.setInterfaces(userService.getClass().getInterfaces());/*除此之外可以使用proxyFactory.setOptimize(true)来启动优化代理方式,设置为true的话如果代理的Target有接口,也会使用CGLIB来创建代理类。*/proxyFactory.setOptimize(true);UserService userServiceProxy = (UserService) proxyFactory.getProxy();userServiceProxy.registryUser("张三");}

                    Ⅱ:AspectJProxyFactory

           定义目标类public class AspectJTarget {public void test(){System.out.println("AspectJTarget...");}}定义切面类@Aspectpublic class AspectJTestBean {@Before(value = "execution(* com.wzy.springstudy.aop.AspectJ.c.*.test())")public void before(){System.out.println("before");}测试代码public static void main(String[] args) {AspectJProxyFactory aspectJProxyFactory = new AspectJProxyFactory();设置目标类aspectJProxyFactory.setTarget(new AspectJTarget());添加Aspect实例 注意此实例的类一定需要使用@Aspect注解标注aspectJProxyFactory.addAspect(new AspectJTestBean());使用AspectJProxyFactory 来构建代理实例AspectJTarget proxy = aspectJProxyFactory.getProxy();使用代理类调用业务方法proxy.test();}}

      方式2:基于xml配置,使用ProxyFactoryBean 

<!--ProxyFactoryBean 使用之前置增强 beforeAdvice--><!--1、定义目标bean--><bean id="target" class="com.wzy.springstudy.aop.advice.impl.UserServiceImpl"/><!--2、定义增强bean--><bean id="berforeAdvice" class="com.wzy.springstudy.aop.advice.UserServiceRegistryBeforeAdvice"/><!--3、定义所需生成的代理类 使用实现了FactoryBean接口的ProxyFactoryBean--><bean id="userService" class="org.springframework.aop.framework.ProxyFactoryBean"><!--指定目标类--><property name="target" ref="target"/><!--指定生成的代理类需要实现那些接口。--><property name="proxyInterfaces" value="com.wzy.springstudy.aop.advice.UserService"/><!--指定需要植入连接点的增强多个增强名称使用“,”号隔开。--><property name="interceptorNames" value="berforeAdvice"/><!--是否启用代理优化设置为true将会强制使用CGLIB动态代理,CGLIB创建代理类比较慢,但是创建的代理对象运行的效率较高,跟jdk动态代理刚好相反,如果代理类是代理的,尽量使用CGLIB来生成代理类--><property name="optimize" value="true"/><!--是否对类进行代理,如果设置为true将会使用CGLIB生成代理类。--><property name="proxyTargetClass" value="true"/><!--生成的代理类是否为单例,默认为true--><property name="singleton" value="true"/><!--是否暴露生成的代理对象,默认为false,设置为true 可以在目标类的被增强的连接点(方法)中使用AopContext.currentProxy()来获取当前生成的代理实例。--><property name="exposeProxy" value="true"/></bean>

      方式3:自动代理构建器,BeanNameAutoProxyCreator 或 DefaultAdvisorAutoProxyCreator 或AnnotationAwareAspectJAutoProxyCreator

               Ⅰ:BeanNameAutoProxyCreator

         <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>

               Ⅱ:DefaultAdvisorAutoProxyCreator

          <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"/>

             Ⅲ:AnnotationAwareAspectJAutoProxyCreator使用这个代理自动构建既能提供DefaultAdvisorAutoProxyCreator的功能也能提供对aspectj注解的方式来时使用SpringAOP

                  定义@Aspect切面定义:

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

                  使用xml配置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"/>

              Ⅳ:使用 <aop:aspectj-autoproxy proxy-target-class="true" expose-proxy="true"/>

                      使用 <aop:aspectj-autoproxy proxy-target-class="true" expose-proxy="true"/>来简化AnnotationAwareAspectJAutoProxyCreator配置。

 

      方式4:使用注解驱动

                在spring3.1的时候提供了注解@EnableAspectJAutoProxy来激活SpringAop的的自动代理,其实这个注解的作用就是想springIOC容器中注册一个AnnotationAwareAspectJAutoProxyCreator实例到容器中,作用就等价于xml中配置<aop:aspectj-autoproxy proxy-target-class="true" expose-proxy="true"/>这个标签。

 

2、在spring boot中是如何自动配置SpringAOP的呢?????

      老规矩我们还是来到spring-boot-autoconfigure包下面的spring.factories SPI文件中,查找SringAOP的自动配置类,经过查找我们找到了如下的SpringAOP配置类:

    org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\

          我们进入AopAutoConfiguration的源码中:

@Configuration(proxyBeanMethods = false)配置类条件注解,如果配置了spring.aop.auto=fasle将不会激活当前SpringAOP的自动配置,否则都会激活。
@ConditionalOnProperty(prefix = "spring.aop", name = "auto", havingValue = "true", matchIfMissing = true)
public class AopAutoConfiguration {如果AopAutoConfiguration 这个配置类被激活了,那么如果当前类路径下存在
org.aspectj.weaver.Advice这个类就会激活当前的内部配置类AspectJAutoProxyingConfiguration,而
这个静态的内部配置类里面又有一个静态内部配置类JdkDynamicAutoProxyConfiguration,这个配置类上面
既然标注了@EnableAspectJAutoProxy 这个注解,这样就清楚了,spring boot自动配置SpringAOP的方式
也就是在使用SpringAOP的注解驱动而已。@Configuration(proxyBeanMethods = false)@ConditionalOnClass(Advice.class)static class AspectJAutoProxyingConfiguration {@Configuration(proxyBeanMethods = false)@EnableAspectJAutoProxy(proxyTargetClass = false)@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false",matchIfMissing = false)static class JdkDynamicAutoProxyConfiguration {}@Configuration(proxyBeanMethods = false)@EnableAspectJAutoProxy(proxyTargetClass = true)@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true",matchIfMissing = true)static class CglibAutoProxyConfiguration {}}@Configuration(proxyBeanMethods = false)@ConditionalOnMissingClass("org.aspectj.weaver.Advice")@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true",matchIfMissing = true)static class ClassProxyingConfiguration {ClassProxyingConfiguration(BeanFactory beanFactory) {if (beanFactory instanceof BeanDefinitionRegistry) {BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);}}}}

      源码中显示,当我们的类路径下有org.aspectj.weaver.Advice这个类就能激活AopAutoConfiguration配置类,然后就能开启SpringAOP的注解驱动@EnableAspectJAutoProxy(proxyTargetClass = false) || @EnableAspectJAutoProxy(proxyTargetClass = true),那么我们应该怎样映入org.aspectj.weaver.Advice这个类呢????????

      当然我们直接添加如下依赖是可以的:但是前提是我们必须依赖spring-aop这个包

        <dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.9.6</version><scope>compile</scope></dependency>

       除了需要依赖aspectjweaver这个包外,还需要依赖spring-aop这个包,因此为了简化引入,spring boot为我们提供了spring-boot-starter-aop这个启动组件,来激活SpringAOP自动配置,如下:

       <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId></dependency>

   我们查看spring-boot-starter-aop这个项目的pom.xml文件如下:

 <dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId><version>2.3.3.RELEASE</version><scope>compile</scope></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-aop</artifactId><version>5.2.8.RELEASE</version><scope>compile</scope></dependency><dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.9.6</version><scope>compile</scope></dependency></dependencies>

 

3、以上就是spring boot中自动配置SpringAOP的原理分析。

 

 

  相关解决方案