JDK代理——静态代理、动态代理实战

说到代理,我们都知道代理分为静态代理和动态代理两大类。

静态代理

  • 优点:代码结构简单,较容易实现

  • 缺点:无法适配所有代理场景,如果有新的需求,需要修改代理类,不符合软件工程的开闭原则

静态代理我们以生活实际场景举例说明,下面我们上代码:

//销售化妆品接口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)

  • 通过代理对象访问真实目标对象,不可直接访问目标对象

    扫描二维码关注公众号,回复: 12376562 查看本文章

为什么要有代理对象?

目的

  • 通过代理对象的隔离,可以在对目标对象访问前后增加额外的业务逻辑,实现功能增强。

  • 通过代理对象访问目标对象,可以防止系统大量地直接对目标对象进行不正确地访问,出现不可预测的后果

有了静态代理,为什么还要有动态代理

动态代理在静态代理的基础上做了改进,提高了程序的可维护性和可扩展性

动态代理

  • 优点:能够动态适配特定的代理场景,扩展性较好,符合软件工程的开闭原则

  • 缺点:动态代理需要利用到反射机制和动态生成字节码,导致其性能会比静态代理稍差一些,但是相比于优点,劣势几乎可以忽略不计

下面直接上代码:

//动态代理实现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动态代理

猜你喜欢

转载自blog.csdn.net/feikillyou/article/details/112917529
今日推荐