zoukankan      html  css  js  c++  java
  • [笔记]动态代理

    怎么做

    效果很简单,功能很强大,比如有下面这样一个接口:

    public interface IUserService {
    
        public String update(String param);
        
    }

    有地方不是需要这样一个接口实现吗?现在根本没有一个具体的类实现了它,但我可以无中生有得给创建一个:

         Object obj = Proxy.newProxyInstance(DynamicProxyTest.class.getClassLoader(), new Class[] {IUserService.class}, new InvocationHandler() {
                @Override
                public Object invoke(Object target, Method method, Object[] params) throws Throwable {
                    ///...
                    return null;
                }
                
            });
            IUserService service = (IUserService)obj;
            service.update("hello");

    没错,得到的代理实例可以直接强转成IUserService。

    然后就可以开心地进行方法调用了。

    等会儿,不是没有地方实现接口吗?那调用方法调到哪儿去了呢?在创建代理时创建的InvocationHandler里:

    new InvocationHandler() {
          @Override
          public Object invoke(Object target, Method method, Object[] params) throws Throwable {
               System.out.println(method.getParameterTypes()[0]);
               System.out.println(params[0]);
               return null;
         }
    }

    这里把所有相关的信息都提供了,调用的那个方法(method),参数是什么(params)。然后就可以想干嘛干嘛了。

    这里有几个东西要注意:

    invoke方法的返回值,就是那个Object,其实就是指接口中方法“public String update(String param)”的返回值“String”。InvokeHandler的方法是共用的,所以只能搞一个Object,如果在这里瞎往外面返回值,是有可能报类型转换错误的(java.lang.ClassCastException)。

    参数中的那个target不要乱用,它表示的是代理实例本身。你再去调它的方法那就死循环了。干嘛要传这么个东西在这里来坑人呢?

    如果把接口改成这样:

    public interface IUserService {
    
        public String prop = "a property";
        
        public String update(String param);
        
    }

    现在如果要访问这个prop属性就排上用场了:

    public Object invoke(Object target, Method method, Object[] params) throws Throwable {
                    System.out.println(method.getParameterTypes()[0]);
                    System.out.println(params[0]);
                    IUserService _this = (IUserService)target;
                    System.out.println(_this.prop);
                    return null;
                }

    更简单地说,参数里的target充当着“this”的角色。没有它就实现不了上面的操作了。 

    有什么用

    要用动态代理那肯定是因为接口本身的实现类没法直接确定。需要在运行时根据条件再动态判断应该怎么调用。举例:

    Spring拦截器

    Spring环境下,咱们拿到的Bean都是Spring提供的,所以Spring可以先给一个假的代理对象,等调用方法的时候,Spring先判断一下是不是要做些别的什么事情,然后在调真实Bean的方法,调用完真实对象方法之后还可以干些别的事情。Spring想怎么玩就怎么玩。

    RPC调用

    远程调用的情况下,本地就只有一个接口,而接口的实现不知道在远程什么位置。所以可以用代理来实现接口,等调用方法的时候,通过其他手段调用到远程服务,获取到值之后进行返回。

  • 相关阅读:
    构造函数创建对象和Object.create()实现继承
    DIV伸缩盒子box
    阿里巴巴面试题
    在字符串上添加一些方法,让字符串具有新添加方法的功能
    JQuery常用函数及功能小结--转载
    滚动公告,永远只显示一条
    JS自定义属性兼容
    手机端touchstart,touchmove,touchend事件,优化用户划入某个可以点击LI的效果
    图片预加载问题
    多联动导航
  • 原文地址:https://www.cnblogs.com/at0x7c00/p/8006628.html
Copyright © 2011-2022 走看看