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动态代理是基于继承;
     
     
  • 相关阅读:
    将PHP文件生成静态文件源码
    Entity Framework Code First 学习日记(6)一对多关系
    Entity Framework Code First 学习日记(5)
    Entity Framework Code First 学习日记(3)
    Entity Framework Code First 学习日记(7)多对多关系
    Entity Framework Code First学习日记(2)
    Entity Framework Code First 学习日记(8)一对一关系
    Entity Framework Code First 学习日记(9)映射继承关系
    Entity Framework Code First 学习日记(10)兼容遗留数据库
    Entity Framework Code First 学习日记(4)
  • 原文地址:https://www.cnblogs.com/BlueStarWei/p/14021066.html
Copyright © 2011-2022 走看看