先粘贴一篇大佬的博文 「Java动态代理作用是什么」,本文是对其学习笔记。
代理(Proxy)是一种设计模式,通过代理对象来访问目标对象,目的是在目标对象的基础上进行增强,例如增加一些额外的功能。Java中的代理主要分为静态代理和动态代理。
静态代理
为每一个类都编写一个对应的代理类,两个类都实现同样的接口。在创建一个代理对象的时候,需要向其构造器中塞入一个目标对象,然后在代理对象的方法内部调用目标对象的同名方法(并可以加入一些额外的功能)。如下图所示:
可见 代理对象=目标对象+增强代码(即上图中的打印日志信息)。因此在使用了代理对象以后,就不用再使用目标对象了。
但是静态代理有一个严重的缺点,在项目中我们的类可能有成千上万个,如果要用静态代理的话,需要给每一个类写一个对应的代理类,显然是非常冗余的。因此我们需要考虑,如果有一种方法,能够绕开编写代理类,而可以直接生成相应的代理对象,这样就会方便简洁很多。这就是动态代理的出发点。
动态代理
感觉一些具体的细节开头的博客解释的很棒了,这里就梳理一下流程。首先上一段代码:
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
interface Calculator
{
int add(int a, int b);
int subtract(int a, int b);
}
class CalculatorImp1 implements Calculator
{
public int add(int a, int b)
{
return a+b;
}
public int subtract(int a, int b)
{
return a-b;
}
}
public class ProxyTest {
public static void main(String[] args) throws Throwable{
CalculatorImp1 target = new CalculatorImp1();
Calculator proxy = (Calculator)getProxy(target);
System.out.println(proxy.getClass().getName());
System.out.println(proxy instanceof CalculatorImp1);
proxy.add(1, 2);
proxy.subtract(1, 2);
}
public static Object getProxy(final Object target) throws Exception {
Class proxyClazz = Proxy.getProxyClass(target.getClass().getClassLoader(), target.getClass().getInterfaces());
Constructor constructor = proxyClazz.getConstructor(InvocationHandler.class);
Object proxy = constructor.newInstance(new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println(method.getName() + "方法开始执行");
Object result = method.invoke(target, args);
System.out.println(result);
System.out.println(method.getName() + "方法结束执行");
return result;
}
});
return proxy;
}
}
我们有一个接口Calculator,以及一个目标类CalculatorImp1。动态代理是在不写代理类的情况下,直接生成代理对象proxy。
这里用到了JDK中的java.lang.reflect.InvocationHandler接口和 java.lang.reflect.Proxy类。其中Proxy有一个静态方法getProxyClass(只需要传入类加载器和接口,就可以生成代理Class对象)。有了代理Class对象后,就可以利用代理Class的构造器创建对象,此时需要传入InvocationHandler,每次调用代理对象的方法,最终都会调用InvocationHandler的invoke()方法。
在创建代理对象的时候用到匿名内部类的方式,实现了接口InvocationHandler()的方法,对invoke方法进行了重写实现。其中的method.invoke部分实现的是目标类的方法,其他代码则是进行的额外的扩充。这样就非常灵活了,无论现在系统有多少类,只要把实例传进来,getProxy()都能给你返回对应的代理对象。就这样,我们完美地跳过了代理类,直接创建了代理对象!