美文网首页web框架中用到的设计模式专题
设计模式之代理模式(JDK及CGlib)

设计模式之代理模式(JDK及CGlib)

作者: 先生zeng | 来源:发表于2019-06-04 00:22 被阅读0次

代理模式


image.png

因为接下去将会看spring方面的源码,所以就把这些常用的先更新下,完整笔记在我git上,需要的可以私信我。

概念: 代理模式是JAVA常用的设计模式之一,代理模式不直调用代理对象,而是通过对象的代理类来处理,就像是中介、黄牛、经纪人,代理模式又分为静态代理和动态代理

代理对象:面向调用者,在调用者和被代理对象之间作为隔离层加以控制,可以增强被代理对象的方法。

被代理对象:真正的执行者,需要对代理对象暴露

下面以歌手-Singer 经纪公司-Agent为例分析几种代理模式

静态代理

何为静态?其实就是在编码阶段,写好代理类,然后编译运行,在程序运行前,代理类已经存在。


image.png

代码理解如下:
Person类: 被代理和代理类需要实现的抽象接口

public interface Person {
    void doSomething();
}

Agent 类: 代理类,这里作为歌手的代理为经济公司

public class Agent implements Person {

    private Person target;

    public Person getProxyInstance(Person target){
        this.target=target;
        return target;
    }

    @Override
    public void doSomething() {
        System.out.println("经纪公司,接收演出");
        target.doSomething();
        System.out.println("经济公司,开始收钱");
    }
}

歌手类: 被代理的对象

public class Single implements Person {

    @Override
    public void doSomething() {
        System.out.println("开始准备演唱会。。。。唱歌");
    }
}

测试类

public class Test {

    public static void main(String[] args) {
        Person proxy=new Agent().getProxyInstance(new Single());
        proxy.doSomething();
    }
}

结果:


image.png

动态代理

相对于静态代理,动态代理的代理类是在运行时生成,动态代理在实现上又有两种,分别是jdk动态代理和cglib动态代理。

JDK动态代理

​ JDK动态代理要求被代理对象必须实现接口,其原理是代理对象实现该接口的方法,同时调用被代理对象的方法。将生成后的代理对象,强制转换为接口被调用者调用。

​ Agent类没有直接实现Person接口,而是通过反射生成字节码文件的方式,动态生成真正的代理类,那么生成的代理类内部具体细节是怎样的?写个方法输出代理类object.

JDK动态代理的原理如下:

//原理:
            //1、拿到被代理对象的引用,并且获取到它的所有的接口,反射获取
            //2、JDK Proxy类重新生成一个新的类、同时新的类要实现被代理类所有实现的所有的接口
            //3、动态生成Java代码,把新加的业务逻辑方法由一定的逻辑代码去调用(在代码中体现)
            //4、编译新生成的Java代码.class
            //5、再重新加载到JVM中运行
            //以上这个过程就叫字节码重组

            //JDK中有个规范,只要要是$开头的一般都是自动生成的

            //通过反编译工具可以查看源代码
            byte [] bytes = ProxyGenerator.generateProxyClass("$Proxy0",new Class[]{Person.class});
            FileOutputStream os = new FileOutputStream("E://$Proxy0.class");
            os.write(bytes);
            os.close();

代码理解如下:
Person类: 被代理和代理类需要实现的抽象接口

public interface Person {
    void doSomething();
}

Agent 类: 代理类,这里作为歌手的代理为经济公司

public class Agent implements InvocationHandler {

    private Person target;

    public Object getProxyInstance(Person target) {
        this.target = target;
        return  Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("经纪公司接单:");
        method.invoke(target,args);
        System.out.println("经纪公司:演出完了,收钱");
        return null;
    }

歌手类: 被代理的对象

public class Singer implements Person {

    public Singer() {
    }

    @Override
    public void doSomeThing() {
        System.out.println("歌手,负责唱歌");
    }
}

客户端类

public class Client {

    public static void main(String[] args) {
        //返回的是singer的代理类
        Person singer = (Person) new Agent().getProxyInstance(new Singer());
        singer.doSomeThing();
    }
}

结果:


image.png

cglib动态代理

与JDK动态代理不同的是,cglib代理不强制被代理类实现接口,它是通过生成代理类的子类,并重写代理类方法来实现的,所以代理类不能用final修饰.
Person类: 被代理和代理类需要实现的抽象接口

public interface Person {
    void doSomething();
}

Agent 类: 代理类,这里作为歌手的代理为经济公司

public class Agent implements MethodInterceptor {

    private Person target;

    public Object getProxyInstance(Object target){
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(target.getClass());
        enhancer.setCallback(this);
        return enhancer.create();
    }
@Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {

        System.out.println("经纪公司:接单");
        methodProxy.invokeSuper(o,objects);
        System.out.println("经纪公司收钱:");
        return null;
    }
}

歌手类: 被代理的对象

public class Singer implements Person {

    @Override
    public void doSomeThing() {
        System.out.println("歌手,负责唱歌");
    }
}

测试类

public class Client {

    public static void main(String[] args) {
        Singer singer = (Singer) new Agent().getProxyInstance(new Singer());
        singer.doSomeThing();
    }
}

结果:

应用场景

代理模式随处可见,最常见的是spring的AOP,比如spring的事务代理,在对数据进行操作时会涉及事务开启、事务提交、事务回滚等操作,简化的数据操作模型如下图:

image.png

业务场景中存在大量的事务操作(红色),而这些往往不是开发者的关注点,开发者更注重于业务逻辑(蓝色)。因此代理模式可以增强业务逻辑代码,在事务执行前开启事务,在事务执行后进行回滚/提交/关闭。

总结

  1. 静态代理需要编写代理类,动态代理不需要;
  2. 静态代理在无需修改被代理类的前提下,对代理类进行增强和扩展,但是静态代理只能对一个被代理类服务,如果被代理类过多,就会产生相应数量的代理类实现与被代理类一致的接口,产生冗余,不易维护;
  3. JDK动态代理只要求代理类实现InvocationHandler接口,被代理类实现业务接口即可。
  4. 静态代理编译时生成的class的性能高于JDK动态代理通过反射生成class;
  5. cglib不要求被代理类实现接口,而是通过继承的方式实现,因此类和方法都不能用final修饰。cglib底层用高性能的字节码生成器,性能高于反射。

感谢您阅读我的文章,如果满意可以帮我点赞,谢谢哈。
如果对文章部分还有什么见解或者疑惑,可以私信评论我,欢迎技术讨论。如果需要获取完整的文件资源,可以加我微信z985085305,获取我整理的全套笔记。
思想的碰撞最能促进技术的进步哦。

相关文章

  • 设计模式之代理

    设计模式之代理模式 一、定义 在Java中代理的实现一般分为三种:JDK静态代理、JDK动态代理以及CGLIB动态...

  • java动态代理(JDK和cglib)(转载自http://ww

    java动态代理(JDK和cglib) JAVA的动态代理 代理模式 代理模式是常用的java设计模式,他的特征是...

  • 设计模式之代理模式(JDK及CGlib)

    代理模式 因为接下去将会看spring方面的源码,所以就把这些常用的先更新下,完整笔记在我git上,需要的可以私信...

  • java程序的性能优化(二)

    善用设计模式 单例模式:各类写法,反序列化破坏单例 代理模式:jdk接口代理,asm代理,cglib,javass...

  • Spring之使用XML配置Spring AOP

    1.aop的原理 Spring AOP底层主要使用了JDK动态代理和cglib动态代理。具体可看文章设计模式之代理...

  • 设计模式

    单例模式 代理模式 静态代理 jdk动态代理 cglib动态代理 工厂模式 适配器模式 建造者模式 观察者模式

  • 代理

    《转》JAVA动态代理(JDK和CGLIB) 代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接...

  • JAVA代理模式深入了解(一)

    目前学习阶段,有问题请帮忙指出,谢谢 代理模式有三种: 静态代理模式 jdk动态代理模式 cglib动态代理模式 ...

  • Java 代理

    静态代理 动态代理 JDK 提供的Proxy CGLib cglib | GitHub 参考文章 Java的三种代理模式

  • Spring AOP原理

    1,设计:代理模式,责任连模式2,实现:JDK实现,cglib实现3,织入的时机:1)编译期:AspectJ2)类...

网友评论

    本文标题:设计模式之代理模式(JDK及CGlib)

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