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

    零、定义

    代理模式,借助代理实现功能。可以理解成中介,厂商通过中介实现销售,房东通过中介出租房子。

    代理模式的定义:给某一个对象提供一个代理,并由代理对象控制对原对象的引用。

    一、角色

    代理模式包含如下角色:
    ISubject:抽象主题角色,是一个接口。该接口是对象和它的代理共用的接口。
    RealSubject:真实主题角色,是实现抽象主题接口的类。
    Proxy:代理角色,内部含有对真实对象RealSubject的引用,从而可以操作真实对象。

    代理对象提供与真实对象相同的接口,以便在任何时刻都能代替真实对象。同时,代理对象可以在执行真实对象操作时,附加其他的操作,相当于对真实对象进行封装。

    二、分类

    静态代理:一个代理类对应一个主题类。

    动态代理:通过反射协助代理,一个代理类可以对应多个主题类。

    而spring的Aop、拦截器就是以动态代理为基础实现的。

    实现动态代理的关键技术是反射。

    动态代理的具体步骤:先实例化代理对象,然后调用代理对象的方法,在代理对象的方法内部,通过反射调用真实对象的方法。

    三、jdk动态代理

    jdk动态代理是java.lang.reflect.*包提供的。。被代理的对象必须是某个接口的实现类。

    jdk动态代理步骤
    1.创建一个实现InvocationHandler接口的处理类,它必须实现invoke()方法

    public Object invoke(Object proxy, Method method, Object[] args)
    • 第一个参数表示代理对象
    • 第二个参数表示当前调度的方法
    • 第三个参数表示调度方法的参数

    2.创建被代理的类及接口
    3.调用Proxy的静态方法,创建一个代理类

    public static Object newProxyInstance(ClassLoader loader,
                                              Class<?>[] interfaces,
                                              InvocationHandler h)

    参数含义:

    • 第一个参数是类加载器ClassLoader
    • 第二个参数是将生成的动态代理对象挂在哪些接口下,这个参数可以设为真实对象所实现的接口。也正是因为这个参数,使用Jdk动态代理的对象必须拥有一个实现的接口,这是jdk动态代理的不足之处。
    • 第三个参数是定义实现逻辑方法的代理类。

    4.通过代理对象调用接口方法时,程序就会进入到invoke()方法里面。

    示例如下:

    UserService.java

    public interface UserService {
        public void getName();
    }

    UserServiceImpl.java

    public class UserServiceImpl implements UserService {
        public void getName() {
            System.out.println("调用真实对象的方法getName()");
        }
    }

    JdkProxyExample.java

    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    public class JdkProxyExample implements InvocationHandler {
        private  Object target=null;
    
        /**
         * 建立代理对象和真实对象的代理关系,并返回代理对象
         * @param target 真实对象
         * @return 代理对象
         */
        public Object getProxyObject(Object target) {
            this.target=target;
            return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
        }
    
        /**
         *  代理方法
         * @param proxy  代理对象
         * @param method 当前调度方法
         * @param args  当前方法参数
         * @return  代理结果
         * @throws Throwable
         */
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("进入代理逻辑方法。");
            System.out.println("在调度真实对象之前的逻辑");
            Object object=method.invoke(target,args);    //这段代码相当于调用真实对象的方法,是通过反射实现的。
            System.out.println("在调度真实对象之后的逻辑");
            return object;
        }
    }

    JdkProxyTest.java

    public class JdkProxyTest {
        public static void main(String[] args) throws NoSuchMethodException {
            JdkProxyExample jdkProxyExample=new JdkProxyExample();
            UserServiceImpl userService=new UserServiceImpl();
            UserService userServiceProxy=(UserService)jdkProxyExample.getProxyObject(userService);
            userServiceProxy.getName();
        }
    }

    运行结果如下:

    进入代理逻辑方法。
    在调度真实对象之前的逻辑
    调用真实对象的方法getName()
    在调度真实对象之后的逻辑

    四、cglib动态代理

     cgLib动态代理的优点是:所代理的对象不需要是某个接口的实现类。像上面举的jdk动态代理例子,UserServiceImpl是UserService的实现类,才可以用jdk动态代理。。这样存在局限性。

    cgLib动态代理的原理,跟jdk动态代理很相似。

    以下使用cgLib的加强者Enhancer,示例如下:

    Order.java如下:

    public class Order {
        public  void getOrder() {
            System.out.println("成功获取Order");
        }
    }

    CgLibProxyExample如下:

    import net.sf.cglib.proxy.Enhancer;
    import net.sf.cglib.proxy.MethodInterceptor;
    import net.sf.cglib.proxy.MethodProxy;
    
    import java.lang.reflect.Method;
    
    public class CgLibProxyExample implements MethodInterceptor {
        /**
         * 生成cgLib代理对象
         * @param cls
         * @return
         */
       public  Object getProxy(Class cls) {
           Enhancer enhancer=new Enhancer();
           //设置增强类型
           enhancer.setSuperclass(cls);
           //定义代理逻辑对象为当前对象。要求当前对象实现MethodInterceptor接口。
           enhancer.setCallback(this);
           //生成并返回代理对象
           return  enhancer.create();
       }
    
        /**
         * 代理逻辑方法。
         * @param o
         * @param method
         * @param args
         * @param methodProxy
         * @return
         * @throws Throwable
         */
        public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
            System.out.println("调用真实对象前。");
            Object result=methodProxy.invokeSuper(o,args);
            System.out.println("调用真实对象后。");
            return result;
        }
    }

     代码示例:

    https://github.com/firefoxer1992/DesignPatternsDemo/tree/master/src/main/java/proxy

    参考资料:

    《Java EE互联网轻量级框架整合开发 SSM框架(Spring MVC+Spring+MyBatis)和Redis实现 》

    http://blog.csdn.net/goskalrie/article/details/52458773

  • 相关阅读:
    在Windows下生成SSH文件
    git常用命令总结
    小Q的歌单
    在vmware下安装Ubuntu16-04
    hexo-next博客中mathjax显示问题解决
    可乐复制问题
    hexo-next博客添加评论功能
    hexo-next博客添加在线联系功能
    tableau desktop
    tableau desktop
  • 原文地址:https://www.cnblogs.com/expiator/p/8394893.html
Copyright © 2011-2022 走看看