文章目录
- Java设计模式之代理模式
- 前言
- 一、代理模式
- 二、使用场景
- 三、静态代理
- 1. 抽象主题类
- 2. 真实主题类
- 3. 代理类
- 4. 客户端
- 四、JDK动态代理
- 1. 抽象主题类
- 2. 真实主题类
- 3. JDK代理工厂
- 4. 客户端
- 五、CGLib代理
- 1. 真实主题类
- 2. CGLib代理工厂
- 3. 客户端
- 总结
- 1. 优点
- 2. 缺点
- 3. Spring中代理选择原则
前言
- 掌握代理模式的应用场景和实现原理
- 了解静态代理和动态代理的区别
- 了解CGLib和JDK Proxy的根本区别
- 手写实现动态代理
一、代理模式
代理模式(Proxy Pattern)是指为其他对象提供一种代理,以控制对这个对象的访问
代理对象在客户端和目标对象之间起到中介作用
根据代理的创建时期,代理模式分为静态代理和动态代理
- 保护目标对象
- 增强目标对象
由程序员创建代理类或特定工具自动生成源代码再对其编译,在程序运行前代理类的 .class 文件就已经存在了。显示声明被代理的对象
/**
* 抽象主题
*/
public interface ISubject {
void request();
}
2. 真实主题类
/**
* 真实主题
*/
public class RealSubject implements ISubject {
@Override
public void request() {
System.out.println("真实主题方法");
}
}
3. 代理类
/**
* 代理类
*/
public class Proxy implements ISubject {
private RealSubject realSubject;
public Proxy(RealSubject realSubject) {
this.realSubject = realSubject;
}
@Override
public void request() {
System.out.println("访问前。。。");
realSubject.request();
System.out.println("访问后。。。");
}
}
4. 客户端
public class Client {
public static void main(String[] args) {
Proxy proxy = new Proxy(new RealSubject());
proxy.request();
}
}
四、JDK动态代理
生成逻辑较为简单,效率较低,底层通过反射方式实现,必须要求代理的目标对象一定要实现一个接口
/**
* 抽象主题
*/
public interface ISubject {
void request();
}
2. 真实主题类
/**
* 真实主题
*/
public class RealSubject implements ISubject {
@Override
public void request() {
System.out.println("真实主题方法");
}
}
3. JDK代理工厂
/**
* 代理工厂
*/
public class ProxyFactory implements InvocationHandler {
private Object target;
public ProxyFactory(Object target) {
this.target = target;
}
public Proxy getTarget() {
return (Proxy) Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("访问前");
Object invoke = method.invoke(target, args);
System.out.println("访问后");
return invoke;
}
}
4. 客户端
public class Client {
public static void main(String[] args) {
ProxyFactory proxy = new ProxyFactory(new RealSubject());
ISubject target = (ISubject) proxy.getTarget();
target.request();
}
}
五、CGLib代理
CGLib效率更高,性能也更高,底层没有用到反射(final修饰的方法无法被代理),采用继承的方式,覆盖父类的方法
1. 真实主题类/**
* 真实主题
*/
public class RealSubject {
public void request() {
System.out.println("真实主题方法");
}
}
2. CGLib代理工厂
/**
* 代理工厂
*/
public class CGLibFactory implements MethodInterceptor {
public Object getTarget(Class> clazz) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("访问前");
Object invoke = methodProxy.invokeSuper(o, objects);
System.out.println("访问后");
return invoke;
}
}
3. 客户端
public class Client {
public static void main(String[] args) {
RealSubject target = (RealSubject) new CGLibFactory().getTarget(RealSubject.class);
target.request();
}
}
总结 1. 优点
- 代理模式能将代理对象与真实被调用的目标对象分离
- 一定程度上降低了系统的耦合程度,易于扩展
- 代理可以起到保护目标对象的作用
- 增强目标对象的职责
- 代理模式会造成系统设计中类的数目增加
- 在客户端和目标对象之间增加了一个代理对象,请求处理速度变慢
- 增加了系统的复杂度
- 当Bean有实现接口时,Spring会JDK动态代理
- 当Bean没有实现接口时,Spring会选择CGLib代理
- Spring可以通过配置强制使用CGLib代理
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)