一.AOP常见的实现方式
1.Spring AOP
2.aspectJ
注意:spring使用的是aspectJ的注解,但实现是spring自身实现的.
二.AOP原理
Spirng AOP原理 , 基于动态代理实现的.
三.代理模式
作用就是提供一个代理类,让我们在调用目标方法的时候,不再是直接对目标方法进行调用,而是通过代理类间接调用.
代理模式的主要角色:
1.subject 业务接口类,可以是抽象类或者是接口
2.realSubject 业务实现类,具体的业务执行,也就是被代理对象
3.proxy 代理类
以房东和中介的关系来举例子:
房东是被代理对象
中介是代理对象
买主买房子不是直接找房东,而是通过中介来找到房东,才能买房子;
买主不是直接房东的买房子方法,而是通过中介调用房东的买房子方法;
对应关系
|--------------------------------------|--------------------|
| 1.subject 业务接口类,可以是抽象类或者是接口 | 中介要做的事情(房东交给中介的事情) |
| 2.realsubject 业务实现类,具体的业务执行,也就是被代理对象 | 房东 |
| 3.proxy 代理类 , 对于realsubject的代理. | 中介 |
代理模式可以在不修改被代理对象的基础上,通过扩展代理类,进行一些功能的增强.
根据代理的创建时期,代理模式分为静态代理和动态代理.
1.静态代理
由程序员创建代理类或特定工具自动生成源代码再对其编译
在程序运行前,代理类的.class文件就已经存在了 (在出租房子之前,中介就已经做好了相关的工作,就等租户来租房子了)
缺陷: 修改或者新增接口和业务实现类时,还需要修改或者新增代理类
2.动态代理
在程序运行时,运用反射机制动态完成创建 , 相比静态代理来说,动态代理更加灵活.
我们不需要针对每个对象单独创建一个代理对象 , 而是把创建代理对象的工作推迟到程序运行时由JVM来实现
Java也对动态代理进行了实现,并给我们提供了一些API,常见的方式有两种
2.1JDK动态代理
只能代理接口,不能代理对象
实现步骤:
1.定义一个接口及其实现类(静态代理中的HouseSubject 和 RealHouseSubject )
public interface HouseSubject {
public void rentHouse();
}
/**
* 业务接口类
*/
public class RealHouseSubject implements HouseSubject{
@Override
public void rentHouse() {
System.out.println("我是房东,我要出租房子...");
}
}
2.实现InvocationHandler接口,并重写invoke方法,在invoke方法中我们会调用目标方法
public class JDKInvocation implements InvocationHandler {
private Object target;//目标对象,被代理对象
public JDKInvocation(Object object){
this.target=object;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("我是中介,开始代理");
//通过反射调用被代理类的方法
Object retVal=method.invoke(target,args);
System.out.println("我是中介,代理结束");
return retVal;
}
}
3.通过Proxy.newProxyInstance方法创建对象
public static void mainJDK(String[] args) {
HouseSubject target=new RealHouseSubject();//代理接口
HouseSubject proxy= (HouseSubject) Proxy.newProxyInstance(target.getClass().getClassLoader(),
new Class[]{HouseSubject.class},
new JDKInvocation(target)
);
proxy.rentHouse();
}
说明:
Proxy类的newProxyInstance方法主要用来生成一个代理对象,这个方法有三个参数:
|------------|---------------------------|
| loader | 类加载类,用于加载代理对象 |
| interfaces | 被代理类实现的一些接口(决定了JDK只能代理接口) |
| h | 实现InvocationHandler接口的对象 |
2.2CGlib动态代理
第三方的,需要添加依赖 ;
既可以代理类,也可以代理接口
实现步骤:
1.定义一个类(被代理类)
/**
* 业务接口类
*/
public class RealHouseSubject implements HouseSubject{
@Override
public void rentHouse() {
System.out.println("我是房东,我要出租房子...");
}
}
2.自定义MethodInteptor,并重写intercept方法,intercept用于增强目标方法
public class CGLibIntercepter implements MethodInterceptor {
private Object target;
public CGLibIntercepter(Object object) {
this.target = object;
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("我是中介,开始代理");
Object retVal = methodProxy.invoke(target, objects);
System.out.println("我是中介,结束代理");
return retVal;
}
}
3.通过Enhancer类的create方法创建类
public static void main(String[] args) {
HouseSubject target=new RealHouseSubject(); //代理接口
HouseSubject proxy= (HouseSubject) Enhancer.create(target.getClass(), new CGLibIntercepter(target));
proxy.rentHouse();
}
注意:CGlib是第三方的开源项目,使用需要添加相关依赖.
面试题
-谈谈Spring AOP是怎么实现的?
基于动态代理实现的
-动态代理是怎么实现的
Spring动态代理是基于JDK和CGlib实现的
-Spring使用的是哪个
两个都使用的
-何时使用JDK,何时使用CGlib
代理类,只能使用CGlib;
代理接口,可以使用JDK,也可以使用CGlib
(SpringBoot2.x之后,默认使用的是CGlib代理 , 通过设置spring.aop.proxy-target-class=false 可以改成JDK代理 )