定义:为其他对象提供一个代理以控制对这个对象的访问.
作用:用于在程序运行时对被代理对象的方法进行增强,和装饰者设计模式的作用一样.
原理:代理对象实现了和被代理对象一样的接口,调用代理对象的方法会间接的调用到被代理对象的方法,因此开发人员可以在调用被代理对象方法之前或者之后执行特定的代码.
缺点:jdk中的Proxy类实现的动态代理要求被代理对象必须要实现接口,且代理类只能增强这些接口中所定义的方法,而不能增强被代理类自己定义的方法.
Java提供了一个Proxy类,调用它的newInstance静态方法可以生成某个对象的代理对象
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)throws IllegalArgumentException{
}
该方法接收三个参数:
- 参数1:生成代理对象使用哪个类装载器,不懂什么是类加载器的话可以看这篇文章详情
- 参数2:生成哪个对象的代理对象,通过接口指定,可以是多个接口,以数组的方式传递
- 参数3:方法处理器,由开发人员编写handler接口的实现来指定,用于增强被代理对象的方法。
返回值:返回代理被代理对象的代理类,它是由程序运行的时候动态创建的.
InvocationHandler接口:
创建代理对象的时候需要传递该接口的实现类,通常是以匿名内部类的形式来创建.实现它只需要实现一个方法:
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
- 参数1:动态创建的代理对象,也就是Proxy.newProxyInstance()方法返回的对象,通常我们用不上它.
- 参数2:被代理对象需要被增强的方法的反射对象
- 参数3:对应method方法的参数
返回值:返回代理对象对应方法的执行结果,即invoke方法里面执行的逻辑.
注意:如果创建代理对象指定了handler(处理器),那么不管用户调用代理对象的什么方法,该方法都是调用处理器的invoke方法。
学习动态代理的目的
动态代理技术都是在框架中使用,例如:Struts1、Struts2、Spring和Hibernate中都使用了动态代理技术。如果你不想自己写个框架,那么你基本上是用上不动态代理技术的.
运行时实现接口
以往实现某个接口,你需要写一个类,然后在类名字的后面给出“implements”XXX接口。例如:
public interface MyInterface {
String fun1(String str);
String fun2(String str);
}
public class MyInterfaceImpl implements MyInterface {
@Override
public String fun1(String str) {
return str;
}
@Override
public String fun2(String str) {
return str;
}
}
上面的代码对我们来说没有什么新鲜感,我们要说的是动态代理技术可以通过一个方法调用就可以生成一个对指定接口的实现类对象,且可以做到在不修改MyInterfaceImpl 源码的前提下对fun1和fun2方法进行扩展(或者说增强)。
Class[] cs = {MyInterface.class};
MyInterface mi = (MyInterface)Proxy.newProxyInstance(loader, cs, h);
上面代码中,Proxy类的静态方法newProxyInstance()方法生成了一个对象,这个对象实现了cs数组中指定的接口。没错,返回值mi是MyInterface接口的实现类。你不要问这个类是哪个类,你只需要知道mi是MyInterface接口的实现类就可以了。
动态代理就是在运行时生成一个类,这个类会实现你指定的一组接口,而这个类没有.java文件,是在运行时生成的,你也不用去关心它是什么类型的,你只需要知道它实现了哪些接口即可。
完整的创建动态代理对象的代码如下:
package blog.csdn.net;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class _Main {
public static void main(String[] args) {
// 创建被代理对象
MyInterfaceImpl impl = new MyInterfaceImpl();
// 创建代理对象,由于代理对象会实现了被代理对象同样的接口,所以可以强转成任意接口
MyInterface proxyInstance = (MyInterface) Proxy.newProxyInstance(impl.getClass().getClassLoader(),
new Class[] { MyInterface.class }, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getName().equals("fun1")) {
// 修改方法的参数
args[0] = "fun1运行前参数叠加" + args[0] + "...";
} else if (method.getName().equals("fun2")) {
args[0] = "fun2运行前参数被替换...";
}
// 执行被代理对象的方法
String result = (String) method.invoke(impl, args);
// 执行代理对象方法后还可以执行一些逻辑
result += method.getName() + "运行后...";
return result;
}
});
String res1 = proxyInstance.fun1("123");
String res2 = proxyInstance.fun2("123");
System.out.println(res1);
System.out.println(res2);
}
}
运行结果: