反射(三) Proxy 代理

java.lang.reflect.Proxy类提供了用于获取和操作代理的静态方法。

1.通过Proxy可以做什么
通过Proxy可以做以下事情:如何通过new方法为一个接口创建动态代理实例?
如何获取一个代理实例的调用处理器(InvocationHandler)?如何通过调用处理器(InvocationHandler)调用方法?
如何判断一个类是否是代理类?
如何获取一个代理类?
如何通过代理的构造器创建动态代理实例?
2.代理相关
通过Proxy代理类的静态方法,可以为接口创建动态代理实例。
通过代理,可以在运行期动态的创建接口的实现,从而达到解耦的目的。
Proxy代理类只能针对接口(interface)创建代理。
在Proxy类中,有成员变量InvocationHandler(调用处理器),所有对动态代理对象的方法调用都会被转向到InvocationHandler接口的实现上。
Proxy代理类应用广泛,在数据库连接、事务管理、拦截器中都使用了动态代理。
3.代码实例

/**
 * <p>java.lang.reflect.Proxy示例</p>
 *
 * @author hanchao 2018/2/28 21:45
 **/
public class ReflectProxyDemo {
    private static final Logger LOGGER = Logger.getLogger(ReflectProxyDemo.class);

    /**
     * <p>示例 接口(动态代理只能代理接口)</p>
     *
     * @author hanchao 2018/2/28 22:04
     **/
    interface MyService {
        void print();

        void save();
    }

    /**
     * <p>示例 类</p>
     *
     * @author hanchao 2018/2/28 22:05
     **/
    static class MyServiceImpl implements MyService {

        @Override
        public void print() {
            LOGGER.info("MyServiceImpl打印信息...");
        }

        @Override
        public void save() {
            LOGGER.info("MyServiceImpl保存数据...");
        }
    }

    /**
     * <p>示例 调用处理器</p>
     *
     * @author hanchao 2018/2/28 22:05
     **/
    static class MyInvocationHandler implements InvocationHandler {
        /**
         * 被代理的对象
         */
        private Object proxiedObj;

        public MyInvocationHandler(Object object) {
            this.proxiedObj = object;
        }

        /**
         * 代理类的调用方法
         *
         * @param proxy  代理对象本身,用于反射获取信息或者连续代理
         * @param method 调用的方法
         * @param args   调用方法的参数
         * @return
         * @throws Throwable
         */
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            //如果是print方法,则直接打印
            if ("print".equals(method.getName())) {
                LOGGER.info("调用了MyInvocationHandler.invoke(proxy,method,args)...不需要事务控制...");
                method.invoke(proxiedObj, args);
            }
            //如果是save方法,则需要进行事务控制
            if ("save".equals(method.getName())) {
                LOGGER.info("调用了MyInvocationHandler.invoke(proxy,method,args)...需要事务控制...");
                LOGGER.info("~~~~~~~~~~~~~~~~开启事务~~~~~~~~~~~~~~~~");
                method.invoke(proxiedObj, args);
                LOGGER.info("~~~~~~~~~~~~~~~~提交或回滚事务(commit/rollback等)~~~~~~~~~~~~~~~~");
            }
            return proxy;
        }
    }

    /**
     * <p>Java反射-代理Proxy 示例</p>
     *
     * @author hanchao 2018/2/28 21:45
     **/
    public static void main(String[] args) throws Throwable {
        /**
         * 在Proxy类中,有成员变量:protected InvocationHandler h;
         * InvocationHandler是 代理实例 的调用处理程序
         */

        /*创建一个接口的 代理实例*/
        //被代理的接口 指定 实现类
        MyService myService = new MyServiceImpl();
        LOGGER.info("通过类实例调用方法:");
        myService.print();
        myService.save();
        System.out.println();

        LOGGER.info("=======================创建代理实例newProxyInstance=======================");
        //创建一个 调用处理器,并设置代理对象
        InvocationHandler invocationHandler = new MyInvocationHandler(myService);
        //创建代理实例
        LOGGER.info("通过Proxy.newProxyInstance(interface.class.getClassLoader,interface.class[],handler)创建代理实例。");
        MyService proxyInstance = (MyService) Proxy.newProxyInstance(//注意类型转换
                MyService.class.getClassLoader(),//接口的class loader
                new Class[]{MyService.class},//接口的类
                invocationHandler);//调用处理器
        //通过代理调用方法
        LOGGER.info("通过代理调用方法:");
        proxyInstance.print();
        proxyInstance.save();
        System.out.println();

        LOGGER.info("=======================获取调用处理器getInvocationHandler=======================");
        //通过Proxy.getInvocationHandler(proxyInstance)获取指定代理的调用处理器
        InvocationHandler invocationHandler1 = Proxy.getInvocationHandler(proxyInstance);
        LOGGER.info("通过Proxy.getInvocationHandler(proxyInstance)获取指定代理的调用处理器:" + invocationHandler1);
        LOGGER.info("通过代理Proxy的InvocationHandler成员变量执行方法:");
        invocationHandler1.invoke(proxyInstance,MyServiceImpl.class.getDeclaredMethod("save"),null);
        System.out.println();

        LOGGER.info("=======================判断是否代理类isProxyClass=======================");
        //通过Proxy.isProxyClass(clazz)判断是否是代理类
        LOGGER.info("通过Proxy.isProxyClass(clazz)判断是否是代理类 - proxyInstance = " + Proxy.isProxyClass(proxyInstance.getClass()));
        LOGGER.info("通过Proxy.isProxyClass(clazz)判断是否是代理类 - myService = " + Proxy.isProxyClass(myService.getClass()) + "\n");        LOGGER.info("=======================获取代理类getProxyClass=======================");
        //通过Proxy.getProxyClass(interface.class.getClassLoader(),interface.class)获取代理类的Class对象
        Class proxyClass = Proxy.getProxyClass(MyService.class.getClassLoader(), MyService.class);
        LOGGER.info("通过Proxy.getProxyClass(interface.class.getClassLoader(),interface.class)获取代理类的Class对象:" + proxyClass);
        LOGGER.info("-----------------------通过构造方法创建代理实例getConstructor.newInstance-----------------------");
        //通过代理的构造器创建代理实例
        LOGGER.info("通过proxyClass.getConstructor(InvocationHandler.class).newInstance(invocationHandler)创建代理实例");
        MyService proxyInstance1 = (MyService) proxyClass.getConstructor(InvocationHandler.class).newInstance(invocationHandler);
        proxyInstance1.save();
    }
}



4.运行结果

2018-03-04 15:15:21 INFO  ReflectProxyDemo:103 - 通过类实例调用方法:
2018-03-04 15:15:21 INFO  ReflectProxyDemo:38 - MyServiceImpl打印信息...
2018-03-04 15:15:21 INFO  ReflectProxyDemo:43 - MyServiceImpl保存数据...

2018-03-04 15:15:21 INFO  ReflectProxyDemo:108 - =======================创建代理实例newProxyInstance=======================
2018-03-04 15:15:21 INFO  ReflectProxyDemo:112 - 通过Proxy.newProxyInstance(interface.class.getClassLoader,interface.class[],handler)创建代理实例。
2018-03-04 15:15:21 INFO  ReflectProxyDemo:118 - 通过代理调用方法:
2018-03-04 15:15:21 INFO  ReflectProxyDemo:75 - 调用了MyInvocationHandler.invoke(proxy,method,args)...不需要事务控制...
2018-03-04 15:15:21 INFO  ReflectProxyDemo:38 - MyServiceImpl打印信息...
2018-03-04 15:15:21 INFO  ReflectProxyDemo:80 - 调用了MyInvocationHandler.invoke(proxy,method,args)...需要事务控制...
2018-03-04 15:15:21 INFO  ReflectProxyDemo:81 - ~~~~~~~~~~~~~~~~开启事务~~~~~~~~~~~~~~~~
2018-03-04 15:15:21 INFO  ReflectProxyDemo:43 - MyServiceImpl保存数据...
2018-03-04 15:15:21 INFO  ReflectProxyDemo:83 - ~~~~~~~~~~~~~~~~提交或回滚事务(commit/rollback等)~~~~~~~~~~~~~~~~

2018-03-04 15:15:21 INFO  ReflectProxyDemo:123 - =======================获取调用处理器getInvocationHandler=======================
2018-03-04 15:15:21 INFO  ReflectProxyDemo:126 - 通过Proxy.getInvocationHandler(proxyInstance)获取指定代理的调用处理器:pers.hanchao.reflect.proxy.ReflectProxyDemo$MyInvocationHandler@2dda6444
2018-03-04 15:15:21 INFO  ReflectProxyDemo:127 - 通过代理Proxy的InvocationHandler成员变量执行方法:
2018-03-04 15:15:21 INFO  ReflectProxyDemo:80 - 调用了MyInvocationHandler.invoke(proxy,method,args)...需要事务控制...
2018-03-04 15:15:21 INFO  ReflectProxyDemo:81 - ~~~~~~~~~~~~~~~~开启事务~~~~~~~~~~~~~~~~
2018-03-04 15:15:21 INFO  ReflectProxyDemo:43 - MyServiceImpl保存数据...
2018-03-04 15:15:21 INFO  ReflectProxyDemo:83 - ~~~~~~~~~~~~~~~~提交或回滚事务(commit/rollback等)~~~~~~~~~~~~~~~~

2018-03-04 15:15:21 INFO  ReflectProxyDemo:131 - =======================判断是否代理类isProxyClass=======================
2018-03-04 15:15:21 INFO  ReflectProxyDemo:133 - 通过Proxy.isProxyClass(clazz)判断是否是代理类 - proxyInstance = true
2018-03-04 15:15:21 INFO  ReflectProxyDemo:134 - 通过Proxy.isProxyClass(clazz)判断是否是代理类 - myService = false

2018-03-04 15:15:21 INFO  ReflectProxyDemo:136 - =======================获取代理类getProxyClass=======================
2018-03-04 15:15:21 INFO  ReflectProxyDemo:139 - 通过Proxy.getProxyClass(interface.class.getClassLoader(),interface.class)获取代理类的Class对象:class pers.hanchao.reflect.proxy.$Proxy0
2018-03-04 15:15:21 INFO  ReflectProxyDemo:140 - -----------------------通过构造方法创建代理实例getConstructor.newInstance-----------------------
2018-03-04 15:15:21 INFO  ReflectProxyDemo:142 - 通过proxyClass.getConstructor(InvocationHandler.class).newInstance(invocationHandler)创建代理实例
2018-03-04 15:15:21 INFO  ReflectProxyDemo:80 - 调用了MyInvocationHandler.invoke(proxy,method,args)...需要事务控制...
2018-03-04 15:15:21 INFO  ReflectProxyDemo:81 - ~~~~~~~~~~~~~~~~开启事务~~~~~~~~~~~~~~~~
2018-03-04 15:15:21 INFO  ReflectProxyDemo:43 - MyServiceImpl保存数据...
2018-03-04 15:15:21 INFO  ReflectProxyDemo:83 - ~~~~~~~~~~~~~~~~提交或回滚事务(commit/rollback等)~~~~~~~~~~~~~~~~



5.总结
根据代码实例和运行结果,总结如下:

通过Proxy.newProxyInstance(interface.class.getClassLoader,interface.class[],handler)创建代理实例 
第一个参数是被代理接口的class loader,作为定义这个代理的类加载器。
第二个参数是被代理接口的数组,作为这个代理类要实现的接口
第三个参数是调用处理器(InvocationHandler)的实现类,所有通过这个代理调用的方法实际上都是调用这个实现类的invoke方法。
注意类型转换。
通过Proxy.getInvocationHandler(proxyInstance)获取指定代理的调用处理器 
参数为代理对象
通过InvocationHandler实现类的invoke()方法可以进行方法调用。
通过InvocationHandler实现类的invoke()方法,实现各类应用,如:数据库连接、事务管理、拦截器等等。
通过Proxy.isProxyClass(clazz)判断是否是代理类
通过Proxy.getProxyClass(interface.class.getClassLoader(),interface.class)获取代理类对象 
第一个参数是被代理接口的class loader,作为定义这个代理的类加载器。
第二个参数是被代理接口的数组,作为这个代理类要实现的接口
通过proxyClass.getConstructor(InvocationHandler.class).newInstance(invocationHandler)创建代理实例
上面提到的通过Proxy.newProxyInstance(…)创建代理实例实际上就是通过proxyClass.getConstructor创建代理实例的分解。
 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值