static Object | newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h) 返回一个指定接口的代理类实例,该接口可以将方法调用指派到指定的调用处理程序。 |
在调用代理对象中的每一个方法时,在代码内部,都是直接调用了InvocationHandler 的invoke方法,而invoke方法根据代理类传递给自己的method参数来区分是什么方法。
Object | invoke(Object proxy,Method method,Object[] args) 在代理实例上处理方法调用并返回结果。 |
讲的有点抽象,下面通过一个实例来演示一下吧:
JDK动态代理示例
现在定义两个接口Vehicle和Rechargable,Vehicle表示交通工具类,有drive()方法;Rechargable接口表示可充电的(工具),有recharge() 方法;
定义一个实现两个接口的类ElectricCar,类图如下:
通过下面的代码片段,来为ElectricCar创建动态代理类:
package com.foo.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
public class Test {
public static void main(String[] args) {
ElectricCar car = new ElectricCar();
// 1.获取对应的ClassLoader
ClassLoader classLoader = car.getClass().getClassLoader();
// 2.获取ElectricCar 所实现的所有接口
Class[] interfaces = car.getClass().getInterfaces();
// 3.设置一个来自代理传过来的方法调用请求处理器,处理所有的代理对象上的方法调用
InvocationHandler handler = new InvocationHandlerImpl(car);
/*
4.根据上面提供的信息,创建代理对象 在这个过程中,
a.JDK会通过根据传入的参数信息动态地在内存中创建和.class 文件等同的字节码
b.然后根据相应的字节码转换成对应的class,
c.然后调用newInstance()创建实例
*/
Object o = Proxy.newProxyInstance(classLoader, interfaces, handler);
Vehicle vehicle = (Vehicle) o;
vehicle.drive();
Rechargable rechargeable = (Rechargable) o;
rechargeable.recharge();
}
}
package com.foo.proxy;
/**
* 交通工具接口
* @author louluan
*/
public interface Vehicle {
public void drive();
}
package com.foo.proxy;
/**
* 可充电设备接口
* @author louluan
*/
public interface Rechargable {
public void recharge();
}
package com.foo.proxy;
/**
* 电能车类,实现Rechargable,Vehicle接口
* @author louluan
*/
public class ElectricCar implements Rechargable, Vehicle {
@Override
public void drive() {
System.out.println("Electric Car is Moving silently...");
}
@Override
public void recharge() {
System.out.println("Electric Car is Recharging...");
}
}
package com.foo.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class InvocationHandlerImpl implements InvocationHandler {
private ElectricCar car;
public InvocationHandlerImpl(ElectricCar car)
{
this.car=car;
}
@Override
public Object invoke(Object paramObject, Method paramMethod,
Object[] paramArrayOfObject) throws Throwable {
System.out.println("You are going to invoke "+paramMethod.getName()+" ...");
paramMethod.invoke(car, null);
System.out.println(paramMethod.getName()+" invocation Has Been finished...");
return null;
}
}
来看一下代码执行后的结果:
![\](https://i-blog.csdnimg.cn/blog_migrate/fcbcdd4367d438e784047dc88f55f40f.jpeg)
生成动态代理类的字节码并且保存到硬盘中:
JDK提供了sun.misc.ProxyGenerator.generateProxyClass(String proxyName,class[] interfaces) 底层方法来产生动态代理类的字节码:
下面定义了一个工具类,用来将生成的动态代理类保存到硬盘中:
package com.foo.proxy;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.Proxy;
import sun.misc.ProxyGenerator;
public class ProxyUtils {
/*
* 将根据类信息 动态生成的二进制字节码保存到硬盘中,
* 默认的是clazz目录下
* params :clazz 需要生成动态代理类的类
* proxyName : 为动态生成的代理类的名称
*/
public static void generateClassFile(Class clazz,String proxyName)
{
//根据类信息和提供的代理类名称,生成字节码
byte[] classFile = ProxyGenerator.generateProxyClass(proxyName, clazz.getInterfaces());
String paths = clazz.getResource(".").getPath();
System.out.println(paths);
FileOutputStream out = null;
try {
//保留到硬盘中
out = new FileOutputStream(paths+proxyName+".class");
out.write(classFile);
out.flush();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
现在我们想将生成的代理类起名为“ElectricCarProxy”,并保存在硬盘,应该使用以下语句:
ProxyUtils.generateClassFile(car.getClass(), "ElectricCarProxy");
这样将在ElectricCar.class 同级目录下产生 ElectricCarProxy.class文件。用反编译工具如jd-gui.exe 打开,将会看到以下信息:
import com.foo.proxy.Rechargable;
import com.foo.proxy.Vehicle;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
/**
生成的动态代理类的组织模式是继承Proxy类,然后实现需要实现代理的类上的所有接口,而在实现的过程中,则是通过将所有的方法都交给了InvocationHandler来处理
*/
public final class ElectricCarProxy extends Proxy
implements Rechargable, Vehicle
{
private static Method m1;
private static Method m3;
private static Method m4;
private static Method m0;
private static Method m2;
public ElectricCarProxy(InvocationHandler paramInvocationHandler)
throws
{
super(paramInvocationHandler);
}
public final boolean equals(Object paramObject)
throws
{
try
{ // 方法功能实现交给InvocationHandler处理
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 void recharge()
throws
{
try
{
// 方法功能实现交给InvocationHandler处理
this.h.invoke(this, m3, null);
return;
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
public final void drive()
throws
{
try
{
// 方法功能实现交给InvocationHandler处理
this.h.invoke(this, m4, null);
return;
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
public final int hashCode()
throws
{
try
{
// 方法功能实现交给InvocationHandler处理
return ((Integer)this.h.invoke(this, m0, null)).intValue();
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
public final String toString()
throws
{
try
{
// 方法功能实现交给InvocationHandler处理
return (String)this.h.invoke(this, m2, null);
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
static
{
try
{ //为每一个需要方法对象,当调用相应的方法时,分别将方法对象作为参数传递给InvocationHandler处理
m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
m3 = Class.forName("com.foo.proxy.Rechargable").getMethod("recharge", new Class[0]);
m4 = Class.forName("com.foo.proxy.Vehicle").getMethod("drive", 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]);
return;
}
catch (NoSuchMethodException localNoSuchMethodException)
{
throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
}
catch (ClassNotFoundException localClassNotFoundException)
{
throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
}
}
}
仔细观察可以看出生成的动态代理类有以下特点:
1.继承自 java.lang.reflect.Proxy,实现了 Rechargable,Vehicle 这两个ElectricCar实现的接口;
2.类中的所有方法都是final 的;
3.所有的方法功能的实现都统一调用了InvocationHandler的invoke()方法。
cglib 生成动态代理类的机制----通过类继承:
JDK中提供的生成动态代理类的机制有个鲜明的特点是: 某个类必须有实现的接口,而生成的代理类也只能代理某个类接口定义的方法,比如:如果上面例子的ElectricCar实现了继承自两个接口的方法外,另外实现了方法bee() ,则在产生的动态代理类中不会有这个方法了!更极端的情况是:如果某个类没有实现接口,那么这个类就不能同JDK产生动态代理了!
幸好我们有cglib。“CGLIB(Code Generation Library),是一个强大的,高性能,高质量的Code生成类库,它可以在运行期扩展Java类与实现Java接口。”
cglib 创建某个类A的动态代理类的模式是:
1. 查找A上的所有非final 的public类型的方法定义;
2. 将这些方法的定义转换成字节码;
3. 将组成的字节码转换成相应的代理的class对象;
4. 实现 MethodInterceptor接口,用来处理 对代理类上所有方法的请求(这个接口和JDK动态代理InvocationHandler的功能和角色是一样的)
一个有趣的例子:定义一个Programmer类,一个Hacker类
package samples;
/**
* 程序猿类
* @author louluan
*/
public class Programmer {
public void code()
{
System.out.println("I'm a Programmer,Just Coding.....");
}
}
package samples;
import java.lang.reflect.Method;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
/*
* 实现了方法拦截器接口
*/
public class Hacker implements MethodInterceptor {
@Override
public Object intercept(Object obj, Method method, Object[] args,
MethodProxy proxy) throws Throwable {
System.out.println("**** I am a hacker,Let's see what the poor programmer is doing Now...");
proxy.invokeSuper(obj, args);
System.out.println("**** Oh,what a poor programmer.....");
return null;
}
}
package samples;
import net.sf.cglib.proxy.Enhancer;
public class Test {
public static void main(String[] args) {
Programmer progammer = new Programmer();
Hacker hacker = new Hacker();
//cglib 中加强器,用来创建动态代理
Enhancer enhancer = new Enhancer();
//设置要创建动态代理的类
enhancer.setSuperclass(progammer.getClass());
// 设置回调,这里相当于是对于代理类上所有方法的调用,都会调用CallBack,而Callback则需要实行intercept()方法进行拦截
enhancer.setCallback(hacker);
Programmer proxy =(Programmer)enhancer.create();
proxy.code();
}
}
程序执行结果:
![\](https://i-blog.csdnimg.cn/blog_migrate/623e3ccf711af826aae18405441031a4.jpeg)
让我们看看通过cglib生成的class文件内容:
package samples;
import java.lang.reflect.Method;
import net.sf.cglib.core.ReflectUtils;
import net.sf.cglib.core.Signature;
import net.sf.cglib.proxy.Callback;
import net.sf.cglib.proxy.Factory;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
public class Programmer$$EnhancerByCGLIB$$fa7aa2cd extends Programmer
implements Factory
{
//......省略
private MethodInterceptor CGLIB$CALLBACK_0; // Enchaner传入的methodInterceptor
// ....省略
public final void code()
{
MethodInterceptor tmp4_1 = this.CGLIB$CALLBACK_0;
if (tmp4_1 == null)
{
tmp4_1;
CGLIB$BIND_CALLBACKS(this);//若callback 不为空,则调用methodInterceptor 的intercept()方法
}
if (this.CGLIB$CALLBACK_0 != null)
return;
//如果没有设置callback回调函数,则默认执行父类的方法
super.code();
}
//....后续省略
}