文章目录
AOP的主要用途
AOP的主要用途是在不改变目标类的情况下,对目标类添加一些额外的功能进行增强,主要原理是使用动态代理来动态的生成代理对象,在代理对象中添加额外的功能
AOP的几个重要的概念:
Joint point(连接点): 表示程序中明确定义的点,比如方法调用、成员访问、异常处理这些点都是AOP可以织入的点
Pointcut(切点): 表示AOP具体需要织入的点,也就是从Joint point(连接点)中过滤出来的一些点
Advice(增强): 表示我要对需要强入的点做什么操作,它通过 before、after 和 around 来区别是在每个 joint point 之前、之后还是代替执行的代码
Target(目标对象): 需要增强的具体对象
Weaving(织入): 将额外的功能添加到目标对象的过程
Aspect(切面): PointCut和Advice的组合
Advice的几个注解:
注解 | 描述 |
---|---|
@Before | 连接点前面执行,不能终止后续流程,除非抛异常 |
@AfterReturning | 连接点正常返回时执行,有异常不执行 |
@Around | 围绕连接点前后执行,也能捕获异常处理 |
@After | 连接点退出时执行,无论是正常退出还是异常退出 |
@AfterThrowing | 连接点方法抛出异常时执行 |
AOP前置增强范例
1:定义接口
public interface GameService {
public void game();
}
public interface ReadService {
public void read();
}
2:定义实现类
@Component
public class GameServiceImpl implements GameService {
@Override
public void game() {
System.out.println("玩游戏");
}
}
@Component
public class ReadServiceImpl implements ReadService {
@Override
public void read() {
System.out.println("阅读书籍");
}
}
@Component
public class SleepServiceImpl {
public void sellp() {
System.out.println("睡觉");
}
}
3:定义切面类
需要引入切面注解@Aspect依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
</dependency>
@Aspect
@Component
public class AspectSection {
@Before("execution(* com.xlf.test.aop.service.GameService.game(..)) || execution(* com.xlf.test.aop.serviceimpl.SleepServiceImpl.sellp(..))")
public void action(){
System.out.println("在干嘛");
}
}
4:自动配置的加载类
@Configuration
@ComponentScan(basePackages = "com.xlf.test.aop")
@EnableAspectJAutoProxy
public class LifeCofig {
}
5:测试类
public class TestAop {
@Test
public void aopBefore(){
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(LifeCofig.class);
GameService gameService = context.getBean("gameServiceImpl",GameService.class);
SleepServiceImpl sleepService = context.getBean("sleepServiceImpl",SleepServiceImpl.class);
ReadService readService = context.getBean("readServiceImpl", ReadService.class);
gameService.game();
System.out.println("------------");
sleepService.sellp();
System.out.println("------------");
readService.read();
}
}
输出结果
后置增强范例
只需要把后置增强注解@Before改为@After即可
来看看运行效果
Spring AOP是如何实现的
我们都知道AOP的实现方法是动态代理,就是在程序运行期间动态的为目标类创建代理,从而实现目标类的增强
Java的动态代理有两种实现方式:
JDK的动态代理
CGlib动态代理
这两种动态代理的主要区别:
JDK是通过代理类跟目标类实现同一个接口来实现代理的
CGlib是通过继承目标类来实现代理的
实现了接口的类进行增强时使用JDK的动态代理,普通类的增强使用CGlib
GameService实现了接口的类,使用的是JDK动态代理
SleepServiceImpl是个普通类,使用的是CBLIB动态代理
既然CGLIB可以实现普通类的增强,那它必然也是支持实现了接口的类的增强,因为实现了接口的类也是普通类
我们只要修改一个参数,就可以实现全部使用CGLIB动态代理
proxyTargetClass = true 表示所有类都使用CGLIB动态代理
我们修改参数后,运行结果如下图所示
可以看出来,GameService是实现了接口的类,默认情况下是使用JDK动态代理,当把@EnableAspectJAutoProxy注解的proxyTargetClass属性改为true时,所有类都使用CBLIB动态代理