java动态代理机制详细分析
一、代理模式
代理模式是常用的java设计模式,特征是代理类与委托类实现同样的接口,代理类负责为委托类执行信息预处理、信息过滤、信息转发给委托类、事后信息处理。代理对象并不直接提供服务,而是通过调用委托对象相应方法实现,为对象访问提供了间接性。Spring中的AOP即通过动态代理实现,具体场景比如Spring中的事物控制。
二、静态代理
静态代理是在程序运行前已写好代理类并编译完成,代理类并持有目标对象引用,并在接口实现方法里调用目标服务。
如果委托类方法较多,且被代理类执行的操作相同,一个一个代理去写会很繁琐。
三、动态代理
程序运行过程时,在内存中临时生成动态代理类,称为动态代理。
1、动态代理简单实现
在java的java.lang.reflect包下提供了一个Proxy类和一个InvocationHandler接口,通过这个类和这个接口可以生成JDK动态代理类和动态代理对象。
具体代码如下:
- 首先是定义CarI接口
package com.dengqi.spring.dyproxy;
/**
* @Auther: dengqi
* @Date: 2018/7/30 18:01
* @Description:
*/
public interface CarI {
void run();
void stop();
}
- 然后是定义CarI接口的实现类CarE
package com.dengqi.spring.dyproxy;
/**
* @Auther: dengqi
* @Date: 2018/7/30 18:02
* @Description:
*/
public class CarE implements CarI {
private String car_code;
public CarE() {
}
public CarE(String car_code) {
this.car_code = car_code;
}
@Override
public void run() {
System.out.println("the car " + car_code + "runs");
try {
Thread.sleep(2000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Override
public void stop() {
System.out.println("the car " + car_code + "stop");
}
}
- 定义一个InvocationHandler实现类,持有目标对象CarE
package com.dengqi.spring.dyproxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* @Auther: dengqi
* @Date: 2018/7/30 18:05
* @Description:
*/
public class CarInvocationHandler implements InvocationHandler {
private Object car ;
public CarInvocationHandler(Object car){
this.car = car;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("----merthod is : " + method + "--------");
System.out.println("car test begin----------");
MonitorUtil.start();
method.invoke(car,args);
MonitorUtil.end();
System.out.println("car test finish,");
return null;
}
}
还可以换一种写法,ProxyFactory写法如下
package com.dengqi.spring.dyproxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* @Auther: dengqi
* @Date: 2018/7/30 18:52
* @Description:
*/
public class TimeProxyFactory {
/**
* target 直接利用目标对象构建动态代理对象
* @param target
* @return
*/
public static Object createProxy(final Object target){
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("----merthod is : " + method + "--------");
System.out.println("car test begin----------");
MonitorUtil.start();
method.invoke(target,args);
MonitorUtil.end();
System.out.println("car test finish,");
return null;
}
});
}
}
- 计时工具类MonitorUtil
package com.dengqi.spring.dyproxy;
/**
* @Auther: dengqi
* @Date: 2018/7/31 10:51
* @Description:
*/
public class MonitorUtil {
private static ThreadLocal<Long> threadLocal = new ThreadLocal();
public static void start(){
long start = System.currentTimeMillis();
threadLocal.set(start);
}
public static void end(){
long end = System.currentTimeMillis();
System.out.println("operation time is : " + (end - threadLocal.get()) + "mills");
}
}
- 执行Client调用
package com.dengqi.spring.dyproxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
/**
* @Auther: dengqi
* @Date: 2018/7/30 18:09
* @Description:
*/
public class Client {
public static void main(String[] args) {
//创建委托对象
CarI car = new CarE("BMW");
//创建委托对象关联的InvocationHandler对象
InvocationHandler handler = new CarInvocationHandler(car);
//创建动态代理对象
CarI carProxy = (CarI) Proxy.newProxyInstance(CarI.class.getClassLoader(),new Class[]{CarI.class},handler);
//打印代理对象名
System.out.println(carProxy.getClass().getName());
//执行代理服务
carProxy.run();
carProxy.stop();
}
}
- 执行结果
com.sun.proxy.$Proxy0
----merthod is : public abstract void com.dengqi.spring.dyproxy.CarI.run()--------
car test begin----------
the car BMWruns
operation time is : 2000mills
car test finish,
----merthod is : public abstract void com.dengqi.spring.dyproxy.CarI.stop()--------
car test begin----------
the car BMWstop
operation time is : 0mills
car test finish,
Process finished with exit code 0
四、动态代理原理分析
java动态代理类的创建
利用Proxy类的newProxyInstance方法创建了一个动态代理对象,查看该方法的源码,动态代理类的创建步骤见注释
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
if (h == null) {
throw new NullPointerException();
}
//1、获取实现接口
final Class<?>[] intfs = interfaces.clone();
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
}
/*
*2、动态生成的代理类
* Look up or generate the designated proxy class.
*/
Class<?> cl = getProxyClass0(loader, intfs);
/*
* Invoke its constructor with the designated invocation handler.
*/
try {
//3、获取构造对象
final Constructor<?> cons = cl.getConstructor(constructorParams);
final InvocationHandler ih = h;
if (sm != null && ProxyAccessHelper.needsNewInstanceCheck(cl)) {
// create proxy instance with doPrivilege as the proxy class may
// implement non-public interfaces that requires a special permission
return AccessController.doPrivileged(new PrivilegedAction<Object>() {
public Object run() {
return newInstance(cons, ih);
}
});
} else {
//4、利用构造器对象生成代理类实例
return newInstance(cons, ih);
}
} catch (NoSuchMethodException e) {
throw new InternalError(e.toString());
}
}
private static Object newInstance(Constructor<?> cons, InvocationHandler h) {
try {
return cons.newInstance(new Object[] {h} );
} catch (IllegalAccessException | InstantiationException e) {
throw new InternalError(e.toString());
} catch (InvocationTargetException e) {
Throwable t = e.getCause();
if (t instanceof RuntimeException) {
throw (RuntimeException) t;
} else {
throw new InternalError(t.toString());
}
}
}
其中Class<?> cl = getProxyClass0(loader, intfs)最重要的一步,在java内存中动态生成了一个类文件,通过以下方法我们将这个类文件打印出来一看究竟。
byte[] bytes = ProxyGenerator.generateProxyClass("$Proxy0", CarE.class.getInterfaces());
String path = "/resource/CarProxy.class";
try {
FileOutputStream out = new FileOutputStream(path);
out.write(bytes);
out.flush();
System.out.println("类文件打印成功");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
打印出来的类文件反编译后内容如下所示
1、调用父类构造方法赋值invocationHandler
2、静态代码块中,会列出CarI接口所有的Method对象,作为$Proxy0类的属性持有
3、调用$Proxy0类的服务方法时,实际统一调用的是InvocationHandler.invoke()方法,将方法Method和参数传入。
这样无论CarI接口有多少个方法,都已经实现了代理。InvocationHandler的invoke方法中可以判断method对象,有需要的话可以实现不同的策略。
import com.dengqi.spring.dyproxy.CarI;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
public final class $Proxy0 extends Proxy implements CarI {
private static Method m1;
private static Method m4;
private static Method m3;
private static Method m0;
private static Method m2;
public $Proxy0(InvocationHandler var1) throws {
super(var1);
}
public final boolean equals(Object var1) throws {
try {
return ((Boolean)super.h.invoke(this, m1, new Object[]{var1})).booleanValue();
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final void stop() throws {
try {
super.h.invoke(this, m4, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final void run() throws {
try {
super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final int hashCode() throws {
try {
return ((Integer)super.h.invoke(this, m0, (Object[])null)).intValue();
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final String toString() throws {
try {
return (String)super.h.invoke(this, m2, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[]{Class.forName("java.lang.Object")});
m4 = Class.forName("com.dengqi.spring.dyproxy.CarI").getMethod("stop", new Class[0]);
m3 = Class.forName("com.dengqi.spring.dyproxy.CarI").getMethod("run", new Class[0]);
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
五、总结
动态代理对象$Proxy0 extends Proxy implements CarI,由于java的单继承机制,$Proxy0 extends Proxy后只能处理接口代理,无法实现class代理。
Spring的AOP就是利用Proxy和InvocationHandler来实现的。