美文网首页设计模式
一文读懂java动态代理

一文读懂java动态代理

作者: 艳阳天不下雨 | 来源:发表于2019-07-30 10:19 被阅读3次

    动态代理的好处

    Java动态代理的优势是实现无侵入式的代码扩展,也就是方法的增强;让你可以在不用修改源码的情况下,增强一些方法;在方法的前后你可以做你任何想做的事情(甚至不去执行这个方法就可以)。此外,也可以减少代码量,如果采用静态代理,类的方法比较多的时候,得手写大量代码。

    动态代理示例:

    接口类:

    public interface UserService { 

        public abstract void add();

        public abstract void update();

    }

    接口实现类:

    public class UserServiceImpl implements UserService { 

         public void add() { 

            System.out.println("----- add -----"); 

        }

        public void update(){

             System.out.println("----- update-----"); 

        }

    }

    代理处理类MyInvocationHandler.java

    import java.lang.reflect.InvocationHandler; 

    import java.lang.reflect.Method; 

    import java.lang.reflect.Proxy; 

    public class MyInvocationHandler implements InvocationHandler { 

        private Object target; 

        public MyInvocationHandler(Object target) {

     //注入目标对象,方便在invoke中调用目标对象的目标方法

            super(); 

            this.target = target; 

        } 

        public Object getProxy() { 

            return Proxy.newProxyInstance(Thread.currentThread() 

                    .getContextClassLoader(), target.getClass().getInterfaces(), 

                    this); 

    //指定代理类生成时的加载器,要实现的接口,代理类的代理方法被调用时需要调用哪个对象的invoke方法。

        } 

        @Override 

        public Object invoke(Object proxy, Method method, Object[] args) 

                throws Throwable { 

    //代理类的代理方法被调用时,会调用传入的h对象的invoke方法。

            System.out.println("----- before -----"); 

            Object result = method.invoke(target, args); 

    //调用真正的目标类的目标方法。

            System.out.println("----- after -----"); 

            return result; 

        } 

    测试类:

    public class DynamicProxyTest { 

        public static void main(String[] args) { 

            UserService userService = new UserServiceImpl(); 

            MyInvocationHandler invocationHandler = new MyInvocationHandler( 

                    userService); 

            UserService proxy = (UserService) invocationHandler.getProxy(); 

            proxy.add();

            proxy.update();

        } 

    输出:

    ----- before -----

    ----- add -----

    ----- after -----

    ----- before -----

    ----- update -----

    ----- after -----

    其基本过程如下: 1.定义目标类接口和目标类  2.实现InvocationHandler接口,在构造方法中注入目标类,实现获取代理类的方法getProxy() ,该方法中调用Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), target.getClass().getInterfaces(), this); 传入的类加载器用于加载生成的代理类的字节码(ProxyGenerator.generateProxyClass()的方法是最终生成代理类的字节码.),传入的接口(可以为多个)用于规定生成的代理类需要代理的方法有哪些,传入的this对象必须是InvocationHandler的实现类对象(称为h对象),因为最终生成的代理对象的方法在被调用是全部是通过转发给对象h的invoke方法来处理的,你可以在invoke方法中通过method.invoke(target, args);来调用目标类的方法,同时在调用之前或者之后加入自己的功能代码。

    //重点就是这里,代理类实现的接口方法

      public final void sayHello(String paramString) { 

        try {<br>      //见上面构造方法,this.h 就代表MyInvocationHandler类,所以执行的就是我们代理实现类中的invoke方法。

          this.h.invoke(this, m3, new Object[] { paramString }); 

          return; 

        } 

        catch (Error|RuntimeException localError) { 

          throw localError; 

        } 

        catch (Throwable localThrowable) { 

          throw new UndeclaredThrowableException(localThrowable); 

        } 

      } 

    我们可以把 InvocationHandler 看做一个中介类,中介类持有一个被代理的目标对象,在 invoke 方法中调用了目标对象的相应方法,而生成的代理类中持有中介类,因此,当我们在调用代理类的方法的时候,调用被转发到中介类h的 invoke 方法,再转为对被目标对象的调用。

    生成的代理类:$Proxy0 extends Proxy implements Person,我们看到代理类继承了 Proxy 类,由于java中的单继承,所以也就决定了生成的 java 动态代理类不能再继承其它类,只能对接口进行代理,所以Java 的动态代理类无法实现直接针对 类的动态代理,只能通过接口间接实现对类的动态代理。

    相关文章

      网友评论

        本文标题:一文读懂java动态代理

        本文链接:https://www.haomeiwen.com/subject/mhrgrctx.html