AOP猛快糙入门

2019-03-06  本文已影响0人  packet

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

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

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

切点(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事务时“套路”对方的

上一篇下一篇

猜你喜欢

热点阅读