zoukankan      html  css  js  c++  java
  • 代理模式详解

           
            代理模式为对象提供一个代理以控制对这个对象的访问。所谓代理,是指与代理元(即:被代理的对象)具有相同接口的类,客户端必须通过代理与代理元进行交互。我们可以将代理理解成另一个对象的代表
            代理(proxy)模式本质上就是通过一个代理对象访问目标对象,而不直接访问目标对象;代理模式可以在不修改被代理对象的基础上,通过扩展代理类,进行一些功能的附加与增强。这么做的好处是,可以让目标对象只关注业务逻辑,而非业务逻辑(比如日志输出等)可以在代理对象中实现,实现业务分离。
    代理模式要点:
    • 代理模式包含三个要素:1)接口/Interface; 2)代理元/Target:即被代理的对象; 3)代理类/Proxy:代理元的代表,对外提供访问;
    • 代理元与代理类都是接口的实现类;
    • 客户端只能访问代理类,无法直接访问代理元;

    代理分为静态代理和动态代理。


    静态代理

     
            静态代理就是在编译时生成代理类。即:通过编码手动创建代理类,并在代理类中调用代理元。
     
    编码实现
     
    1.接口
    package effectiveJava.proxy;
    
    public interface HelloService {
        void sayHello();
    }

    2,代理元

    package effectiveJava.proxy;
    
    public class HelloServiceImpl implements HelloService{
        @Override
        public void sayHello() {
            System.out.println("Hello Proxy.");
        }
    }

    3,代理类

    package effectiveJava.proxy.staticProxy;
    
    import effectiveJava.proxy.HelloService;
    
    public class LogProxy implements HelloService {
    
        private HelloService service;
    
        public LogProxy(HelloService service) {
            this.service = service;
        }
    
        @Override
        public void sayHello() {
            System.out.println("Static Proxy : Before Hello....");
            service.sayHello();
            System.out.println("Static Proxy : After Hello....");
        }
    }

    4,测试类

    package effectiveJava.proxy.staticProxy;
    
    import effectiveJava.proxy.HelloServiceImpl;
    
    public class LogProxyDemo {
        public static void main(String[] args) {
            LogProxy logProxy = new LogProxy(new HelloServiceImpl());
            logProxy.sayHello();
        }
    }

    5,测试结果

    Static Proxy : Before Hello....
    Hello Proxy.
    Static Proxy : After Hello....

    动态代理


            动态代理地实现有两种方式:1)基于JDK的动态代理;2)基于CGLIB的动态代理;

    1)基于JDK的动态代理

    API

    public class Proxy implements java.io.Serializable {
         /**
       * 创建代理实例
          *  @param loader 代理元的类加载器
          *  @param interfaces 代理元的接口
          *  h 一个 InvocationHandler 对象
          */
         
       public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h);
    
    }
    /**
     *
     * 每个代理的实例都有一个与之关联的 InvocationHandler 实现类,
     * 如果代理的方法被调用,那么代理便会通知和转发给内部的 InvocationHandler 实现类,由它决定处理。
     */
    public interface InvocationHandler {
    
        public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable;
    }

    编码实现

    1,接口、代理元(编码与静态代理一致,不再赘述)
    2,代理类(必须实现InvocationHandler接口)
    package effectiveJava.proxy.v0;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    
    public class HelloInvocation implements InvocationHandler {
        /**
         * 代理元
         */
        private Object target;
    
        public HelloInvocation(Object target) {
            this.target = target;
        }
    
        /**
         *
         * @param proxy 代理类实例
         * @param method 实际要调用的方法
         * @param args  实际要调用方法的参数类型
         * @return 结果值
         * @throws Throwable
         */
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("HelloInvocation : Before Hello....");
            Object reslut = method.invoke(target, args);
            System.out.println("HelloInvocation : After Hello....");
            return reslut;
        }
    
    }

    3,测试类

    package effectiveJava.proxy.v0;
    
    import effectiveJava.proxy.HelloService;
    import effectiveJava.proxy.HelloServiceImpl;
    
    import java.lang.reflect.Proxy;
    
    /**
    * 通过Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)创建代理对象的实例
    */
    public class HelloInvocationDemo {
        public static void main(String[] args) {
            HelloServiceImpl helloService = new HelloServiceImpl();
            HelloInvocation helloInvocation = new HelloInvocation(helloService);
            HelloService impl = (HelloService)Proxy.newProxyInstance(
                    helloService.getClass().getClassLoader(),
                    helloService.getClass().getInterfaces(),
                    helloInvocation);
            impl.sayHello();
        }
    }

    4,测试结果

    HelloInvocation : Before Hello....
    Hello Proxy.
    HelloInvocation : After Hello....

    2)基于CGLIB的动态代理

       Cglib是基于继承的方式进行代理,代理类去继承目标类,每次调用代理类的方法都会被方法拦截器拦截,在拦截器中才是调用目标类的该方法的逻辑。因此,基于CGLIB的动态代理不需要接口。

    编码实现

    1,引入架包

    <dependency>
        <groupId>cglib</groupId>
        <artifactId>cglib</artifactId>
        <version>2.2.2</version>
    </dependency>
    2,代理类(HelloServiceImpl.java,编码与静态代理一致)
     3, 方法拦截器
    package effectiveJava.proxy.cglib;
    
    import net.sf.cglib.proxy.MethodInterceptor;
    import net.sf.cglib.proxy.MethodProxy;
    
    import java.lang.reflect.Method;
    
    public class LogInterceptor implements MethodInterceptor {
        @Override
        public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
            System.out.println("Cglib : Before hello..."); 
            //调用父委方法
            Object result = methodProxy.invokeSuper(object, args);
            System.out.println("Cglib : After hello...");
            return result;
        }
    }

    4,测试类

    package effectiveJava.proxy.cglib;
    
    import effectiveJava.proxy.HelloService;
    import effectiveJava.proxy.HelloServiceImpl;
    import net.sf.cglib.proxy.Enhancer;
    
    public class CglibDemo {
        public static void main(String[] args) {
            //创建Enhancer对象,类似于JDK动态代理的Proxy类
            Enhancer enhancer = new Enhancer();
            //设置父类
            enhancer.setSuperclass(HelloServiceImpl.class);
            //设置回调函数(拦截器)
            enhancer.setCallback(new LogInterceptor());
            //创建代理类实例
            HelloService service = (HelloService)enhancer.create();
            service.sayHello();
        }
    }

    5,测试结果

    Cglib : Before hello...
    Hello Proxy.
    Cglib : After hello...
    总结:
    • 静态代理是在编译时创建代理,动态代理是在运行时创建代理;
    • JDK动态代理是基于接口的方式,CGLib动态代理是基于继承;
     
     
  • 相关阅读:
    Eclipse '《》'operator is not allowed for source level below 1.7
    eclipse怎么在包里建一个包
    java jdk environment variables
    甲骨文中国 / Oracle 提供的技术资源
    在Eclipse中使用log4j配置实例听
    StringBuilder的常用方法
    mediasoup-demo公网安装部署
    使用NodeJs新建一个https服务器,并可以发布静态资源
    使用shell脚本批量执行adb命令,卸载安装apk
    这 5 个前端组件库,可以让你放弃 jQuery UI
  • 原文地址:https://www.cnblogs.com/BlueStarWei/p/14021066.html
Copyright © 2011-2022 走看看