Spring AOC篇

51 阅读3分钟

Spring AOP篇

日志

1.硬编码 (不推荐):通用逻辑+专用逻辑 耦合难以维护

2.静态代理

定义:定义一个代理对象,包装这个组件,以后业务的执行从代理开始,不直接调用组件

特点:定义期间就指定好代理关系

代理对象本身并不是目标对象,而是将目标对象作自身属性

优点:同一类型的所有对象都能代理

缺点:范围太小,只能负责不服接口代理功能

3.动态代理:运行期间才决定好代理关系(拦截器:拦截所有)

定义:目标对象在执行期间才会被动态拦截,插入指定逻辑

优点:可代理世间万物

缺点:不好写

AOP

专业术语

未命名绘图.drawio.png

切入点:实际用通知方法的连接点

AOP实现

1.导入AOP依赖

2.编写切面Aspect

3.编写通知方法

4.指定切入点表达式

5.测试AOP动态织入

@Aspect 告诉Spring组件里面是切面

切面类

告诉Spring,以下通知何时何地运行

何时:

@Before 方法执行之前

@AfterReturning 方法执行正常返回结果运行

@AfterThrowing 方法执行抛出异常执行

@After 方法执行之后运行

@Around 环境通知

何地:

​ 切入点表达式

execution(方法修饰符 返回值类型 包名.类名.方法名(参数) throws 异常) 最常用

​ eg.

	// 匹配 com.example.service 包下的所有类的所有方法
	execution(* com.example.service.*.*(..))
	
	// 匹配 com.example.service 包及子包下所有类的所有方法
	execution(* com.example.service..*.*(..))

	// 匹配所有 public 方法
	execution(public * *(..))
	
	// 匹配返回值为 String 的方法
	execution(String *(..))

within() 匹配某个类或包下的所有方法。

​ eg.

	within(com.example.service.UserService)   // 类
	within(com.example.service.*)             // 包

this()/target()

​ this:代理对象是指定类型

​ target:目标对象(被代理的原始对象)是指定类型

​ eg.

	this(com.example.service.UserService)
	target(com.example.service.UserService)

args() 匹配方法参数

​ eg.

	args(Long,..)     // 第一个参数是 Long
	args(String)      // 只有一个 String 参数

bean() Spring bean连接点

​ eg.

	// 匹配 id 为 userService 的 bean 中的所有方法
	bean(userService)
	// 匹配名字以 Service 结尾的 bean 中的所有方法
	bean(*Service)

AOP底层原理

1.spring会为每个被切面而切入的组件创建代理对象

2.代理对象中保存了切面类里面所有通知方法构成的增强器链

3.目标方法执行时先去执行增强器链中拿到所需要提前执行的通知方法去执行

​ 增强器链:一个方法对应的所有增强器的集合

​ 增强器:切面里封装的“增强逻辑+匹配机制”

通知方法的执行顺序

正常链路

2.png

异常链路

3.png

@PointCut 抽取切入点表达式

多切面执行顺序

4.png

@Order

给组件调顺序,数字越小,优先级越高

@Around 环绕通知

环绕通知就像一层“外壳”,把目标方法包裹住, 既能在方法前后做处理,又能控制方法是否执行,是 AOP 里最灵活的通知。

环绕通知方法一般要接收一个 ProceedingJoinPoint 参数,代表当前连接点。

eg.

@Around("execution(* com.example.service.*.*(..))")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
    // 前置逻辑
    System.out.println("方法执行前");

    // 执行目标方法
    Object result = pjp.proceed();

    // 后置逻辑
    System.out.println("方法执行后");

    return result;
}

Spring容器底层的三级缓存机制

​ 用三个Map来管理单例Bean的不同阶段

成品:

​ Map<string,object>singletonobjects

​ 完全创建好的单例对象池

半成品:

​ Map<string,object>earlysingleobjects

​ 半成品Bean(已经实例化,但还没完全初始化好)

​ 解决循环依赖:A正在创建,B需A就先把A的半成品放到二级缓存先给B用占个位子

模具:

​ Map<string,objectFactory<?>>singletonFactones

​ 解决代理对象(AOP)的问题