目录
- 代理
- 什么是代理
- 代理模式
- 静态代理
- 动态代理
- JDK动态代理
- CGLIB动态代理
- Spring AOP使用的是哪种代理?
代理
什么是代理
生活中的代理
- 房产中介 : 房屋进行租赁时,卖方会把房子授权给中介,由中介代理带客户看房,商谈价格
- 艺人经纪人:广告商找艺人拍广告时,不会直接和艺人沟通,会和经纪人沟通
房子的主人要做的事情,交给中介代理
代理模式
代理模式(菜鸟教程)
为其他对象提供一种代理以控制这个对象的访问,它的作用就是通过一个代理类,让我们在调用目标方法的时候,不是直接对目标得到进行调用,而是通过代理间接调用
代理模式的主要角色
- Subject: 业务接口类,可以是抽象类或者接口(不一定有)
- RealSubject: 业务实现类,具体的业务执行,也就是被代理对象
- Proxy: 代理类.RealSubjectde的代理
比如说房屋这里
Subject:提前定义好的事情,交给中介做的事情。
RealSubject:房东
Proxy:中介
根据代理的创建时期,代理模式分为静态代理和动态代理。
静态代理
由程序员创建代理类或特定工具自动生成源代码在对其编译,在程序员运行前代理类的.class文件就已经存在了
(在出租房子之前,中介已经做好了相关的工作,就等用户来租房子了)
- 定义接口(定义房东要做的事情,也是中介需要做的事情)
public interface HouseSubject {
void rentHouse();
}
- 实现接口(房东出租房子)
public class RealHouseSubject implements HouseSubject{
@Override
public void rentHouse() {
System.out.println("我是房东,我出租房子");
}
}
- 代理(中介,帮房东)
public class HouseProxy implements HouseSubject{
//将被代理对象是声明为成员变量
private HouseSubject houseSubject;
public HouseProxy(HouseSubject houseSubject) {
this.houseSubject = houseSubject;
}
@Override
public void rentHouse() {
// 开始代理
System.out.println("我是中介,开始代理");
//代理房东出租房子
houseSubject.rentHouse();
//代理结束
System.out.println("代理结束");
}
}
4.使用
public class StaticMain {
public static void main(String[] args) {
HouseSubject subject = new RealHouseSubject();
//创建代理类
HouseProxy proxy = new HouseProxy(subject);
//通过代理类访问目标方法
proxy.rentHouse();
}
}
运行结果
虽然静态代理完成了对目标对象的代理,但是由于代码都写死了,对目标对象的每个方法的增强都是手动完成的,非常不灵活
如果增加需求:代理房屋出售
1.定义接口修改
public interface HouseSubject {
void rentHouse();
void saleHouse();
}
2.接口实现修改
public class RealHouseSubject implements HouseSubject{
@Override
public void rentHouse() {
System.out.println("我是房东,我出租房子");
}
@Override
public void saleHouse() {
System.out.println("我是房东,我出售房子");
}
}
3.代理类修改
public class HouseProxy implements HouseSubject{
//将被代理对象是声明为成员变量
private HouseSubject houseSubject;
public HouseProxy(HouseSubject houseSubject) {
this.houseSubject = houseSubject;
}
@Override
public void rentHouse() {
// 开始代理
System.out.println("我是中介,开始代理");
//代理房东出租房子
houseSubject.rentHouse();
//代理结束
System.out.println("代理结束");
}
@Override
public void saleHouse() {
// 开始代理
System.out.println("我是中介,开始代理");
//代理房东出售房子
houseSubject.saleHouse();
//代理结束
System.out.println("代理结束");
}
}
我们修改接口(Subject)和业务实现类(RealSubject)时,还需要修改代理类(Proxy)。
同样的,如果有新增接口(Subject)和业务实现类(RealSubject),也需要对每一个业务实现类新增代理类(Proxy)
代理的流程是一样的,有没有一种办法,让他们通过一个代理类来实现呢?
这就需要用到动态代理技术了
动态代理
在程序运行时,运用发射制动态创建而成
(对于房子中介,我们不需要提前预测都有哪些业务,而是业务来了,在根据情况创建)
JDK动态代理
1.定义一个接口及其实现类(静态代理中的HouseSubject 和 RealHouseSubject)
2.自定义InvocationHandler并重写invoke方法,在invoke方法中我们会调用目标方法(被代理类的方法)并自定义一些处理逻辑
3.通过Proxy.newPorxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h) 方法创建代理对象
Loader:类加载器,用于加载代理对象
interfaces:被代理类实现的一些接口(这个参数的定义,也决定了JDK动态代理只能实现了接口的一些类)
h:实现了InvocationHandler接口对象
CGLIB动态代理
JDK动态代理有一个最致命的问题是其只能实现接口类。
在有一些场景下,我们的业务代码是直接实现的,并没有接口定义,CGLIB动态代理机制这时派上用场。
CGLIB介绍与原理
CGLIB是一个开源项目,需要手动添加相关依赖
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib-nodep</artifactId>
<version>3.1</version>
</dependency>
Spring AOP使用的是哪种代理?
1.Spring Framework
2.Speing Boot
底层实现都是JDK和CGLIB
Spring Framework: 如果代理的是接口,使用JDK。 如果代理的是没有实现接口的类,使用CGLIB
Spring Boot:默认配置使用CGLIB代理 在Spring Boot 2.X 之后的版本代理无论是否实现了接口,都使用CGLIB代理,如果需要使用JDK代理,需要设置。在Spring Boot 2.X 之前的版本默认使用JDK代理(和Spring Framework一致)