Spring:简单聊聊Spring AOP的原理和使用场景

BigDataKer 2019-09-14 20:02:53

软件工程有个基本原则,即关注点分离,不同的问题交给不同的部分去解决,面向切面编程 AOP 正是此种技术的体现,通用化功能代码的实现对应的就是所谓的切面(Aspect),业务功能代码和切面代码分开后,架构将变得高内聚低耦合。

Spring:简单聊聊Spring AOP的原理和使用场景

 

AOP 的三种织入方式:

编译时织入:需要特殊的 Java 编译器,如 AspectJ;

类加载时织入:需要特殊的 Java 编译器,如 AspectJ 和 AspectWerkz;

运行时织入:Spring 采用的方式,通过动态代理的方式,实现简单,动态代理虽然有性能上的开销,但是好处就是不需要特殊的编译器和类加载器。

AOP 的主要名词概念:

Aspect:通用功能的代码实现;

Target:被织入 Aspect 的对象;

Join Point:可以作为切入点的机会,所有方法都可以作为切入点;

Pointcut:Aspect 实际被应用在的 Join Point,支持正则;

Advice:类里的方法以及这个方法如何织入到目标方法的方式;

Weaving:AOP 的实现过程。

Advice 的种类:

前置通知(Before);

后置通知(AfterReturning);

异常通知(AfterThrowing);

最终通知(After);

环绕通知(Around)。

1.Spring AOP的使用

这里我们基于 Spring Boot 构建项目,使用 AOP 需要添加 Maven 依赖:

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

这里我们创建 Aspect 文件通过 AOP 统一处理 request 请求日志:

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.http.HttpServletRequest;

@Aspect // 定义为切面类
@Component
public class RequestLogAspect {
 private static final Logger logger = LoggerFactory.getLogger(RequestLogAspect.class);
 // 定义切入点
 @Pointcut("execution(public * com.example.server.soa.web.controller..*.*(..))") // 支持正则
 public void webLog() {
 }
 // 方法执行之前切入
 @Before("webLog()")
 public void doBefore(JoinPoint joinPoint) {
 // 接收到请求, 记录请求内容
 ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
 HttpServletRequest request = attributes.getRequest();
 // 记录下请求内容
 logger.info("url: ", request.getRequestURL().toString());
 logger.info("ip: ", request.getRemoteAddr());
 }
 @After("webLog()")
 public void doAfter() {
 logger.info("doAfter");
 }
 // 方法执行return之后切入
 @AfterReturning(returning = "ret", pointcut = "webLog()")
 public void doAfterReturning(Object ret) {
 // 处理完请求, 返回内容
 logger.info("response: ", ret);
 }
 @AfterThrowing("webLog()")
 public void doAfterThrowing() {
 logger.info("doAfterThrowing");
 }
}

2.Spring AOP的原理

Spring 提供了两种方式来生成代理对象:JdkProxy 和 Cglib,具体使用哪种方式生成,由 AopProxyFactory 根据 AdvisedSupport 对象的配置来决定。默认的策略是如果目标类实现了接口,则用 JdkProxy 来实现,否则使用 Cglib。

Spring:简单聊聊Spring AOP的原理和使用场景

 

掌握 Spring AOP 的原理,需要先看下代理模式:

代理模式就是接口 + 真正实现类 + 代理类组成的,其中真实实现类和代理类都是需要实现接口的,实例化的时候要使用代理类,所以 Spring AOP 需要做的是生成一个代理类来替换掉真实实现类以对外服务。

代理模式参考:https://blog.csdn.net/smartbetter/article/details/70834042

Spring 里的代理模式的实现:

真正实现类的逻辑包含在了 getBean() 方法里;

getBean() 方法返回的实际上是 Proxy 的实例;

Proxy 实例是 Spring 采用 JDK Proxy 或 Cglib 动态生成的;

getBean() 方法用于查找和实例化容器中的 Bean,这也是为什么 Spring AOP 只能作用于 Spring 容器中 Bean 的原因,对于不是使用 IOC 容器管理的对象,Spring AOP 是无能为力的。

————————————————

版权声明:本文为CSDN博主「郭朝」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。

原文链接:https://blog.csdn.net/smartbetter/article/details/100716557

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值