Spring-AOP 杂谈小记
本文最后更新于:2022年9月16日 下午
前情提要
众所周知,IOC(Inversion of Control)
&& AOP(Aspect-Oriented Programming)
是Spring
的两大核心
而AOP
又是基于IOC
的
AOP
,面向切面编程,是OOP
(面向对象编程)的拓展和延伸,是设计模式中代理模式的一种实现
OOP
通常只能对连续代码进行封装,而类似日志这样分散核心代码前后各处的非核心代码,却难以实现集中处理,是一大痛点
官方一点就是:它将业务逻辑的各个部分进行隔离,使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,使开发人员在编写业务逻辑时可以专心于核心业务,从而提高了开发效率
于是便有了AOP
Spring
的AOP
基于AspectJ
,具体底层实现有两种:
JDK
原生动态代理(有接口的情况):需要被代理的目标类必须实现接口,因为这个技术要求代理对象和目标对象实现同样的接口(兄弟两个拜把子模式)cglib
(无接口的情况):通过继承被代理的目标类(认干爹模式)实现代理,所以不需要目标类实现接口,但是不能对final
方法进行代理;其底层使用字节码处理框架ASM
,来转换字节码并生成新的类(效率高于前者)
正片(叠底
好的,上面都是官方废话
前情提要啊,前情提要
(略过切面的配置,你们都懂的对吧)
现在的主要问题是如何使用AOP
生成的代理类呢
(我发现大部分都在讲怎么配置 没讲怎么用啊大哥)
有接口的情况(JDK动态代理)
1 |
|
好的,现在假装:我们有一个接口(Calculator
)和一个实现类(CalculatorImpl
)
前面说了,Spring
的AOP
基于IOC
,所以我们的目标类和代理类都是交给IOC
管理的
并且,我们将不能再通过IOC
容器获取原始目标类(被从IOC
中删除,可能是给代理类让位)
好的,问题来了,我们要如何获取代理类呢?
首先,我们不知道代理类的类名,其次不知道其bean
的id
,how to get it
(插叙:其实通过cal.getClass().getName()
可以获得类名,发现是动态生成的:com.sun.proxy.$Proxy16
)
但是,前面说了,代理类和目标类共同实现同一个接口,而且IOC
容器可以智能地根据接口返回实现类(前提是实现类唯一)
这可能就是IOC
自动删除目标类bean
的原因,这样我们就可以根据接口直接获取代理类了
1 |
|
但是捏,问题来了,如果实现类不唯一怎么办
比如还有一个实现类:CalculatorImpl2
也实现了Calculator
接口
那么IOC
容器中将有两个代理类(实现了同一接口Calculator
)
这种情况下ioc.getBean(Calculator.class)
就不知道返回哪一个实现类了,就会抛出异常
1 |
|
那我们在这种情况下该如何获取CalculatorImpl
的代理类呢(大部分资料都没说aaaaa 气shi我啦)
这种时候就需要回想一下IOC
的知识了,在接口有多个实现类的情况下,我们如何获取指定实现类
通过重载函数getBean(String var1, Class<T> var2)
是吧,第一个参数是bean id
,第二个是接口类
那么此时,我们也可以通过这种方法标识实现类(毕竟直接通过实现类.class
已经不行了对吧,deleted)
id?
那么问题又来了,id
是啥,如果是通过xml
配置的,id
就是自己写的
1 |
|
如果是通过@Component
注解控制的,那么默认id
为类名的小驼峰,即calculatorImpl
1 |
|
当然@Component
也可以自定义id
,like @Component("calImpl")
这个故事告诉我们知识需要回顾和串联
无接口(cglib继承实现子类)
这种情况下直接通过目标类即可获取代理类(子类)
1 |
|