美文网首页
java基础-代理模式

java基础-代理模式

作者: dancer4code | 来源:发表于2019-10-20 14:38 被阅读0次

    1.代理模式

    为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。(结构型模式)

    2.优缺点

    优点:

    1. 代理模式能将代理对象与真实对象被调用的目标对象分离。
    2. 一定程度上降低了系统的耦合度,扩展性好。
    3. 保护目标对象。
    4. 增强目标对象。

    缺点:

    1. 代理模式会造成系统设计中类的数目的增加。
    2. 在客户端和目标对象增加一个代理对象,会造成请求处理速度变慢
    3. 增加了系统的复杂度。

    3.代理模式分类

    • 静态代理
    • JDK动态代理
    • CGLIB动态代理

    4.简单实现例子

    静态代理

    用歌手,经纪人的例子举例:


    静态代理.jpg

    静态代理必须实现同一个接口

    代码:

    public interface Sing {
        void singSongs();
    }
    
    //歌手
    public class Singer implements Sing {
        @Override
        public void singSongs() {
            System.out.println("singer can sing songs");
        }
    }
    
    //经纪人
    public class Agent implements Sing {
        private Sing sing = null;
        @Override
        public void singSongs() {
            sing.singSongs();
        }
    
        public Agent(Sing sing) {
            this.sing = sing;
            System.out.println("代理人接收到唱歌邀请");
        }
        public void before(){
            System.out.println("判断是否能去,金钱,时间安排,对歌手有没影响");
        }
        public void after(){
            System.out.println("邀请单位给出评价,相约下次合作");
        }
    }
    
    

    演出开始

    public class Performance {
        public static void main(String[] args) {
            Singer singer = new Singer();
            Agent agent = new Agent(singer);
    
            agent.before();
            agent.singSongs();
            agent.after();
        }
    }
    

    result

    代理人接收到唱歌邀请
    判断是否能去,金钱,时间安排,对歌手有没影响
    singer can sing songs
    邀请单位给出评价,相约下次合作
    

    总结
    从上面的代码中可以看出静态代理类,将代码写死了,如果需要这个代理类代理多个类那么就需要为每个类编写代码,这样做不利于程序的扩展

    JDK动态代理

    JDKAgent

    public class JDKAgent implements InvocationHandler {
    
        private Object target;
    
        public JDKAgent(Object target) {
            this.target = target;
        }
    
        public Object creatAgent(){
            // 1.得到目标对象的类加载器
            ClassLoader classLoader = target.getClass().getClassLoader();
            // 2.得到目标对象的实现接口
            Class<?>[] interfaces = target.getClass().getInterfaces();
            // 3.第三个参数需要一个实现invocationHandler接口的对象
            Object newProxyInstance = Proxy.newProxyInstance(classLoader, interfaces, this);
            return newProxyInstance;
        }
        
        // 第一个参数:代理对象.一般不使用
        // 第二个参数:需要增强的方法
        // 第三个参数:方法中的参数
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            before();
            Object invoke = method.invoke(target, args);
            after();
            return invoke;
        }
    
        public void before(){
            System.out.println("判断此次演出准备工作是否到位");
        }
        public void after(){
            System.out.println("演出是否完美收官");
        }
    }
    
    

    测试类

    public class JDKDemo {
        public static void main(String[] args) {
            Singer singer = new Singer();
            JDKAgent jdkAgent = new JDKAgent(singer);
    
            Sing sing = (Sing)jdkAgent.creatAgent();
            sing.singSongs();
        }
    }
    

    result

    判断此次演出准备工作是否到位
    singer can sing songs
    演出是否完美收官
    

    总结

    • Interface:对于JDK Proxy,业务类是需要一个Interface的,这是一个缺陷;

    • Proxy:Proxy类是动态产生的,这个类在调用Proxy.newProxyInstance()方法之后,产生一个Proxy类的实力。实际上,这个Proxy类也是存在的,不仅仅是类的实例,这个Proxy类可以保存在硬盘上;

    • Method:对于业务委托类的每个方法,现在Proxy类里面都不用静态显示出来

    • InvocationHandler:这个类在业务委托类执行时,会先调用invoke方法。invoke方法在执行想要的代理操作,可以实现对业务方法的再包装。

    CGLIB动态代理

    CGLIB(Code Generation Library)是一个开源项目,是一个强大的,高性能,高质量的Code生成类库,它可以在运行期扩展Java类与实现Java接口。CGLIB包的底层是通过使用一个小而快的字节码处理框架ASM,来转换字节码并生成新的类.如果你要单独使用CGLIB,那么需要导入cglib的jar包还需要一个asm相关jar包,但是spring框架的spring-core.jar包中已经集成了cglib与asm.
    CGLib是针对类来实现代理的,他的原理是对指定的目标生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理.

    注意:
    jdk的动态代理只可以为接口去完成操作,而cglib它可以为没有实现接口的类去做代理,也可以为实现接口的类去做代理

    Dancer

    public class Dancer {
        public void dance(){
            System.out.println("dancer can dance");
        }
    }
    

    代理类

    public class CglibAgent implements MethodInterceptor {
        //得到目标对象
        private Object target;
    
        //使用构造方法传递目标对象
        public CglibAgent(Object target) {
            super();
            this.target = target;
        }
    
        //创建代理对象
        public Object createProxy(){
            //1.创建Enhancer
            Enhancer enhancer = new Enhancer();
            //2.传递目标对象的class
            enhancer.setSuperclass(target.getClass());
            //3.设置回调操作
            enhancer.setCallback(this);
    
            return enhancer.create();
        }
        @Override
        //参数一:代理对象;参数二:需要增强的方法;参数三:需要增强方法的参数;参数四:需要增强的方法的代理
        public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
            // 增强前
            System.out.println("这是增强方法前......");
            Object invoke = methodProxy.invoke(target, args);
            // 增强后
            System.out.println("这是增强方法后......");
            return invoke;
        }
    
    }
    
    

    测试

    public class CglibDemo {
        public static void main(String[] args) {
            Singer singer = new Singer();
            CglibAgent cglibAgent = new CglibAgent(singer);
            Sing sing = (Sing)cglibAgent.createProxy();
            sing.singSongs();
    
            System.out.println("--------separator--------");
    
            Dancer dancer = new Dancer();
            CglibAgent dancerAgent = new CglibAgent(dancer);
            Dancer proxy = (Dancer) dancerAgent.createProxy();
            proxy.dance();
        }
    }
    
    

    result

    这是增强方法前......
    singer can sing songs
    这是增强方法后......
    --------separator--------
    这是增强方法前......
    dancer can dance
    这是增强方法后......
    

    总结

    方式 优点 缺点
    静态代理 简单,需实现统一接口 扩展性差,性能
    JDK动态代理 耦合低,需实现统一接口 性能
    CGLIB动态代理 不需实现统一接口,代理类不能是final 性能

    代码 proxy-demo

    参考
    静态代理、JDK动态代理和CGLIB动态代理之间的区别?
    代理模式

    相关文章

      网友评论

          本文标题:java基础-代理模式

          本文链接:https://www.haomeiwen.com/subject/vqoomctx.html