Spring-AOP 杂谈小记

本文最后更新于:2022年9月16日 下午

前情提要

众所周知,IOC(Inversion of Control) && AOP(Aspect-Oriented Programming)Spring的两大核心

AOP又是基于IOC

AOP,面向切面编程,是OOP(面向对象编程)的拓展和延伸,是设计模式中代理模式的一种实现

OOP通常只能对连续代码进行封装,而类似日志这样分散核心代码前后各处的非核心代码,却难以实现集中处理,是一大痛点

官方一点就是:它将业务逻辑的各个部分进行隔离,使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,使开发人员在编写业务逻辑时可以专心于核心业务,从而提高了开发效率

于是便有了AOP

SpringAOP基于AspectJ,具体底层实现有两种:

  • JDK原生动态代理(有接口的情况):需要被代理的目标类必须实现接口,因为这个技术要求代理对象和目标对象实现同样的接口(兄弟两个拜把子模式)
  • cglib(无接口的情况):通过继承被代理的目标类(认干爹模式)实现代理,所以不需要目标类实现接口,但是不能对final方法进行代理;其底层使用字节码处理框架ASM,来转换字节码并生成新的类(效率高于前者)

正片(叠底

好的,上面都是官方废话

前情提要啊,前情提要

(略过切面的配置,你们都懂的对吧)

现在的主要问题是如何使用AOP生成的代理类呢

(我发现大部分都在讲怎么配置 没讲怎么用啊大哥)

有接口的情况(JDK动态代理)

1
2
3
4
5
6
@Test
public void test() {
ApplicationContext ioc = new ClassPathXmlApplicationContext("spring-context.xml");
Calculator cal = ioc.getBean(Calculator.class);
System.out.println(cal.div(1, 1));
}

好的,现在假装:我们有一个接口(Calculator)和一个实现类(CalculatorImpl

前面说了,SpringAOP基于IOC,所以我们的目标类和代理类都是交给IOC管理的

并且,我们将不能再通过IOC容器获取原始目标类(被从IOC中删除,可能是给代理类让位)

好的,问题来了,我们要如何获取代理类呢?

首先,我们不知道代理类的类名,其次不知道其beanid,how to get it

(插叙:其实通过cal.getClass().getName()可以获得类名,发现是动态生成的:com.sun.proxy.$Proxy16

但是,前面说了,代理类和目标类共同实现同一个接口,而且IOC容器可以智能地根据接口返回实现类(前提是实现类唯一)

这可能就是IOC自动删除目标类bean的原因,这样我们就可以根据接口直接获取代理类了

1
Calculator cal = ioc.getBean(Calculator.class); 

但是捏,问题来了,如果实现类不唯一怎么办

比如还有一个实现类:CalculatorImpl2也实现了Calculator接口

那么IOC容器中将有两个代理类(实现了同一接口Calculator

这种情况下ioc.getBean(Calculator.class)就不知道返回哪一个实现类了,就会抛出异常

1
NoUniqueBeanDefinitionException

那我们在这种情况下该如何获取CalculatorImpl的代理类呢(大部分资料都没说aaaaa 气shi我啦)

这种时候就需要回想一下IOC的知识了,在接口有多个实现类的情况下,我们如何获取指定实现类

通过重载函数getBean(String var1, Class<T> var2)是吧,第一个参数是bean id,第二个是接口类

那么此时,我们也可以通过这种方法标识实现类(毕竟直接通过实现类.class已经不行了对吧,deleted)

id?

那么问题又来了,id是啥,如果是通过xml配置的,id就是自己写的

1
<bean id="calImpl" class="com.mrbeanc.spring.aop.CalculatorImpl">

如果是通过@Component注解控制的,那么默认id为类名的小驼峰,即calculatorImpl

1
Calculator cal = ioc.getBean("calculatorImpl", Calculator.class);

当然@Component也可以自定义id,like @Component("calImpl")

这个故事告诉我们知识需要回顾和串联

无接口(cglib继承实现子类)

这种情况下直接通过目标类即可获取代理类(子类)

1
2
3
4
CalculatorImpl cal = ioc.getBean("calculatorImpl");
//or
CalculatorImpl cal = ioc.getBean(CalculatorImpl.class);
//maybe 我猜的hh

Peace

Ref

Spring——AOP实现方式 - 掘金

字节码增强和spring AOP 原理_长不大的大灰狼的博客-CSDN博客_字节码增强实现aop

理解Spring中的getBean() - 简书

【Spring框架】Spring的AOP使用_Sampson_S的博客-CSDN博客


Spring-AOP 杂谈小记
https://mrbeancpp.github.io/2022/09/16/Spring-AOP-杂谈小记/
作者
MrBeanC
发布于
2022年9月16日
许可协议