• 设计模式-代理模式


    7、代理模式
    代理模式是指为其他对象提供一种代理,以控制对这个对象的访问,属于结构型模式。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
    代理模式一般包含三种角色:
    抽象主题角色(Subject):抽象主题类的主要职责是声明真实主题与代理的共同接口方法,该类可以是接口也可以是抽象方法。
    真实主题角色(RealSubject):该类也被称为被代理类,该类定义了代理所表示的真实对象,是负责执行系统真正的业务逻辑对象。
    代理主题角色Proxy:也被称为代理类,其内部有RealSubjuct的引用,因此具备完全的对RealSubject的代理权。客户端调用代理对象的方法,但是会在代理对象前后增加一些处理代码。

    代理模式的通用写法:

    package com.jdwa.nomalproxy;
    
    public interface ISubject {
        void request();
    }
    
    package com.jdwa.nomalproxy;
    
    public class RealSubject implements ISubject{
        @Override
        public void request() {
            System.out.println("real service is called ");
        }
    }
    
    
    package com.jdwa.nomalproxy;
    
    public class Proxy implements ISubject {
    
        private ISubject subject;
    
        public Proxy(ISubject subject){
            this.subject = subject;
        }
    
    
        @Override
        public void request() {
            before();
            subject.request();
            after();
        }
    
        private void before(){
            System.out.println("called before real service ...");
        }
    
        private void after(){
            System.out.println("called after real service ...");
        }
    
    }
    
    package com.jdwa.nomalproxy;
    
    public class Client {
        public static void main(String[] args) {
            ISubject subject = new RealSubject();
            Proxy proxy = new Proxy(subject);
            proxy.request();
        }
    
    }
    

    从静态代理带动态代理:

    package com.jdwa.staticproxy;
    
    public interface IPerson {
        void findLove();
    }
    
    package com.jdwa.staticproxy;
    
    public class Tom implements IPerson {
        @Override
        public void findLove() {
            System.out.println("must be a beautiful girl");
        }
    }
    
    package com.jdwa.staticproxy;
    
    public class TomFather implements IPerson {
    
        private IPerson tom;
    
        public TomFather(IPerson tom){
            this.tom = tom;
        }
        @Override
        public void findLove() {
            before();
            tom.findLove();
            after();
        }
    
        private void before(){
            System.out.println("find a suitable girl ...");
        }
    
        private void after(){
            System.out.println("Get ready to be together ...");
        }
    }
    
    package com.jdwa.staticproxy;
    
    public class Client {
        public static void main(String[] args) {
            IPerson tom = new Tom();
            IPerson tomFather = new TomFather(tom);
            tomFather.findLove();
        }
    }
    

    动态代理

    package com.jdwa.staticproxy;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    public class MatchMarker implements InvocationHandler {
    
        private IPerson target;
    
        public IPerson getInstance(IPerson target){
            this.target = target;
            Class<?> clazz = target.getClass();
            return (IPerson) Proxy.newProxyInstance(clazz.getClassLoader(),clazz.getInterfaces(),this);
        }
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            before();
            Object result = method.invoke(this.target,args);
            after();
            return result;
        }
    
        private void before(){
            System.out.println("I'm matchmarker,I hava already collect your infomation ,start to look for");
        }
    
        private void after(){
            System.out.println("They are very satisfied with each other");
        }
    }
    
    

    测试

    package com.jdwa.staticproxy;
    
    public class Client {
        public static void main(String[] args) {
    //        IPerson tom = new Tom();
    //        IPerson tomFather = new TomFather(tom);
    //        tomFather.findLove();
    
            MatchMarker matchMarker = new MatchMarker();
            IPerson tom = matchMarker.getInstance(new Tom());
            tom.findLove();
        }
    }
    

    这就是JDK自带的动态代理实现。
    我们都知道jdk动态代理采用字节重组,重新生成对象来代替原始对象,以达到动态代理的目的。jdk动态代理生成对象的步骤如下:
    a、获取被代理对象的引用,并获取他的所有接口,反射获取。
    b、jdk动态代理类重新生成一个新的类,同时新的类要实现被代理类实现的所有接口
    c、动态生成Java代码新加的业务逻辑方法由一定的逻辑代码调用
    d、编译新生成的Java代码,得到class
    e、重新加载到JVM中运行

    我们通过将内存中的对象字节码输出,然后反编译,可以查看代理对象的源代码。

    package com.jdwa.staticproxy;
    
    import sun.misc.ProxyGenerator;
    
    import java.io.FileOutputStream;
    
    public class Client {
        public static void main(String[] args) throws Exception{
    //        IPerson tom = new Tom();
    //        IPerson tomFather = new TomFather(tom);
    //        tomFather.findLove();
    
    //        MatchMarker matchMarker = new MatchMarker();
    //        IPerson tom = matchMarker.getInstance(new Tom());
    //        tom.findLove();
            
            IPerson person = new MatchMarker().getInstance(new Tom());
            person.findLove();
            byte[] bytes = ProxyGenerator.generateProxyClass("$Proxy0",new Class[]{IPerson.class});
            FileOutputStream fos = new FileOutputStream("E://$Proxy0.class");
            fos.write(bytes);
            fos.close();
        }
    }
    

    通过源代码我们可以发现$Proxy0类继承了Proxy类,同时还实现了IPerson接口,重写了findLove方法。在静态块中用反射查找了目标 对象的所有方法,而且保存了所有方法的引用,重写的方法用反射调用目标对象的方法。这些代码,都是jdk帮我们自动生成的。

    CGLIB实现

    package com.jdwa.staticproxy;
    
    
    import org.springframework.cglib.proxy.Enhancer;
    import org.springframework.cglib.proxy.MethodInterceptor;
    import org.springframework.cglib.proxy.MethodProxy;
    
    import java.lang.reflect.Method;
    
    public class CGLibMatchMarker implements MethodInterceptor {
    
        public Object getInstance(Class<?> clazz) throws Exception{
            Enhancer enhancer = new Enhancer();
            enhancer.setSuperclass(clazz);
            enhancer.setCallback(this);
    
            return enhancer.create();
        }
    
        @Override
        public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
            before();
            Object obj = methodProxy.invokeSuper(o,objects);
            after();
            return obj;
        }
    
        private void before(){
            System.out.println("cglib ----I'm matchmarker,I hava already collect your infomation ,start to look for");
        }
    
        private void after(){
            System.out.println("cglib ----They are very satisfied with each other");
        }
    }
    
    
    package com.jdwa.staticproxy;
    
    import sun.misc.ProxyGenerator;
    
    import java.io.FileOutputStream;
    
    public class Client {
        public static void main(String[] args) throws Exception{
    //        IPerson tom = new Tom();
    //        IPerson tomFather = new TomFather(tom);
    //        tomFather.findLove();
    
    //        MatchMarker matchMarker = new MatchMarker();
    //        IPerson tom = matchMarker.getInstance(new Tom());
    //        tom.findLove();
    
    //        IPerson person = new MatchMarker().getInstance(new Tom());
    //        person.findLove();
    //        byte[] bytes = ProxyGenerator.generateProxyClass("$Proxy0",new Class[]{IPerson.class});
    //        FileOutputStream fos = new FileOutputStream("E://$Proxy0.class");
    //        fos.write(bytes);
    //        fos.close();
    
            Tom tom = (Tom) new CGLibMatchMarker().getInstance(Tom.class);
            tom.findLove();
    
        }
    }
    
    
    
    

    cglib的执行效率要高于jdk的,就是因为CGLib采用了FastClass机制,他的原理简单来说就是:为代理类和被代理类各生成一个类,这个类会为代理类和被代理类的方法分配一个INDEX(int类型);这个INDEX当作一个入参,FastClass就可以直接定位要调用的方法并直接进行调用,省去了反射调用,所以调用效率比JDK代理通过反射调用高。

    欢迎大家留言,以便于后面的人更快解决问题!另外亦欢迎大家可以关注我的微信公众号,方便利用零碎时间互相交流。共勉!

    ------愿来生只做陌上的看花人,无须入尘缘,仅行于陌上,看一川风花,无爱无伤-----
  • 相关阅读:
    [openjudge] jubeeeeeat
    [BJOI2006] 狼抓兔子
    [模板]网络最大流
    [HNOI2002]营业额统计
    【Java学习笔记之十一】Java中常用的8大排序算法详解总结
    【Java学习笔记之十】Java中循环语句foreach使用总结及foreach写法失效的问题
    【Java学习笔记之九】java二维数组及其多维数组的内存应用拓展延伸
    【Java学习笔记之八】JavaBean中布尔类型使用注意事项
    【Java学习笔记之七】java函数的语法规则总结
    二分图匹配--匈牙利算法模板
  • 原文地址:https://www.cnblogs.com/caozz/p/proxy.html
Copyright © 2020-2023  润新知