动态代理
JDK动态代理
JDK动态代理是使用Java提供的一个动态代理类Proxy,根据其提供的静态方法newProxyInstance,来动态的在内存中构建代理对象。
注意:目标类需实现接口
应用实例:
- 定义一个老师的接口:ITeacher
- 目标对象(被代理对象) LiTeacher 实现接口 ITeacher
- 代理类ProxyFactory,聚合一个Object类型的属性(通过构造器注入目标对象),使用Proxy.newInstance()生成代理对象
- 通过返回的代理对象来调用目标对象的方法
代码示例:
// 目标类所实现的接口
public interface ITeacher {
void teach();
}
// 目标类
// 目标类
public class LiTeacher implements ITeacher{
@Override
public void teach() {
System.out.println("正在上课中...");
}
}
// 生成代理对象的工厂
public class ProxyFactory {
private Object target;
public ProxyFactory(Object target) {
this.target = target;
}
// 获取代理对象的方法
public Object getProxyInstance() {
/*
该方法三个参数:
ClassLoader loader:类加载器,用于加载代理类。可以通过目标对象获取
Class<?>[] interfaces:目标对象所属类实现的接口的字节码对象[]
InvocationHandler h:代理对象的调用处理程序
*/
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new InvocationHandler() {
/*
Object invoke: 代理对象
Method method: 对接口方法进行封装的method对象
Object[] args: 调用方法的实际参数
*/
@Override
public Object invoke(Object proxy, Method method,
Object[] args) throws Throwable {
System.out.println("增强操作1...");
// 反射机制调用目标方法
Object returnVal = method.invoke(target, args);
System.out.println("增强操作2...");
return returnVal;
}
});
}
}
// 测试类
public class Main {
public static void main(String[] args) {
// 创建目标对象
LiTeacher target = new LiTeacher();
// 创建代理工厂对象
ProxyFactory factory = new ProxyFactory(target);
// 获取代理对象
ITeacher proxyObject = (ITeacher)factory.getProxyInstance();
proxyObject.teach();//com.sun.proxy.$Proxy0
}
}
// 打印结果:
增强操作1...
正在上课中...
增强操作2...
JDK动态代理原理:
调用Proxy.newProxyInstance()
方法后,会在内存中生成代理类com.sun.proxy.$Proxy0
,该代理类会持有一个InvocationHandler
接口的实例类的引用。通过构造器传递给父类Proxy
从下方对$Proxy0
反编译的代码中可以看出,在我们使用代理类调用方法proxyObject.teach()
时,会自动调用当前代理对象父类Proxy
的引用属性protected InvocationHandler h;
的 .invoke()
方法。
并将当前代理对象this
,当前 被调用方法的** 方法对象**m3
,当前方法参数封装成Object数组(Object[])null
,一并传递。
该引用对象属性protected InvocationHandler h;
即为我们自己所编写的new InvocationHandler(){...};
匿名内部类对象。
进入匿名内部类后,通过Object returnVal = method.invoke(target, args);
反射原理,调用目标对象的方法。也会先后执行我们的增强操作
简单来说: 调用代理对象方法proxyObject.teach()
-> 会自动调用匿名内部类InvocationHandler
的invoke
方法并将当前方法信息传递 -> 执行目标对象的方法 -> 前后也可执行我们的增强方法
进行反编译后,代理类$Proxy0
结构:
public final class class extends Proxy
implements Iteacer {
private static Method m1;
private static Method m8;
private static Method m2;
private static Method m3;
private static Method m6;
private static Method m5;
private static Method m7;
private static Method m9;
private static Method m0;
private static Method m4;
public class(InvocationHandler invocationhandler) //通过构造将handler传入
{
super(invocationhandler);
}
...
public final void teach() throws {
try {
super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
...
}
使用IO的方式将内存中代理类写入到文件中:
/**
* 使用IO的方式将内存中代理类写入到文件中,然后反编译出来进行观察
*/
private static void createProxyClassFile() {
byte[] data = ProxyGenerator.generateProxyClass("$Proxy0.class", new Class[] {LiTeacher.class});
try {
FileOutputStream out = new FileOutputStream("$Proxy0.class");
out.write(data);
out.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}