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

    引言

    我们在写一个功能函数的时候,常常要写入一些与功能无关的代码,如日志记录、参数校验、安全和事务支持等。功能无关代码混在函数中,会带来一些麻烦

    • 对OO造成破坏
    • 加深类之间的耦合
    • 代码重用性降低

    代理模式可以解决这个问题,关键功能代码放在函数中,枝节性代码放在代理类中

    代理模式

    1、作用

    代理模式的作用是,为其他对象提供一种代理,在不改变接口的前提下,以控制对这个对象的访问

    2、角色

    代理模式一般涉及到3个角色:抽象角色(接口)、代理角色、真实(被代理)角色

    3、类型

    静态代理、动态代理(jdk代理、CGLIB代理)

    静态代理

    代理类、被代理类需要实现相同的接口,或者继承相同的父类

    /**
     * Created by danny.yao on 2017/10/9.
     * 静态代理中,代理类和被代理类需要实现此接口
     */
    public interface IUser {
        public void doSomething(String thingsToDo);
    }
     
    /**
     * Created by danny.yao on 2017/10/9.
     * 被代理类,真实业务逻辑
     */
    public class Danny implements IUser {
    
        public void doSomething(String thingsToDo) {
            System.out.println(this.getClass().getName() + "一边唱歌一边" + thingsToDo);
        }
    }
     
    /**
     * Created by danny.yao on 2017/10/9.
     * 代理类,被代理类作为其属性,增强被代理类功能
     */
    public class UserProxy implements IUser {
    
        private IUser user;
    
        public UserProxy(IUser user){
            this.user = user;
        }
    
        // 在不改变danny行为的基础上,增强功能
        public void doSomething(String thingsToDo) {
            doBefore();
            user.doSomething(thingsToDo);
            doAfter();
        }
        private void doBefore(){
            System.out.println("赖床。。。");
            System.out.println("起床洗漱。。。");
            System.out.println("吃早饭。。。");
            System.out.println("然后。。。");
        }
        private void doAfter(){
            System.out.println("那啥之后。。。");
            System.out.println("开始打王者荣耀!");
        }
    }

    测试类

    public class UserProxyTest {
        @Test
        public void testDoSomething(){
            UserProxy dannyProxy = new UserProxy(new Danny());
            dannyProxy.doSomething("上班!!");
        }
    }

    缺点:

    • 被代理类须已经存在,而且作为代理类的内部属性
    • 每个业务类都要一个代理类,如果业务量庞大,会导致类急剧膨胀

    动态代理

    动态代理类的源码是在程序运行期间,由JVM根据反射等机制动态生成的

    1、jdk代理

    被代理类,须实现接口;代理类,不需要实现接口

    // 接口和实现类,同静态代理
     
    public class DynamicProxy implements InvocationHandler {
        // 把静态代理中的类引用,改为Object类型
        private Object object;
    
        public DynamicProxy(Object object){
            this.object = object;
        }
    
        // 把方法调用过程改为反射方式,不依赖接口的具体方法
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            doBefore();
            method.invoke(object, args);
            doAfter();
            return null;
        }
    
        private void doBefore(){
            System.out.println("那啥之前。。。");
        }
        private void doAfter(){
            System.out.println("那啥之后。。。");
        }
    
        // 返回动态代理 newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
        public <T> T getProxy(){
            return (T) Proxy.newProxyInstance(
                  object.getClass().getClassLoader(),
                    object.getClass().getInterfaces(),
                    this
            );
        }
    }

    测试类

    public class DynamicProxyTest {
        @Test
        public void testInvoke() throws Exception {
            DynamicProxy dynamicProxy = new DynamicProxy(new Danny());
            IUser dannyProxy = dynamicProxy.getProxy();
            dannyProxy.doSomething("上班!!");
        }
    }

    缺点:

    • 被代理类必须实现接口

    2、CGLIB代理

    也叫作子类代理,它是在内存中构建一个子类对象,从而实现对目标对象功能的扩展。被代理类不需要实现接口

    // 未实现接口的类
    public class Pig {
        public void doSomething(String thingsToDo){
            System.out.println("懒洋洋地" + thingsToDo);
        }
    }
     
    public class CGLibProxy implements MethodInterceptor {
    
        public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
            doBefore();
            Object result = methodProxy.invokeSuper(o, args);
            doAfter();
            return result;
        }
        // cglib 中通过加强器来创建代理
        public <T> T getProxy(Class<T> tClass){
            return (T) Enhancer.create(tClass, this);
        }
        private void doBefore(){
            System.out.println("那啥之前。。。");
        }
        private void doAfter(){
            System.out.println("那啥之后。。。");
        }
    }

    测试类

    public class CGLibProxyTest {
        @Test
        public void testIntercept() throws Exception {
            CGLibProxy cgLibProxy = new CGLibProxy();
            Pig pigProxy = cgLibProxy.getProxy(Pig.class);
            pigProxy.doSomething("思考人生。。。");
        }
    }

    缺点:

    • 会拦截并包装被代理类的所有方法,做不到方法级别的个性化拦截

    参考:

    https://www.zhihu.com/question/20794107

    http://www.cnblogs.com/machine/archive/2013/02/21/2921345.html

    http://www.cnblogs.com/cenyu/p/6289209.html

  • 相关阅读:
    联赛膜你测试20 T1 Simple 题解 && NOIP2017 小凯的疑惑 题解(赛瓦维斯特定理)
    P5518
    快速除法 / 取模
    P6860
    spoj LCMSUM
    虚树 学习笔记
    长链剖分 学习笔记
    CF526G
    P4292
    01 分数规划(water)
  • 原文地址:https://www.cnblogs.com/dannyyao/p/7642452.html
Copyright © 2011-2022 走看看