您的位置 首页 java

JAVA实现代理模式的3种方式

什么是代理模式

代理模式 是项目中常用的一种设计模式。提供了间接访问目标对象的一种方式;即通过代理对象访问目标对象。

这样做的好处是,可以在不改变原有目标对象的基础上,对目标对象增加额外的扩展功能。

代理模式又分为静态代理、 jdk 动态代理、 Cglib 动态代理三种实现方式。

三种实现方式各有优点,以及适用的场景。

一、静态代理

被代理对象与代理对象需要实现相同的接口或者是继承相同父类,因此要定义一个接口或抽象类。

 /**代理接口*/public interface IHello {
    String hi(String key);
}
/**代理接口实现类*/public class HelloImpl implements IHello {
    @Override
    public String hi(String key) {
        String str = "hello:" + key;
        System.out.println("HelloImpl! " + str);
        return str;
    }
}
/**静态代理类*/public class Hello static Proxy implements IHello {

     private  IHello hello;

    public HelloStaticProxy(IHello hello) {
        this.hello = hello;
    }

    @Override
    public String hi(String key) {
        System.out.println(">>> static proxy start");
        String result = hello.hi(key);
        System.out.println(">>> static proxy end");
        return result;
    }
}
/**测试*/public class DemoTest {

    public static  void  main(String[] args) {
        IHello helloProxy = new HelloStaticProxy(new HelloImpl());
        helloProxy.hi("world");
    }
}
  

输出结果

 >>> static proxy start
HelloImpl! hello:world
>>> static proxy end
  

二、jdk动态代理

jdk动态代理是基于接口的一种代理方式,目标对象一定要实现接口。

原理是,利用 反射机制 ,动态生成匿名类继承Proxy类并且实现了要代理的接口,由于 java 不支持多继承,所以JDK动态代理不能代理类

 /**代理接口*/public interface IHello {
    String hi(String key);
}
/**代理接口实现类*/public class HelloImpl implements IHello {
    @Override
    public String hi(String key) {
        String str = "hello:" + key;
        System.out.println("HelloImpl! " + str);
        return str;
    }
}


/**jdk动态代理类*/public class JdkProxy implements InvocationHandler {

    private Object target;

    public JdkProxy(Object target) {
        this.target = target;
    }

    /**
     * 获取被代理接口实例对象
     *
     * @param <T>
     * @return
     */    public <T> T getProxy() {
        return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println(">>> JdkProxy start");
        Object result = method.invoke(target, args);
        System.out.println(">>> JdkProxy end");
        return result;
    }
}

/**测试*/public class Demo2Test {

    public static void main(String[] args) {
        JdkProxy proxy = new JdkProxy(new HelloImpl());
        IHello helloProxy = proxy.getProxy();
        helloProxy.hi(" jdk proxy !");
    }
}
  

输出结果

 >>> JdkProxy start
HelloImpl! hello: jdk proxy !
>>> JdkProxy end
  

三、cglib动态代理

目标对象可以不用实现接口,不能针对 final类 进行代理。

原理是,动态生成class继承目标对象

使用cglib必须引入对应的jar包

  <dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>3.2.7</version>
</dependency>
  
 /**目标类*/public class HelloImpl {
    public String hi(String key) {
        String str = "hello:" + key;
        System.out.println("HelloImpl! " + str);
        return str;
    }
}

/**cglib代理类*/public class CglibProxy implements InvocationHandler {

    private Object target;

    /**
     * 获取被代理接口实例对象
     */    public <T> T getProxy() {
        //1创建增强器对象
        Enhancer e = new Enhancer();
        //2设置增强器的类加载器
        e.setClassLoader(target.getClass().getClassLoader());
        //3设置代理对象父类类型
        e.setSuperclass(target.getClass());
        //4设置 回调函数 
        e.setCallback(this);
        //5创建代理对象
        return (T) e.create();
    }

    public CglibProxy(Object target) {
        this.target = target;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println(">>> cglib start");
        Object obj = method.invoke(target, args);
        System.out.println(">>> cglib end");
        return obj;
    }
}

/**测试*/public class Demo3Test {

    public static void main(String[] args) {
        HelloImpl hello = new HelloImpl();
        CglibProxy cglibProxy = new CglibProxy(hello);
        HelloImpl proxy = cglibProxy.getProxy();
        proxy.hi(" cglib ");
    }
}
  

输出结果

 >>> cglib start
HelloImpl! hello: cglib 
>>> cglib end
  

四、总结

  • 静态代理,代理类必须非常明确,所以无法做到通用,但是效率也是最高的
  • jdk动态代理,必须基于接口代理,有一定局限性;动态生成 字节码 文件,可以用于通用业务(性能日志等)
  • cglig动态代理,也是动态生成字节码文件,生成的代理类继承了目标对象
  • spring aop默认代理策略是:如果目标对象实现了接口,则使用jdk动态代理,否则使用cglib代理
  • jdk8之后,jdk动态代理效率要高于cglib代理

文章来源:智云一二三科技

文章标题:JAVA实现代理模式的3种方式

文章地址:https://www.zhihuclub.com/191417.shtml

关于作者: 智云科技

热门文章

网站地图