代理模式详解
目标
- 掌握代理模式的应用场景和实现原理
- 了解静态代理和动态代理的区别
- 了解CGLib和JDK Proxy的根本区别
- 手写实现定义的动态代理
SpringAOP是用代理模式实现,到底是怎么实现的?
仿真实现
代理模式 (Proxy Pattern)是指为其他对象提供一种代理,以控制对这个对象的访问。
代理对象在客户端和目标对象直接起到中介作用。
属于结构型设计模式。
目的:
保护目标对象
增强目标对象
生活中的代理模式
- 房产中间
- 快递小哥
- 黄牛党
- 媒婆
非侵入式的日志实现
Subject <–> Proxy
|
realSubject
静态代理:
public interface Person(){
void findLove();
}
public class Son implements Person {
public void findLove(){
System.out.println("儿子要求,肤白貌美大长腿");
}
}
public class Father{
private Person person;
public Father(Person person){
this.person= person;
}
public void findLove() {
System.out.println("父亲物色对象");
person.findLove();
System.out.println("双方父母同意,确立关系");
}
}
public class FatherProxyTest{
public static void main(String[] args) {
Father father = new Father(new Son());
father.findLove();
// 农村,媒婆
// 婚介所
// 大家每天都在用的一种静态代理的形式
// 对数据库进行分库分表
// ThreadLocal
// 进行数据源的动态切换
}
}
动态代理
dbroute
public class Order {
private Object orderInfo;
private Long createTime;
private String id;
}
// setter getter
public class OrderDAO{
public int insert(Order order) {
System.out.println("OrderDao创建Order成功!");
return 1;
}
}
public class DynamicDataSourceEntity{
private final static String DEFAULT_SOURCE= null;
private final static ThreadLocal<String> local = new ThreadLocal<String>();
private DynamicDataSourceEntity(){}
public static String get() {
return local.get();
}
public static void set(String source) {
local.set(source);
}
public static void restore(){
local.set(DEFAULT_SOURCE)
}
}
public class OrderServiceStaticProxy {
private IOrderService orderService;
orderService.createOrder()
}
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");
Date date = sdf.parse("2017/02/01");
public class Girl implements Person{
public void findLove() {
System.out.print("高富帅");
System.out.print("身高180cm");
}
}
public class MeiPo implements InvocationHandler {
private Person target;
public Object getInstance(Person person) {
this.target = person;
Class<?> clazz = target.getClass();
return Proxy.newProxyInstance(clazz.getClassLoader(),clazz.getInterfaces(),this);
}
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
method.invoke(this.target,args);
return null;
}
}
public interface LQInvocationHandler{
public Object invoke(Objet object );
}
public class LQProxy{
public static Object newProxyInstance(ClassLoader classLoader,Class<?> interfaces,) {
// 1.动态生成源代码
// 2.java文件输出到磁盘
getResource("").getPath(); // 类路径
}
}
// 理解jdk动态代理的实现原理
- 拿到被代理类的引用, 并且获取它的所有的接口(反射获取)
- JDK Proxy 类重新生成一个新的类,实现了被代理类所有接口的方法
- 动态生成java代码,把增加逻辑加入到新生成代码中。
- 编译生成新的java 代码的class文件
- 加载并重新运行新的class ,得到类就是全新的类
public void findJob() {
}
public void eat() {
}
InvocatonHandler
public Object G
aop
日志输出
数据源的切换
cglib proxy
MethodInterceptor {
public Object getInstance(Class<?> clazz) {
Enhancer hancer = new Enhancer();
enhancer.setSuper()
enhance.setCallBack(this)
return enhancer.create();
}
}
public class Customer {
public void findLove(){
}
}
Customer.class
MethodProxy signature
System.setProperty(DebuggomgClassWriter)
cglib FastClass
代理销量更改
jdk采用读取接口的信息
cglib覆盖父类方法
目的:都是生成一个新的类,去实现增强代码逻辑的功能
// JDK Proxy 对用户而言,必须要有一个接口实现,目标类相对来说复杂
// CGLib 可以代理任意一个普通的类,没有任何要求
// CGLib ,生成代理逻辑更复杂,效率,调用效率高,生成一个包含了所有的逻辑的 FastClass,不再需要反射调用
// CGlib 不能代理final的方法
代理模式与spring
ProxyFactoryBean
AOPProxy
CglibAopProxy
JdkDynamicAopProxy
Spring中的代理选择原则
- 当Bean 有实现接口时,Spring就会用 JDK的动态代理
- 当Bean没有实现接口时,Spring选择CGLib.
- Spring可以通过配置强制使用CGLib,只需要在Spring的配置文件中加入如下代码
<aop:aspectj-autoproxy proxy-target-class="true ">
代理模式能将代理对象与真实被调用目标的隔离
一定程度上降低了系统的耦合程度,易于扩张
代理可以起到保护目标对象的作用
增强目标对象的职责
代理模式会造成系统设计中类的数目增加
增加了系统的复杂度