一文读懂java动态代理

动态代理的好处

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 {
      //见上面构造方法,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动态代理)