(一).什么是动态代理?
定义:动态代理为其他对象提供一种代理以控制对这个对象的访问。
(二).为什么要用动态代理?
动态代理的优势就是实现无侵入式的代码扩展,比如 Spring的AOP的拦截功能是由java中的动态代理来实现的。
动态代理可以用在记录方法的日志,AOP,权限等等,而不侵入原来类的代码。
(三).java中动态代理的实现
在java中如果要为一个类创建动态代理,这个类必须实现接口,然后还有两个重要的东西:Proxy和InvocationHandler。Proxy类是创建动态代理的主要类。它的newProxyInstance()静态方法返回一个代理对象的实例,而InvocationHandler是该被代理类的事物处理器。具体看代码。
1.创建一个的接口,并创建该接口的实现类,
package com.my.proxyTest;
//创建一个接口
public interface UserService {
public void addUser(String userName);
}
package com.my.proxyTest;
public class UserServiceImpl implements UserService {
@Override
public void addUser(String userName) {
System.out.println("增加的用户名为:"+userName);
}
}
2.通过实现InvocationHandler接口创建自己的调用处理器
package com.my.proxyTest;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class UserServiceHandler implements InvocationHandler{
public Object target;//用Object接收,可以传进来任意类型的对象。
public UserServiceHandler(Object obj){
target=obj;
}
/**
* proxy:代理类
* method:被代理类的方法
* args:该方法的参数数组
*/
@Override
//这里的invoke方法不是显示调用,而是java创建的代理对象$Proxy0.class调用
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("开始添加用户。。。");//在原来的对象方法执行前面,执行这段代码
Object obj=method.invoke(target,args);//传入被代理对象,也就是目标对象
return obj;
}
}
3.写测试类,并为对象创建代理对象
package com.my.proxyTest;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class Client {
public static void main(String[] args) {
UserService userService=new UserServiceImpl();
UserServiceHandler h=new UserServiceHandler(userService);
//把$Proxy0强制转换成UserService
UserService userServiceProxy=(UserService)Proxy.newProxyInstance(
userService.getClass().getClassLoader(),
userService.getClass().getInterfaces(),
h);
System.out.println(userServiceProxy instanceof Proxy); //输出为true
//输出:userServiceProxy的Class类是:class $Proxy0
//这里可以看出userServiceProxy的Class类是$Proxy0。
//这个$Proxy0类继承了Proxy,实现了UserServiceImpl接口
System.out.println("userServiceProxy的Class类是:"+userServiceProxy.getClass().toString());
System.out.print("<span style="font-size: 14px;">userServiceProxy</span>中的属性有:");
Field[] field=userServiceProxy.getClass().getDeclaredFields();
for(Field f:field){
System.out.print(f.getName()+", ");
}
System.out.print("\n"+"<span style="font-family: Arial, Helvetica, sans-serif;">userServiceProxy</span>中的方法有:");
Method[] method=userServiceProxy.getClass().getDeclaredMethods();
for(Method m:method){
System.out.print(m.getName()+", ");
}
System.out.println("\n"+"<span style="font-family: Arial, Helvetica, sans-serif;">userServiceProxy</span><span style="font-family: Arial, Helvetica, sans-serif;">的父类是:"+userServiceProxy.getClass().getSuperclass()); </span>
System.out.print("\n"+"<span style="font-family: Arial, Helvetica, sans-serif;">userServiceProxy</span>实现的接口是:");
Class<?>[] interfaces=userServiceProxy.getClass().getInterfaces();
for(Class<?> i:interfaces){
System.out.print(i.getName()+", ");
}
System.out.println("\n\n"+"运行结果为:");
userServiceProxy.addUser("张三");
}
}
输出结果:
true
userServiceProxy的Class类是:class $Proxy0
userServiceProxy中的属性有:m3, m1, m0, m2,
userServiceProxy中的方法有:addUser, hashCode, equals, toString,
userServiceProxy的父类是:class java.lang.reflect.Proxy
userServiceProxy实现的接口是:com.my.proxyTest.UserService,
运行结果为:
开始添加用户。。。
增加的用户名为:张三。可以发现在没有改动原来类的基础上,增加了原来类的业务逻辑。这就是java动态代理运用。
(四)分析源码
先看看Proxy类的主要代码
Proxy构造方法
private final static Class[] constructorParams ={ InvocationHandler.class }; //定义参数是<span style="font-family: Arial, Helvetica, sans-serif;">InvocationHandler的数组</span>
protected InvocationHandler h;
// 由于 Proxy 内部从不直接调用构造函数,所以 private 类型意味着禁止任何调用
private Proxy() {
}
// 由于 Proxy 内部从不直接调用构造函数,所以 protected 意味着只有子类可以调用
protected Proxy(InvocationHandler h) {
this.h = h;
}
Proxy静态方法newProxyInstance
public static Object newProxyInstance(ClassLoader loader, Class<?>[]interfaces,InvocationHandler h) throws IllegalArgumentException {
// 检查 h 不为空,否则抛异常
if (h == null) {
throw new NullPointerException();
}
// 获得与指定类装载器和一组接口相关的代理类类型对象
Class cl = getProxyClass(loader, interfaces);
// 通过反射获取构造函数对象并生成代理类实例
try {
Constructor cons = cl.getConstructor(constructorParams);
//cons即是形参为InvocationHandler类型的构造方法,通过构造方法创建代理类实例,
//此时需将调用处理器对象作为参数被传入
return (Object) cons.newInstance(new Object[] { h });
} catch (NoSuchMethodException e) { throw new InternalError(e.toString()); }
catch (IllegalAccessException e) { throw new InternalError(e.toString()); }
catch (InstantiationException e) { throw new InternalError(e.toString()); }
catch (InvocationTargetException e) { throw new InternalError(e.toString()); }
}
类Proxy的getProxyClass方法调用ProxyGenerator的 generateProxyClass方法产生ProxySubject.class的二进制数据:
public static byte[] generateProxyClass(final String name, Class[] interfaces)
我们可以import sun.misc.ProxyGenerator,调用 generateProxyClass方法产生binary data,然后写入文件,最后通过反编译工具来查看内部实现原理。 反编译后的userServiceProxy.java Proxy静态方法newProxyInstance
public final class $Proxy0 extends Proxy implements Subject {
private static Method m1;
private static Method m0;
private static Method m3;
private static Method m2;
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals",
new Class[] { Class.forName("java.lang.Object") });
m0 = Class.forName("java.lang.Object").getMethod("hashCode",
new Class[0]);
m3 = Class.forName("***.RealSubject").getMethod("request",
new Class[0]);
m2 = Class.forName("java.lang.Object").getMethod("toString",
new Class[0]);
} catch (NoSuchMethodException nosuchmethodexception) {
throw new NoSuchMethodError(nosuchmethodexception.getMessage());
} catch (ClassNotFoundException classnotfoundexception) {
throw new NoClassDefFoundError(classnotfoundexception.getMessage());
}
} //static
public $Proxy0(InvocationHandler invocationhandler) {
super(invocationhandler);
}
@Override
public final boolean equals(Object obj) {
try {
return ((Boolean) super.h.invoke(this, m1, new Object[] { obj })) .booleanValue();
} catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
@Override
public final int hashCode() {
try {
return ((Integer) super.h.invoke(this, m0, null)).intValue();
} catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
public final void request() {
try {
super.h.invoke(this, m3, null);
return;
} catch (Error e) {
} catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
@Override
public final String toString() {
try {
return (String) super.h.invoke(this, m2, null);
} catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
}
总结
一个典型的动态代理创建对象过程可分为以下四个步骤:
1、通过实现InvocationHandler接口创建自己的调用处理器 IvocationHandler handler = new InvocationHandlerImpl(...);
2、通过为Proxy类指定ClassLoader对象和一组interface创建动态代理类
Class clazz = Proxy.getProxyClass(classLoader,new Class[]{...});
3、通过反射机制获取动态代理类的构造函数,其参数类型是调用处理器接口类型
Constructor constructor = clazz.getConstructor(new Class[]{InvocationHandler.class});
4、通过构造函数创建代理类实例,此时需将调用处理器对象作为参数被传入
Interface Proxy = (Interface)constructor.newInstance(new Object[] (handler));
为了简化对象创建过程,Proxy类中的newInstance方法封装了2~4,只需两步即可完成代理对象的创建。
生成的ProxySubject继承Proxy类实现UserServiceImpl接口,实现的UserServiceImpl的方法实际调用处理器的invoke方法,而invoke方法利用反射调用的是被代理对象的的方法(Object result=method.invoke(proxied,args))
java的用jdk实现动态代理有个美中不足,它只能实现继承接口的类。对于那些没有实现任何接口类无法使用动态代理,这时候就需要用到第三方的cglib来实现。