zoukankan      html  css  js  c++  java
  • java设计模式(五)——代理模式

    1、基本概念

    为其他对象提供一种代理,来控制这个对象的访问,属于结构型的模式,实现代码增强的功能。

    生活场景:如婚恋介绍所,黄牛,租房

    应用场景:如spring中的aop

    2、代理类型

    静态代理和动态代理

    动态代理又有cglib和jdk的动态代理。

    2.1、静态代理

    案例:父亲给儿子相亲:

    类图:

    接口:相亲人员

    public interface IblindDatePerson {

    void blindDate();
    }

    被代理对象:儿子

    public class Wangwu implements IblindDatePerson {
    
        @Override
        public void blindDate() {
            System.out.println("我的要求是:女的,活的");
        }
    
    }

    代理对象:父亲

    public class LaoWang implements IblindDatePerson {
        private IblindDatePerson wangwu;
    
        public LaoWang(IblindDatePerson wangwu){
            this.wangwu = wangwu;
        }
        @Override
        public void blindDate() {
            before();
            wangwu.blindDate();
            after();
    
        }
        private void before() {
            System.out.println("开始替儿子王五在相亲公园寻找");
        }
    
        private void after() {
            System.out.println("儿子王五的相亲对象找到了");
        }
    }

    测试类:

    public class Test {
        public static void main(String[] args) {
    
            IblindDatePerson iperson = new LaoWang(new Wangwu());
            iperson.blindDate();
    
        }
    }

    输出:

    开始替儿子王五在相亲公园寻找
    我的要求是:女的,活的
    儿子王五的相亲对象找到了

    从上面案例可以看到,我们代理的是同一类型的对象,即相亲对象,如果是别的人员,就无法代理,这就是静态代理。那么动态

    代理,就可以代理任何的对象。

     2.2、动态代理

     动态代理采用在运行时动态生成代码的方式,取消了对被代理类的扩展限制,遵循开闭原则

    1、基于JDK动态代理

    被代理的类需要继承统一接口

    案例:类图

     接口:

    public interface IblindDatePerson {
    
        void  blindDate();
    
    }

    被代理类:

    public class Zhangsan implements IblindDatePerson {
        @Override
        public void blindDate() {
            System.out.println("我的要求是:女的,活的");
        }
    }

    代理类:实现InvocationHandler 接口

    public class LaoWangJdkproxy implements InvocationHandler {
    
        private Object target;
    
        public Object getProxyInstance(Object target){
            this.target = target;
            Class<?> clazz =  target.getClass();
            return 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("开始替儿子王五在相亲公园寻找");
        }
    
        private void after() {
            System.out.println("儿子王五的相亲对象找到了");
        }
    }

    测试类:

    public class Test {
        public static void main(String[] args) {
            IblindDatePerson iperson  = (IblindDatePerson)new LaoWangJdkproxy().getProxyInstance(new Zhangsan());
            iperson.blindDate();
        }
    }

    输出:

    开始替儿子王五在相亲公园寻找
    我的要求是:女的,活的
    儿子王五的相亲对象找到了

    这里的重点就是这个代理类了,它需要实现InvocationHandler 接口

        private Object target;
      //对外提供一个获取代理对象的方法,target是传入被代理的类
        public Object getProxyInstance(Object target){
            this.target = target;
            Class<?> clazz =  target.getClass();
            return Proxy.newProxyInstance(clazz.getClassLoader(),clazz.getInterfaces(),this);
        }
    生成代理类的关键方法:需要传入三个参数:target的类加载器,target的所有接口,当前对象
    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;
        }

    这个是基于Jdk的动态代理。

    2、基于cglib的动态代理

    被代理的类不需要继承统一接口

    它需要导入一个cglib包

     <dependency>
                <groupId>cglib</groupId>
                <artifactId>cglib-nodep</artifactId>
                <version>2.2</version>
            </dependency>

    类图:

     代理类:实现MethodInterceptor 接口

    public class LaoWangCglibProxy implements MethodInterceptor {
    
       public Object getProxyInstance(Class<?> clazz) throws Exception{
           Enhancer enhancer = new Enhancer();
           enhancer.setSuperclass(clazz);
           enhancer.setCallback(this);
           return  enhancer.create();
       }
    
        @Override
        public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
            before();
            Object ob = method.invoke(obj,args);
            after();
            return ob;
        }
    
        private void before() {
            System.out.println("开始替儿子王五在相亲公园寻找");
        }
    
        private void after() {
            System.out.println("儿子王五的相亲对象找到了");
        }
    }

    以上就是两种动态代理的实现

    动态代理相比静态代理的优点:

    1、静态代理只能手动代理:如果我们新增一个一种情况,我们就需要新增一个代理对象,例如:

    我们新增一个狗类,有个实现类二哈

    public interface IDog {
    
        void play();
    }
    public class ErhaDog implements IDog {
        @Override
        public void play() {
            System.out.println("二哈在拆家。。。");
        }
    }

    如果静态代理就需要新增一个代理类,去处理狗相关的代理

    如果是动态代理就不需要了,我们测试方法里,直接把ErhaDog对象传过去,即可生成代理对象 

    结合策略模式,即可很好的进行扩展。

    2、如果被代理对象新增一个方法,那么代理类就需要新增一个代理类去处理,而动态代理不需要。

    3、动态代理采用在运行时动态生成代码的方式,取消了对被代理类的扩展限制,遵循开闭原则

  • 相关阅读:
    Sprng Data JPA与hibernate的关系
    Exception in thread "main" java.io.FileNotFoundException: d:xxx.txt (拒绝访问。)
    Telnet测试BIO Socket
    计算机网络篇
    Postman测试接口发现时间少8个小时?添加这两行代码就解决!
    匿名内部类
    解决线程安全的三种方法
    equals和hashcode的区别
    postman测试springsecurity 登录鉴权,获取Cookie后进行其他接口测试
    (链表)求相交链表交点
  • 原文地址:https://www.cnblogs.com/tdyang/p/13253961.html
Copyright © 2011-2022 走看看