一、什么是AOP
AOP是一种思想,也称为“面向切面编程”。
AOP 技术利用一种称为“横切”的技术,剖解开封装的对象内部,并将那些影响了多个类
的公共行为封装到一个可重用模块,并将其名为“Aspect”,即方面。所谓“方面”,简单地说,
就是将那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的
重复代码,降低模块间的耦合度,并有利于未来的可操作性和可维护性。
AOP将程序中业务处理的主要逻辑称为“核心关注点”,其他次要的部分称为“横切关注点”。横切关注点的特点是,它们经常发生在核心关注点的多处,且各处基本相似。比如权限认证、日志等。Aop 的作用在于抽离出系统中的横切关注点,以降低模块间的耦合度。
二、AOP的原理
AOP是基于代理(Proxy)实现的,具体实现方式有两种:
- jdk动态代理
– 若目标对象有实现接口,用JDK代理 - Cglib代理
–若目标对象没有实现接口,默认用Cglib代理
ps:(对于这两种代理有兴趣的同学可以看下这篇文章) https://www.cnblogs.com/cenyu/p/6289209.html
三、AOP中的基本概念
AOP中的基本概念很多很杂,这里简要介绍几种,
-
通知(Adivce):
通知有"Before,After ,After-returning,After-throwing,Around" 五种类型 -
切面(Aspect):
切面是切点和通知的集合,一般单独作为一个类。 -
连接点(Join point):
程序执行的某个特定位置(如:某个方法调用前、调用后,方法抛出异常后),一个类或一段程序代码拥有一些具有边界性质的特定点,这些代码中的特定点就是连接点。Spring仅支持方法的连接点。 -
切点(Pointcut):
如果连接点相当于数据中的记录,那么切点相当于查询条件,一个切点可以匹配多个连接点
四、一个简单的AOP例子
前面说过,aop的作用就是将那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块间的耦合度。现在比如说有一个web项目,我们需要知道一个方法的执行时间并且打印日志,那么此时我们可以利用aop来实现。
首先用IntelliJ IDEA 创建一个springboot项目叫做aopdemo,然后在aopdemo下新建两个程序:
@Controller
public class HelloController {
private static final Logger logger = LoggerFactory.getLogger(HelloController.class);
@RequestMapping(path = {"/hello"})
@ResponseBody
public String Hello(){
logger.info("Hello World");
try {
Thread.sleep(3000);//这里让线程睡眠3s,以便在后面辨别方法执行前后的时间
} catch (InterruptedException e) {
e.printStackTrace();
}
return "Hello World";
}
}
由于刚创建的项目没有AOP相关的依赖,所以要在pom.xml文件中加入:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
@Aspect
@Component
public class LogAspect {
private static final Logger logger = LoggerFactory.getLogger(LogAspect.class);
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
// execution即执行,*是通配符,以下语句的作用就是匹配com.example.aopdemo.controller包
// 中HelloController类的所有方法,也就是说当HelloController类中的任意方法被调用时,
// 此方法会在其之前先调用
@Before("execution(* com.example.aopdemo.controller.HelloController.*(..))")
public void beforeMethod(JoinPoint joinPoint){
logger.info("before method:"+ df.format(new Date()));
}
@After("execution(* com.example.aopdemo.controller.HelloController.*(..))")
public void afterMethod(JoinPoint joinPoint){
logger.info("after method:"+ df.format(new Date()));
}
}
运行AopdemoApplication,在浏览器中输入“http://localhost:8080/hello”
可以看到控制台打印出的log如下:
当HelloController 的hello方法被执行前,aop先执行了beforeMethod方法,hello方法执行完之后,再执行了afterMethod方法,由于hello方法睡眠了3s,所以打印出来执行前后的时间差也是3s,符合我们的预期。
这只是aop的一个简单应用,更多更复杂的还需要我们一点点去了解。