目录
- 代理
- 什么是代理
- 代理模式
- 静态代理
- 动态代理
- JDK动态代理
- CGLIB动态代理
- Spring AOP使用的是哪种代理?
代理
什么是代理
生活中的代理
- 房产中介 : 房屋进行租赁时,卖方会把房子授权给中介,由中介代理带客户看房,商谈价格
- 艺人经纪人:广告商找艺人拍广告时,不会直接和艺人沟通,会和经纪人沟通
房子的主人要做的事情,交给中介代理
代理模式
代理模式(菜鸟教程)
为其他对象提供一种代理以控制这个对象的访问,它的作用就是通过一个代理类,让我们在调用目标方法的时候,不是直接对目标得到进行调用,而是通过代理间接调用
代理模式的主要角色
- Subject: 业务接口类,可以是抽象类或者接口(不一定有)
- RealSubject: 业务实现类,具体的业务执行,也就是被代理对象
- Proxy: 代理类.RealSubjectde的代理
比如说房屋这里
Subject:提前定义好的事情,交给中介做的事情。
RealSubject:房东
Proxy:中介
根据代理的创建时期,代理模式分为静态代理和动态代理。
静态代理
由程序员创建代理类或特定工具自动生成源代码在对其编译,在程序员运行前代理类的.class文件就已经存在了
(在出租房子之前,中介已经做好了相关的工作,就等用户来租房子了)
- 定义接口(定义房东要做的事情,也是中介需要做的事情)
public interface HouseSubject {void rentHouse();
}
- 实现接口(房东出租房子)
public class RealHouseSubject implements HouseSubject{@Overridepublic void rentHouse() {System.out.println("我是房东,我出租房子");}
}
- 代理(中介,帮房东)
public class HouseProxy implements HouseSubject{//将被代理对象是声明为成员变量private HouseSubject houseSubject;public HouseProxy(HouseSubject houseSubject) {this.houseSubject = houseSubject;}@Overridepublic 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{@Overridepublic void rentHouse() {System.out.println("我是房东,我出租房子");}@Overridepublic void saleHouse() {System.out.println("我是房东,我出售房子");}
}
3.代理类修改
public class HouseProxy implements HouseSubject{//将被代理对象是声明为成员变量private HouseSubject houseSubject;public HouseProxy(HouseSubject houseSubject) {this.houseSubject = houseSubject;}@Overridepublic void rentHouse() {// 开始代理System.out.println("我是中介,开始代理");//代理房东出租房子houseSubject.rentHouse();//代理结束System.out.println("代理结束");}@Overridepublic 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一致)