zoukankan      html  css  js  c++  java
  • 设计模式-代理模式

    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代理通过反射调用高。

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

    ------愿来生只做陌上的看花人,无须入尘缘,仅行于陌上,看一川风花,无爱无伤-----
  • 相关阅读:
    10 个雷人的注释,就怕你不敢用!
    Java 14 之模式匹配,非常赞的一个新特性!
    poj 3661 Running(区间dp)
    LightOJ
    hdu 5540 Secrete Master Plan(水)
    hdu 5584 LCM Walk(数学推导公式,规律)
    hdu 5583 Kingdom of Black and White(模拟,技巧)
    hdu 5578 Friendship of Frog(multiset的应用)
    hdu 5586 Sum(dp+技巧)
    hdu 5585 Numbers
  • 原文地址:https://www.cnblogs.com/caozz/p/proxy.html
Copyright © 2011-2022 走看看