什么是AOP?
- 通用化功能代码的实现,对应的就是所谓的切面(横向重复代码,纵向抽取成一个切面)
- 业务功能代码和切面代码分开后,架构将变成高内聚低耦合
- 确保功能的完整性:把切面连接到目标对象中(织入)
AOP的三种织入方式:
- 编译时织入:需要特殊的java编译器,如AspectJ
- 类加载时织入:需要特殊的java编译器,如AspectJ和AspectWerkz
- 运行时织入:Spring采用的方式,通过动态代理,Cglib代理等,实现简单
问题分析:
假如现在在Controller包下有一个HelloController类,HelloController类下有一个hello方法
假如现在要对该方法进行一些日志处理,那么只要在return之前,编写一些代码进行处理即可,但是随着程序的不断迭代,HelloController里面的方法越来越多,甚至Controller包下的Controller类也越来越多,此时如果对每个Controller类的每个方法都增加记录的代码,就会变得相当麻烦,后期的维护成本也相当的高。为了解决这以问题,便引入了AOP
代码实现:
Spring boot框架中Spring AOP的简单应用
在pom.xml中引入相关spring aop的相关依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
编写相关切面类
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
@Aspect //切面类
@Component //作为bean 托管到ioc容器
public class RequestLogAspect {
private static final Logger logger = LoggerFactory.getLogger(RequestLogAspect.class);
//切入点
@Pointcut("execution(public * com.oracle.controller..*.*(..))")
public void controllerLog(){}
//开始处切入
@Before("controllerLog()")
public void doBofore(JoinPoint joinPoint){
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
//记录下请求内容
logger.info("URL:"+request.getRequestURI());
logger.info("ip:"+request.getRemoteAddr());
}
@AfterReturning(returning = "ret",pointcut = "controllerLog()")
public void doAfterReturning(Object ret){
logger.info("RESPONSE:"+ret);
}
}
AOP的主要名词概念:
- Aspect(切面):通用功能的代码实现
- Join Point(连接点):可以作为切入点的地方。这个点可以是调用方法时、抛出异常时、甚至修改一个字段时。
- Pointcut(切点):会匹配通知所要织入的一个或多个连接点,我们通常使用明确的类和方法名称(比如上述代码的"execution(public * com.oracle.controller..*.*(..))")
- Advice(通知):类里面的方法(前置通知,后置通知,环绕通知,最终通知,最终通知)
- targer(目标对象):被代理的对象
- Weaving(织入):把切面连接到被代理对象中