学习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()));
网友评论