jdk动态代理


一、什么是代理?

代理是一种常用的设计模式,其目的就是为其他对象提供一个代理以控制对某个对象的访问。代理类负责为委托类预处理消息,过滤消息并转发消息,以及进行消息被委托类执行后的后续处理。

代理模式UML图:

简单结构示意图:

为了保持行为的一致性,代理类和委托类通常会实现相同的接口,所以在访问者看来两者没有丝毫的区别。通过代理类这中间一层,能有效控制对委托类对象的直接访问,也可以很好地隐藏和保护委托类对象,同时也为实施不同控制策略预留了空间,从而在设计上获得了更大的灵活性。Java 动态代理机制以巧妙的方式近乎完美地实践了代理模式的设计理念。

二、Java 动态代理类 

Java动态代理类位于java.lang.reflect包下,一般主要涉及到以下两个类:

(1)接口 InvocationHandler:该接口中仅定义了一个方法

public object invoke(Object obj,Method method, Object[] args)

在实际使用时,第一个参数obj一般是指代理类,method是被代理的方法,如上例中的request(),args为该方法的参数数组。这个抽象方法在代理类中动态实现。

(2)Proxy:该类即为动态代理类,其中主要包含以下内容:

protected Proxy(InvocationHandler h):构造函数,用于给内部的h赋值。

static Class getProxyClass (ClassLoaderloader, Class[] interfaces):获得一个代理类,其中loader是类装载器,interfaces是真实类所拥有的全部接口的数组。

static Object newProxyInstance(ClassLoaderloader, Class[] interfaces, InvocationHandler h):返回代理类的一个实例,返回后的代理类可以当作被代理类使用(可使用被代理类的在Subject接口中声明过的方法)

所谓DynamicProxy是这样一种class:它是在运行时生成的class,在生成它时你必须提供一组interface给它,然后该class就宣称它实现了这些 interface。你当然可以把该class的实例当作这些interface中的任何一个来用。当然,这个DynamicProxy其实就是一个Proxy,它不会替你作实质性的工作,在生成它的实例时你必须提供一个handler,由它接管实际的工作。

在使用动态代理类时,我们必须实现InvocationHandler接口

通过这种方式,被代理的对象(SubjectImpl)可以在运行时动态改变,需要控制的接口(Subject接口)可以在运行时改变,控制的方式(DynamicSubject类)也可以动态改变,从而实现了非常灵活的动态代理关系。

动态代理步骤:

  • 1.创建一个实现接口InvocationHandler的类,它必须实现invoke方法
  • 2.创建被代理的类以及接口
  • 3.通过Proxy的静态方法 newProxyInstance(ClassLoaderloader, Class[] interfaces, InvocationHandler h)创建一个代理
  • 4.通过代理调用方法

三、JDK的动态代理具体使用

1、需要动态代理的接口:

/**
 * @Author lyh
 * @Date 2022/3/3
 * 需要动态代理的接口
 */
public interface Subject {

    /**
     * 说话
     * @param str
     * @return
     */
    String say(String str);
}

2、需要代理的实际对象

/**
 * @Author lyh
 * @Date 2022/3/3
 * 需要代理的实际对象
 */
public class SubjectImpl implements Subject {

    @Override
    public String say(String str) {
        return str;
    }
}

3、编写处理器实现类

/**
 * @Author lyh
 * @Date 2022/3/3
 * 处理器实现类
 */
public class InvocationHandlerImpl implements InvocationHandler {

    /**
     * 这个就是我们要代理的真实对象
     */
    private Object subject;

    /**
     * 构造方法,给我们要代理的真实对象赋初值
     *
     * @param subject
     */
    public InvocationHandlerImpl(Object subject)
    {
        this.subject = subject;
    }

    /**
     * 该方法负责集中处理动态代理类上的所有方法调用。
     * 调用处理器根据这三个参数进行预处理或分派到委托类实例上反射执行
     *
     * @param proxy  代理类实例
     * @param method 被调用的方法对象
     * @param args   调用参数
     * @return
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("调用方法前的处理");
        System.out.println("method"+method);
        //调用真实对象的方法
        Object returnValue = method.invoke(subject, args);
        System.out.println("调用方法结束后的处理");
        return returnValue;
    }
}

4、测试

public class Test {
    public static void main(String[] args) {
        // 真实对象(被代理对象)
        Subject realSubject = new SubjectImpl();
        // invocation
        InvocationHandlerImpl invocationHandler = new InvocationHandlerImpl(realSubject);
        ClassLoader classLoader = realSubject.getClass().getClassLoader();
        Class<?>[] interfaces = realSubject.getClass().getInterfaces();
        //调用Proxy的newProxyInstance 指定类装载器、一组接口及调用处理器生成动态代理类实例
        Subject subject = (Subject)Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);
        System.out.println("代理对象类型"+subject.getClass().getName());
        //通过代理对象调用方法
        String say = subject.say("你好呀!");
        System.out.println(say);
    }
}

5、输出结果

摘自:https://blog.csdn.net/jiankunking/article/details/52143504