Spring注解(AOP)

底层动态代理

  程序运行期间动态的将某段代码切入到指定方法指定位置进行运行的编程方式

 

导入aop的相关模块

<!-- https://mvnrepository.com/artifact/org.springframework/spring-aspects -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aspects</artifactId>
    <version>5.1.6.RELEASE</version>
</dependency>

 

动态感知业务类运行的状态

    通知: 前置 @Before  后置 @After  环绕 @Around 异常@AfterThrowing  返回 @AfterReturning

    补充环绕通知: 动态代理,手动推进目标方法运行(joinPoint.proceed() )

 

步骤:

编写切面类

在切面类里面  把每个方法 何时何地切入都指定好

将切面类和业务逻辑类 都添加到容器中

告诉容器 哪个是切面类@Aspect

 

在 xml中  <aop: aspectj-autoproxy> </aop:aspectj-autoproxy>    开启基于注解版的切面功能

注解中: 在当前的配置类加入  @EnableAspectJAutoProxy 启用基于注解的aop模式

 

正常代码:

 

@Component
public class Mathcalculator {
     public int div(int i , int j) {
         System.out.println("Mathcalculator--div被调用");
         return i/j;
     }
}

 

切面类:

 

@EnableAspectJAutoProxy
@Configuration
public class AOPConfig {
   @Bean  //业务逻辑类注册到容器
    public Mathcalculator mathcalculator() {
        return new Mathcalculator();
    }
   
   @Bean  // 切面类注册到容器中
   public LogAspects logAspects() {
       return new LogAspects();
   }
}

 

测试:

 

public class test {
    @Test 
    public void test01(){  
        //使用无参构造器  创建applicationContext  (详情自己研究下有参构造器的方法)
        AnnotationConfigApplicationContext applicationContext=
                new AnnotationConfigApplicationContext(AOPConfig.class);
        Mathcalculator bean = applicationContext.getBean(Mathcalculator.class);
        bean.div(1, 1);
       //设置需要激活的环境
        applicationContext.getEnvironment().setActiveProfiles("dev","test"); //可以设置多个
       //注册主配置类
        applicationContext.register(Profile.class);    
       //启动刷新容器
       applicationContext.refresh();
      }  
} 

结果:

 

升级:

切面类

@Aspect
public class LogAspects {
  //抽取公共的切入点表达式  本类的  如果是别的类的 写全名就OK了
    
    @Pointcut("execution(public int com.toov5.config.Mathcalculator .*(..))" )
    public void pointCut() {
        
    }
// @Before("public int com.toov5.config.Mathcalculator.div(int , int)")
   @Before( "pointCut()" )
    public void logStart(JoinPoint joinpoint) {  //获取签名 获取方法
      Object[] args = joinpoint.getArgs(); //目标方法 运行时候需要的参数表
        System.out.println("除法运行@Before"+joinpoint.getSignature().getName()+"运行时参数表"+args );
    }
    @After( "pointCut()" ) //运行异常与否 都要执行的
    public void logEnd(JoinPoint joinPoint) {
        System.out.println(joinPoint.getSignature().getName()+"除法结束@After");
    }
    @AfterReturning(value="pointCut()", returning="result")
    public void logReturn(JoinPoint joinpoint,Object result ) { //result 接受返回值
        System.out.println(joinpoint.getSignature().getName()+"除法正常运行@AfterReturning,结果:"+result);
    } 
    @AfterThrowing(value = "pointCut()", throwing="e")
    public void logException(JoinPoint joinpoint, Exception e) {
        System.out.println( joinpoint.getSignature().getName()+"除法异常@AfterThrowing"+e.getMessage());
    }
}

配置:

@EnableAspectJAutoProxy
@Configuration
public class AOPConfig {
   @Bean  //业务逻辑类注册到容器
    public Mathcalculator mathcalculator() {
        return new Mathcalculator();
    }
   
   @Bean  // 切面类注册到容器中
   public LogAspects logAspects() {
       return new LogAspects();
   }
}

 

测试类:

 

public class test {
    @Test 
    public void test01(){  
        //使用无参构造器  创建applicationContext  (详情自己研究下有参构造器的方法)
        AnnotationConfigApplicationContext applicationContext=
                new AnnotationConfigApplicationContext(AOPConfig.class);
        Mathcalculator bean = applicationContext.getBean(Mathcalculator.class);
        bean.div(1, 1);
       //设置需要激活的环境
        applicationContext.getEnvironment().setActiveProfiles("dev","test"); //可以设置多个
       //注册主配置类
        applicationContext.register(Profile.class);    
       //启动刷新容器
       applicationContext.refresh();
      }  
} 

结果:

 

JointPoint 要写一定要写在 参数的首位! 

 

 三步走:

   1  将业务逻辑组件和切面类都加入到容器,告诉Spring哪个是切面类(@Aspect)

   2 在切面类上的每一个通知方法上标注 通知注解,告诉Spring合适何地运行(切入点表达式)

   3 开启基于注解的aop模式 与config上 

 

总结:

 

 

 

aop的原理


 

 加入@EnableAspectJAutoProxy  才有AOP

 

继续点开看

利用AspectJAutoProxyRegistrar  给自定义容器中注册bean

  给容器注册一个AnnotationAwareAspectJAutoProxyCreator   自动代理创建器

   可以一直追踪其父类:

      

 实现了 SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware  

                                   后置处理器                                        

 

关注后置处理器的工作  Bean初始化完成前后做的事情

 BeanFactory                自动注入 

 AbstractAutoProxyCreator :

@Override
public void setBeanFactory(BeanFactory beanFactory) {
this.beanFactory = beanFactory;
}

 

 然后是与后置处理器有关的: 

@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName)

 有后置处理器的逻辑

 

 AbstractAutoProxyCreator   类

AnnotationAwareAspectJAutoProxyCreator 类  initBeanFactory

 

启动后

1、  传入主配置类  创建 IOC容器

2、  注册配置类 调用refresh() 刷新容器

3、 registerBeanPostProcessors(beanFactory)  注册bean的后置处理器 方便拦截bean的创建

       1先获取ioc容器中已经定义了需要创建对象的所有BeanPostProcessor

       2给容器加别的BeanPostProcessor

       3优先注册实现了PriorityOrdered接口的BeanPostProcessor

       4在给容器中注册实现了Ordered接口的BeanPostProcessor

       5注册没实现优先级接口的BeanPostProcessor

             创建internalAutoProxyCreator的BeanPostProcessor

                   创建Bean的实例

                   populateBean 初始化Bean

                           1、 invokeAwareMethods() 处理Aware接口的方法回调

                           2、 applyBeanPostProcessorsBeforeInitialization() 应有后置处理器的BeforeInitialization( ) 

                           3、invokeInitMethods() 自定义的初始化方法

                           4、applyBeanPostProcessorsAfterInitialization ()  执行后置处理器的 postProcessAfterInitialization

4、BeanPostProcessor(AnnotationAwareAspectJAutoProxyCreator)创建成功; aspectJAdvisorBuilder

   6 把beanPostProcessor注册到BeanFactory中 调用addBeanPostProcessor(postProcessor)

 

posted @ 2019-04-07 21:33  toov5  阅读(292)  评论(0编辑  收藏  举报