美文网首页
AOP猛快糙入门

AOP猛快糙入门

作者: packet | 来源:发表于2019-03-06 20:05 被阅读0次

    学习AOP已经很多年了,但是想起来总有点模糊,现在做下梳理,用最简单直接的方式做个总结。
    一定要动手!!!!!!!!!!!!!!!
    使用SpringBoot项目,首先添加maven依赖

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

    先认识有几个核心概念:
    AOP:Aspect Oriented Programming,面向切面编程。
    连接点(Joinpoint):被切入的方法。
    增强(Advice):一共有5种

    • @Before:前置增强,就是在目标方法执行之前执行;
    • @AfterReturning:后置增强,方法退出时执行;
    • @AfterThrowing:有异常时该方法执行;
    • @After:最终增强,无论什么情况都会执行;
    • @Afround:环绕增强

    切点(Pointcut):标记被切入的方法,连接了连接点和增强。

    @Component
    @Aspect
    public class WorkAspect {
    
       // 第一种方式:直接使用切点表达式
       @Before("execution(* com.example.aop.Worker.work())")
       @Order(1)
       public void before1(JoinPoint joinPoint) {
           System.out.println("before1: " + joinPoint.getSignature());
       }
    
       // 第二种方式: 切点(表达式)
       @Pointcut("execution(* com.example.aop.Worker.work())")
       public void point() {
       }
    
       @Before("point()")
       @Order(2)
       public void before2(JoinPoint joinPoint) {
           System.out.println("before2: " + joinPoint.getSignature());
       }
    
       // 第三种方式: 切点(注解)
       @Pointcut("@annotation(com.example.aop.Cache)")
       public void point2() {
    
       }
    
       @Order(3)
       @Before("point2()")
       public void before3(JoinPoint joinPoint) {
           System.out.println("before3: " + joinPoint.getSignature());
       }
    }
    
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.METHOD)
    @Documented
    public @interface Cache {
    }
    
    
    @Component
    public class Worker {
    
       @Cache
       public void work() {
           System.out.println("cnt: " + (++cnt));
       }
    
       private int cnt;
    
       public int getCnt() {
           return cnt;
       }
    
       public void setCnt(int cnt) {
           this.cnt = cnt;
       }
    
       @Override
       public String toString() {
           return "Work{" +
                   "cnt=" + cnt +
                   '}';
       }
    }
    
    

    再看下测试代码:

    @ComponentScan("com.example.aop")
    @Configuration
    @EnableAspectJAutoProxy
    public class Config {
    }
    
    public class AopMain {
        public static void main(String[] args) {
            AnnotationConfigApplicationContext applicationContex =
                    new AnnotationConfigApplicationContext(Config.class);
            Worker worker = applicationContex.getBean(Worker.class);
            worker.work();
        }
    }
    

    测试结果:
    before1: void com.example.aop.Worker.work()
    before2: void com.example.aop.Worker.work()
    before3: void com.example.aop.Worker.work()
    cnt: 1

    2019-03-13深入:
    代理类是一个空壳(或外观),它背后才是真正的类,通常称为目标类。由此得出代理类要包含目标类。

    当进入目标对象的方法后,执行的上下文已经变成目标对象本身了,因为目标对象的代码是我们自己写的,和事务没有半毛钱关系,此时你再调用带注解的方法,照样没有事务,只是一个普通的方法调用而已。

    @Transactional:Spring选择让protected方法和package方法不支持事务,所以只有public方法支持事务。
    只要是以代理方式实现的声明式事务,无论是JDK动态代理,还是CGLIB直接写字节码生成代理,都只有public方法上的事务注解才起作用。
    而且必须在代理类外部调用才行,如果直接在目标类里面调用,事务照样不起作用。

    //是否是JDK动态代理
    System.out.println("isJdkDynamicProxy => " + AopUtils.isJdkDynamicProxy(exampleService));
    //是否是CGLIB代理
    System.out.println("isCglibProxy => " + AopUtils.isCglibProxy(exampleService));
    //代理类的类型
    System.out.println("proxyClass => " + exampleService.getClass());
    //代理类的父类的类型
    System.out.println("parentClass => " + exampleService.getClass().getSuperclass());
    //代理类的父类实现的接口
    System.out.println("parentClass's interfaces => " + Arrays.asList(exampleService.getClass().getSuperclass().getInterfaces()));
    //代理类实现的接口
    System.out.println("proxyClass's interfaces => " + Arrays.asList(exampleService.getClass().getInterfaces()));
    //代理对象
    System.out.println("proxy => " + exampleService);
    //目标对象
    System.out.println("target => " + AopProxyUtils.getSingletonTarget(exampleService));
    //代理对象和目标对象是不是同一个
    System.out.println("proxy == target => " + (exampleService == AopProxyUtils.getSingletonTarget(exampleService)));
    //目标类的类型
    System.out.println("targetClass => " + AopProxyUtils.getSingletonTarget(exampleService).getClass());
    //目标类实现的接口
    System.out.println("targetClass's interfaces => " + Arrays.asList(AopProxyUtils.getSingletonTarget(exampleService).getClass().getInterfaces()));
    

    参考:【面试】我是如何在面试别人Spring事务时“套路”对方的

    相关文章

      网友评论

          本文标题:AOP猛快糙入门

          本文链接:https://www.haomeiwen.com/subject/chaxpqtx.html