package com.bzyd.test.jdk_proxy_;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* @Description JDK动态代理示例
* @Author dangxianyue
* @Date 2022/9/25 1:05
*/
public class JdkDynamicProxyTest {
public static void main(String[] args) {
// 让代理对象的class文件写入到磁盘
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
Suitor suitor = new Suitor();//被代理者
InvocationHandler h = new ProxyEnhancer(suitor);//增强器
/**
* 创建代理类实例,Proxy就是个空壳,需要指定一下三个参数,才能生成代理类实例
* 第一个参数,ClassLoader loader,指定代理类的类加载器
* 第二个参数:Class>[] interfaces,指定代理类要实现的接口列表
* 第三个参数:InvocationHandler h,指定代理类的增强逻辑
*/
Object _proxy = Proxy.newProxyInstance(suitor.getClass().getClassLoader(), suitor.getClass().getInterfaces(), h);
System.out.println("_proxy: " + _proxy.getClass().getSuperclass().getName());
//_proxy: java.lang.reflect.Proxy
//从这里可以看出,JDK创建出来的代理类对象都继承了Proxy类,
//实际上是,_proxy extends Proxy implements LoveLetter,但不是被代理者Suitor的子类,这是和Cglib代理的区别之一
//而Java是单继承的,所以被代理者Suitor必须实现接口
//@Aurowired
//private xxxImpl xxx;
//当用到代理类的场景时,这里用实现类接收会报错,得用接口去接收
LoveLetter loveLetter = (LoveLetter) _proxy;
loveLetter.sendLetter("小丽");//调用代理类对象
//结果:
//_proxy: java.lang.reflect.Proxy
//增强逻辑【送情书】>>>>>>>>>>>>>开始
//写情书:小丽,我喜欢你! (此处可以看出类内调用没有被代理增强)
//送情书:小丽,这是有人送你的情书!
//增强逻辑【送情书】>>>>>>>>>>>>>结束
}
}
/**
* 求爱接口
*/
interface LoveLetter {
/**
* 写情书
*
* @param name
*/
void writeLetter(String name);
/**
* 送情书
*
* @param name
*/
void sendLetter(String name);
}
/**
* 追求者,被代理者
* JDK代理是接口代理,被代理类必须实现某个接口
*/
class Suitor implements LoveLetter {
@Override
public void writeLetter(String name) {
System.out.println("写情书:" + name + ",我喜欢你!");
}
@Override
public void sendLetter(String name) {
//注意,类内自调用,即,反射调用被代理者原逻辑,而原逻辑内又调用本类方法
//相当于this.writeLetter(name),调用到的是被代理者的方法,而不是通过代理类调用到的增强方法
//所以这就是为什么类内调用不被代理增强的原因
//也就是@Transactional事务注解,在类内调用时无效的原因!!!
writeLetter(name);
System.out.println("送情书:" + name + ",这是有人送你的情书!");
}
}
/**
* 代理增强类
* 封装增强逻辑
* 必须实现java.lang.reflect.InvocationHandler接口
*/
class ProxyEnhancer implements InvocationHandler {
/**
* 被代理对象,反射调用方法要用到实例,所以得自己保存
*/
private Suitor suitor;
public ProxyEnhancer(Suitor suitor) {
this.suitor = suitor;
}
/**
* 增强逻辑
* 底层原理是使用反射调用对象的方法
* 效率比AspectJ预编译静态代理慢得多
* 但不需要额外的编译,是在运行时动态生成代理增强类
*
* @param proxy Proxy.newProxyInstance创建出来的代理类Proxy的一个实例
* @param method 被代理对象suitor反射出来的被代理的方法
* @param args 方法参数,反射调用要用到
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String s = "writeLetter".equals(method.getName()) ? "写情书" :
("sendLetter".equals(method.getName()) ? "送情书" : "");
System.out.println("增强逻辑【"+s+"】>>>>>>>>>>>>>开始");
Object invoke = method.invoke(suitor, args);
System.out.println("增强逻辑【"+s+"】>>>>>>>>>>>>>结束");
return invoke;
}
}