动态代理实现的两种方式:
jdk内置动态代理
cglib
jdk内置:
在java.lang.reflect包下有一个工具类:
Proxy存在一个方法:
@CallerSensitive
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h) throws IllegalArgumentException{
ClassLoader: 类加载器 传入的就是原有对象的类加载器,原有对象.getClass().getClassLoader();
interfaces: 接口数组 传入原有对象实现的所有接口 原有对象.getClass().getinterfaces();
invocationHandler: 执行处理类对象
可以看一下源码:
public interface InvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
}
它是一个接口,只有一个invoke方法
proxy: 代理对象
method: 增强对象在调用方法的时候的方法本身
args: 增强对象调用方法的时候传入的实参数组本身.
可能不太好理解,直接用代码来演示一下:
定义接口car:
public interface Car {
void run();
void stop();
int oilTank(); //油箱大小
void driver(String diverName);
Car didi();
}
qq车实现类:
public class QQ implements Car {
@Override
public void run() {
try {
Thread.sleep(1000);
System.out.println("qq完成百公里加速");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Override
public void stop() {
System.out.println("刹车");
}
@Override
public int oilTank() {
return 50;
}
@Override
public void driver(String diverName) {
System.out.println(diverName+"正在驾驶中");
}
@Override
public Car didi() {
System.out.println("按喇叭");
return this;
}
}
此时我想获取qq完成百公里加速花费的时间,通过动态代理:
/**
* 动态代理实现
*/
public class ProxyTest2 {
public static void main(String[] args) {
QQ qq = new QQ();
Car car =(Car)Proxy.newProxyInstance(
qq.getClass().getClassLoader(),
qq.getClass().getInterfaces(),
new ZQHandler(qq));
car.run();
car.stop();
car.driver("小明");
int i = car.oilTank();
System.out.println(i);
car.didi();
}
private static class ZQHandler implements InvocationHandler{
private Car car;
public ZQHandler(Car car){
this.car = car;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// method.invoke(car);
//当前方法名称
System.out.println(method.getName());
//当前方法名称为run时则进行增强
if ("run".equals(method.getName())){
long start = System.currentTimeMillis();
//调用原有方法
method.invoke(car);
long end = System.currentTimeMillis();
System.out.println("花费时间: " + (end-start));
}else if("driver".equals(method.getName())){
System.out.println(args[0]);
method.invoke(car,"小红");
}else if("oilTank".equals(method.getName())){
Object o = method.invoke(car);
return (Integer)o+50;
}else if("didi".equals(method.getName())){
method.invoke(car);
//返回增强对象
return proxy;
}else {
//调用原有方法
method.invoke(car);
}
return null;
}
}
}
输出结果:
根据结果可以看出不仅仅可以针对逻辑增强,对参数和返回值都可以进行增强.
实现原理:
我们先使用ProxyGenerator对象通过Car接口生成一个class文件存入到本地,稍后会提到为什么会说到ProxyGenerator对象
public class ProxyTest {
public static void main(String[] args) throws IOException {
byte[] xes = ProxyGenerator.generateProxyClass("X", new Class[]{Car.class});
FileOutputStream fileOutputStream = new FileOutputStream("D:\\X.class");
fileOutputStream.write(xes);
}
}
在本地用java反编译工具打开class文件:
import com.ceeemall.aop.service.Car;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
public final class X extends Proxy
implements Car
{
private static Method m1;
private static Method m6;
private static Method m3;
private static Method m2;
private static Method m4;
private static Method m5;
private static Method m7;
private static Method m0;
public X(InvocationHandler paramInvocationHandler)
throws
{
super(paramInvocationHandler);
}
public final boolean equals(Object paramObject)
throws
{
try
{
return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
public final Car didi()
throws
{
try
{
return (Car)this.h.invoke(this, m6, null);
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
public final void run()
throws
{
try
{
this.h.invoke(this, m3, null);
return;
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
public final String toString()
throws
{
try
{
return (String)this.h.invoke(this, m2, null);
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
public final void stop()
throws
{
try
{
this.h.invoke(this, m4, null);
return;
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
public final int oilTank()
throws
{
try
{
return ((Integer)this.h.invoke(this, m5, null)).intValue();
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
public final void driver(String paramString)
throws
{
try
{
this.h.invoke(this, m7, new Object[] { paramString });
return;
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
public final int hashCode()
throws
{
try
{
return ((Integer)this.h.invoke(this, m0, null)).intValue();
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
static
{
try
{
m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
m6 = Class.forName("com.ceeemall.aop.service.Car").getMethod("didi", new Class[0]);
m3 = Class.forName("com.ceeemall.aop.service.Car").getMethod("run", new Class[0]);
m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
m4 = Class.forName("com.ceeemall.aop.service.Car").getMethod("stop", new Class[0]);
m5 = Class.forName("com.ceeemall.aop.service.Car").getMethod("oilTank", new Class[0]);
m7 = Class.forName("com.ceeemall.aop.service.Car").getMethod("driver", new Class[] { Class.forName("java.lang.String") });
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
return;
}
catch (NoSuchMethodException localNoSuchMethodException)
{
throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
}
catch (ClassNotFoundException localClassNotFoundException)
{
throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
}
}
}
首先是可以看到生成的类继承了Proxy类实现了我们的Car接口,因此生成的X类中必定是实现了Car中的所有方法.
比如我们可以看到run方法,
public final void run()
throws
{
try
{
this.h.invoke(this, m3, null);
return;
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
这个h是父类Proxy中的,指的是invocationHandler接口,因为是protected修饰,因此在子类通过this可以访问:
/**
* the invocation handler for this proxy instance.
* @serial
*/
protected InvocationHandler h;
/**
* Constructs a new {@code Proxy} instance from a subclass
* (typically, a dynamic proxy class) with the specified value
* for its invocation handler.
*
* @param h the invocation handler for this proxy instance
*
* @throws NullPointerException if the given invocation handler, {@code h},
* is {@code null}.
*/
protected Proxy(InvocationHandler h) {
Objects.requireNonNull(h);
this.h = h;
}
再往下看可以看到对静态变量m的定义:
static
{
try
{
m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
m6 = Class.forName("com.ceeemall.aop.service.Car").getMethod("didi", new Class[0]);
m3 = Class.forName("com.ceeemall.aop.service.Car").getMethod("run", new Class[0]);
m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
m4 = Class.forName("com.ceeemall.aop.service.Car").getMethod("stop", new Class[0]);
m5 = Class.forName("com.ceeemall.aop.service.Car").getMethod("oilTank", new Class[0]);
m7 = Class.forName("com.ceeemall.aop.service.Car").getMethod("driver", new Class[] { Class.forName("java.lang.String") });
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
return;
}
catch (NoSuchMethodException localNoSuchMethodException)
{
throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
}
catch (ClassNotFoundException localClassNotFoundException)
{
throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
}
}
通过反射获取Car接口中所有的方法.
这样步骤就比较清晰了, 生成的类X我们可以理解为代理类,他实现了原有类实现的接口Car,同时继承了Proxy,代理类通过父类Proxy的成员变量InvocationHandler,调用其invoke方法,而invoke需要三个参数,proxy就是代理对象本身,传入的是this,method代表需要增强方法的本身,如我需要执行run(); 则method就是run()方法对象,即m3, args则为参数数据,run()没有参数则为null
然后我们再来看一下Proxy中newProxyInstance做了什么事情:
@CallerSensitive
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
Objects.requireNonNull(h);
final Class<?>[] intfs = interfaces.clone();
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
}
/*
* Look up or generate the designated proxy class.
*/
Class<?> cl = getProxyClass0(loader, intfs);
/*
* Invoke its constructor with the designated invocation handler.
*/
try {
if (sm != null) {
checkNewProxyPermission(Reflection.getCallerClass(), cl);
}
final Constructor<?> cons = cl.getConstructor(constructorParams);
final InvocationHandler ih = h;
if (!Modifier.isPublic(cl.getModifiers())) {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
cons.setAccessible(true);
return null;
}
});
}
return cons.newInstance(new Object[]{h});
} catch (IllegalAccessException|InstantiationException e) {
throw new InternalError(e.toString(), e);
} catch (InvocationTargetException e) {
Throwable t = e.getCause();
if (t instanceof RuntimeException) {
throw (RuntimeException) t;
} else {
throw new InternalError(t.toString(), t);
}
} catch (NoSuchMethodException e) {
throw new InternalError(e.toString(), e);
}
}
先挑几步重点来看:
final Class<?>[] intfs = interfaces.clone(); 克隆了实现的接口
Class<?> cl = getProxyClass0(loader, intfs); //获取代理对象
final Constructor<?> cons = cl.getConstructor(constructorParams); //获取代理对象的构造器
return cons.newInstance(new Object[]{h}); //通过构造方法创建实例,invocationHandler的数组为参数
点进getProxyClass0(loader, intfs);,多点几次点到apply();
前面是一系列的判断 + 类名及路径的拼接
然后有这样一行代码:
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces, accessFlags);
try {
return defineClass0(loader, proxyName,
proxyClassFile, 0, proxyClassFile.length);
} catch (ClassFormatError e) {
/*
* A ClassFormatError here means that (barring bugs in the
* proxy class generation code) there was some other
* invalid aspect of the arguments supplied to the proxy
* class creation (such as virtual machine limitations
* exceeded).
*/
throw new IllegalArgumentException(e.toString());
}
就是通过ProxyGenerator对象创建代理对象的.后面的defineClass0()方法是将字节数组转化成class对象的操作,就不看了,因为我也看不懂.