zoukankan      html  css  js  c++  java
  • Java的动态代理

    何为动态代理:其实Struts2的Action请求也是用动态代理的,比如Action需要调用很多拦截器,但是如果用Action实例去一一调用拦截器,是不是好麻烦,而且代码的耦合度很高吖,那我能不能为每个Action都自动生成一个动态代理对象呢,让这个对象代替Action实例去干活,答案是可以的,
    代理设计模式的原理: 使用一个代理将对象包装起来, 然后用该代理对象取代原始对象. 任何对原始对象的调用都要通过代理. 代理对象决定是否以及何时将方法调用转到原始对象上.

    那怎样实现动态代理呢?

    下面就讲一下具体步骤:
          1建立具体的业务逻辑类
          2建立代理对象类,并把业务逻辑类包裹进来
          3取得需要代理的对象,(一般在构造方法里获取,另外写方法获取也可以)
          4返回代理对象(其实和需要代理的对象时同一个对象,只是名字不一样,不信的话可以测试一下他们hashCode是否一样),
            使用Proxy.newProxyInstance(loader, interfaces, h)方法返回一个代理对象:

    Proxy.newProxyInstance(loader, interfaces, h)参数说明
       loader: 代理对象使用的类加载器。 ClassLoader loader=target.getClass().getClassLoader();
       interfaces: 指定代理对象的类型. 即代理代理对象中可以有哪些方法. Class[] interfaces=new Class[]{HaveproxyObject.class}
       h: 当具体调用代理对象的方法时, 应该如何进行响应, 实际上就是调用 InvocationHandler 的 invoke 方法
     InvocationHandler h=new InvocationHandler() {public Object invoke(Object proxy, Method method, Object[] args){}参数说明
                    proxy: 代理对象。 一般不在invoke方法里不使用该对象,以避免陷入死循环
                    method: 正在被调用的方法,也就SpringAOP所说的连接点,
                    args: 调用方法传入的参数,也就是调用业务逻辑类的方法时传递的参数

          5InvocationHandler的invoke()方法里实现 在调用需要代理的对象(就是业务逻辑类)的方法前后  需要实现的功能
    具体实现代码:

        第一步,建立逻辑类吧:

    package com.jeremy.spring.InvocationHandler;
    
    public class ArithmeticCalculatorImpl implements ArithmeticCalculator {
    
        @Override
        public int add(int i, int j) {
            int result =i+j;
            System.out.println(this.getClass()+"     "+this.hashCode());//只是测试是否为同一个对象
            return result;
        }
    
        @Override
        public int sub(int i, int j) {
            int result =i-j;
            return result;
        }
    
        @Override
        public int mul(int i, int j) {
            int result =i*j;
            return result;
        }
    
        @Override
        public int div(int i, int j) {
            int result =i/j;
            return result;
        }
    
    }

      第二步——第五步:

      

    package com.jeremy.spring.InvocationHandler;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    public class ArithmeticCalculatorProxy {
      //第二步包裹业务逻辑类
    private ArithmeticCalculator target=null; /* * 使用构造方法传递要代理的对象(第三步取得需要代理的对象) */ public ArithmeticCalculatorProxy(ArithmeticCalculator arithmeticCalculator) { this.target=arithmeticCalculator; } /* * 返回代理对象,(第四步取得代理对象,使用Proxy.newProxyInstance()方法)也就是返回ArithmeticCalculator对象,为什么要返回呢?? */ public ArithmeticCalculator getLoggingProxy(){ ArithmeticCalculator proxy = null; ClassLoader loader=target.getClass().getClassLoader(); Class[] interfaces=new Class[]{ArithmeticCalculator.class};
        //第五步使用invacatioHandler的invoke()方法,实现调用业务逻辑类的方法前后需要实现的功能 InvocationHandler h
    =new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object result = null;
                        result = method.invoke(target, args);//Method.invoke():方法就是去执行逻辑类的方法
                    return result;
                }
            };
            /**
             * loader: 代理对象使用的类加载器。 
             * interfaces: 指定代理对象的类型. 即代理代理对象中可以有哪些方法. 
             * h: 当具体调用代理对象的方法时, 应该如何进行响应, 实际上就是调用 InvocationHandler 的 invoke 方法
             */
            
            proxy=(ArithmeticCalculator) Proxy.newProxyInstance(loader, interfaces, h);
            System.out.println(proxy.getClass()+"     "+proxy.hashCode());//只是为 测试是否是同一个对象
            return proxy;
        }
    }

    测试代码:

        @Test
        public void test() {
            ArithmeticCalculator aImpl=new ArithmeticCalculatorImpl();
            aImpl=new ArithmeticCalculatorProxy(aImpl).getLoggingProxy();
            int result=aImpl.add(1, 2);
            System.out.println(result);
        }

    测试结果:

    class $Proxy4 9856161
    class com.jeremy.spring.InvocationHandler.ArithmeticCalculatorImpl 9856161
    3

         

  • 相关阅读:
    18 | 案例篇:内存泄漏了,我该如何定位和处理?
    17 | 案例篇:如何利用系统缓存优化程序的运行效率?
    16 | 基础篇:怎么理解内存中的Buffer和Cache?
    Scrapyd 改进第一步: Web Interface 添加 charset=UTF-8, 避免查看 log 出现中文乱码
    scrapy_redis 相关: 将 jobdir 保存的爬虫进度转移到 Redis
    lxml.etree.HTML(text) 解析HTML文档
    CSS/Xpath 选择器 第几个子节点/父节点/兄弟节点
    scrapy_redis 相关: 查看保存的数据
    scrapy 通过FormRequest模拟登录再继续
    python2 python3 转换,兼容
  • 原文地址:https://www.cnblogs.com/jeremy-blog/p/4026860.html
Copyright © 2011-2022 走看看