说到代理,我们都知道代理分为静态代理和动态代理两大类。
静态代理
-
优点:代码结构简单,较容易实现
-
缺点:无法适配所有代理场景,如果有新的需求,需要修改代理类,不符合软件工程的开闭原则
静态代理我们以生活实际场景举例说明,下面我们上代码:
//销售化妆品接口
public interface Cosmetic {
void sellCosmetic(double price);
}
//化妆品供货商
public class CosmeticFactory implements Cosmetic {
@Override
public void sellCosmetic(double price) {
System.out.println("销售化妆品,价格为"+price);
}
}
//化妆品代理商(赚差价)
public class CosmeticProxy implements Cosmetic {
private CosmeticFactory factory;
public CosmeticProxy(CosmeticFactory factory){
this.factory = factory;
}
@Override
public void sellCosmetic(double price) {
doBeforeSell();
factory.sellCosmetic(price);
doAfterSell();
}
private void doBeforeSell() {
System.out.println("代理购买化妆品前置操作...");
}
private void doAfterSell() {
System.out.println("代理购买化妆品后置操作...");
}
}
//
public class ProxyTest {
public static void main(String[] args) {
CosmeticFactory cosmeticFactory = new CosmeticFactory();
CosmeticProxy cosmeticProxy = new CosmeticProxy(cosmeticFactory);
cosmeticProxy.sellCosmetic(8888);
}
}
我们可以看到实现代理模式,需要几个步骤:
-
定义真实对象和代理对象的公共接口(Cosmetic)
-
代理对象内部对真实目标对象的引用(引用供货商CosmeticFactory)
-
通过代理对象访问真实目标对象,不可直接访问目标对象
扫描二维码关注公众号,回复: 12376571 查看本文章
为什么要有代理对象?
目的:
-
通过代理对象的隔离,可以在对目标对象访问前后增加额外的业务逻辑,实现功能增强。
-
通过代理对象访问目标对象,可以防止系统大量地直接对目标对象进行不正确地访问,出现不可预测的后果
有了静态代理,为什么还要有动态代理?
动态代理在静态代理的基础上做了改进,提高了程序的可维护性和可扩展性
动态代理
-
优点:能够动态适配特定的代理场景,扩展性较好,符合软件工程的开闭原则
-
缺点:动态代理需要利用到反射机制和动态生成字节码,导致其性能会比静态代理稍差一些,但是相比于优点,劣势几乎可以忽略不计
下面直接上代码:
//动态代理实现InvocationHandler,并实现其invoke()方法
public class DynamicProxy implements InvocationHandler {
private Object realObject;
public DynamicProxy(Object realObject){
this.realObject = realObject;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
doBefore();
Object obj = method.invoke(proxy, args);
doAfter();
return obj;
}
private void doBefore() {
System.out.println("动态代理代理前置操作...");
}
private void doAfter() {
System.out.println("动态代理后置操作...");
}
}
public class ProxyTest {
public static void main(String[] args) {
CosmeticFactory cosmeticFactory = new CosmeticFactory();
DynamicProxy dynamicProxy = new DynamicProxy(cosmeticFactory);
Cosmetic cosmetic = (Cosmetic) Proxy.newProxyInstance(
cosmeticFactory.getClass().getClassLoader(),
cosmeticFactory.getClass().getInterfaces(),
dynamicProxy);
cosmetic.sellCosmetic(9999);
}
}
从代码可以看到InvocationHandler的invoke() 方法有3
个参数:
-
Object proxy
:代理对象 -
Method method
:真正执行的方法 -
Object[] agrs
:调用method 时传入的参数列表
invoke() 方法是一个代理方法,也就是说最后客户端请求代理时,执行的就是该方法。
如何通过代理工厂动态生成代理对象:
生成代理对象需要用到java.lang.reflect.Proxy类,它可以生成任意一个代理对象,里面提供一个静态方法newProxyInstance
。
Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h);
实例化代理对象时,需要传入3
个参数:
-
ClassLoader loader:加载动态代理类的类加载器
-
Class<?>[] interfaces:代理类实现的接口,可以传入多个接口
-
InvocationHandler h:指定代理类的调用处理程序,即调用接口中的方法时,会找到该代理工厂
h
,执行invoke()
方法。
动态代理正是因为满足开闭原则,即面向扩展开放,面向修改关闭。在面对功能需求扩展时,只需要关注扩展的部分,不需要修改系统中原有的代码。
JDK 的动态代理:
(1)JDK 动态代理的使用方法
-
代理工厂需要实现
InvocationHandler
接口,调用代理方法时会执行invoke()
方法 -
生成代理对象需要使用
Proxy
对象中的newProxyInstance()
方法,返回对象可强转成传入的其中一个接口,然后调用接口方法即可实现代理
(2)JDK 动态代理的特点
-
目标对象强制需要实现一个接口,否则无法使用 JDK 动态代理
总结:
静态代理
-
静态代理类:主动创建或者由第三方工具生成,再进行编译;在程序运行之前,代理类的 .class 文件已经存在
-
静态代理事先知道要代理的是什么
-
静态代理类通常只代理一个类
动态代理
-
动态代理通常是在程序运行时,通过
反射机制
动态生成* -
动态代理类通常代理
接口
下的所有类 -
动态代理事先不知道要代理的是什么,只有在运行的时候才能确定*
-
动态代理的调用处理程序必须事先继承 InvocationHandler 接口,使用 Proxy 类中的 newProxyInstance 方法动态的创建代理类*
-
基于接口的动态代理,也叫
JDK动态代理