一、概述
在实际开发过程中,往往我们自己不会去创建代理类,而是通过JDK提供的Proxy类在程序运行时,运用反射机制动态创建而成,这就是所谓的动态代理。
1.1、动态代理 vs 静态代理
静态代理需要程序员自己写代理类,动态代理不需要。动态代理虽然不需要程序员自己写代理类了,但是还是需要我们定义对被代理对象直接访问方法的拦截,用于对拦截的方法做增强。动态代理技术在框架中使用的场景很多,例如:MyBatis、Spring、SpringMVC等
二、API
2.1、Proxy
public class Proxy extends Object implements Serializable
提供了用于创建动态代理类和对象的静态方法
2.2、InvocationHandler
三、案例代码
3.1、pom
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
</dependency>
<!-- 普通maven项目中使用Sl4j注解 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.22</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.32</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.10</version>
</dependency>
</dependencies>
3.2、Star
/**
* @Author : 一叶浮萍归大海
* @Date: 2023/10/29 23:31
* @Description: 抽象角色
*/
public interface Star {
/**
* 唱歌
* @param musicName 歌曲名字
* @return
*/
String sing(String musicName);
/**
* 跳舞
*/
void dance();
}
3.3、SuperStar
/**
* @Author : 一叶浮萍归大海
* @Date: 2023/10/29 23:32
* @Description: 被代理角色
*/
@Data
public class SuperStar implements Star {
/**
* 歌手名字
*/
private String starName;
public SuperStar() {
}
public SuperStar(String starName) {
this.starName = starName;
}
@Override
public String sing(String musicName) {
System.out.println(this.starName + "正在唱:" + musicName);
return "谢谢!谢谢!";
}
@Override
public void dance() {
System.out.println(this.starName + "正在优美的跳舞");
}
}
3.4、MyInvocationHandler
@Slf4j
public class MyInvocationHandler implements InvocationHandler {
private Object obj;
public MyInvocationHandler(Object obj) {
this.obj = obj;
}
/**
* 增强逻辑
*
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 目标方法执行之前
log.info("目标方法执行之前执行,目标方法名称:{},入参:{}", method.getName(), Arrays.toString(args));
// 目标方法执行
Object result = method.invoke(obj, args);
// 目标方法执行之后
log.info("目标方法执行之后执行,result:{},obj:{}",result,obj.getClass());
return result;
}
}
3.5、测试
@Slf4j
public class App {
public static void main(String[] args) {
m4();
}
/**
* Star动态代理:实现InvocationHandler接口方式
*/
private static void m4() {
Star targetObj = new SuperStar("杨超越");
MyInvocationHandler proxy = new MyInvocationHandler(targetObj);
Star proxyObj = (Star) Proxy.newProxyInstance(targetObj.getClass().getClassLoader(), targetObj.getClass().getInterfaces(), proxy);
String result = proxyObj.sing("奢香夫人");
System.out.println("result = " + result);
proxyObj.dance();
}
/**
* Star动态代理:匿名内部类方式
*/
private static void m3() {
// target
SuperStar target = new SuperStar("杨超越");
// 被代理对象的类加载器
ClassLoader classLoader = target.getClass().getClassLoader();
// 被代理对象实现的所有接口
Class<?>[] interfaces = target.getClass().getInterfaces();
Star proxyStar = (Star) Proxy.newProxyInstance(classLoader, interfaces, new InvocationHandler() {
/**
* invoke方法的执行实际:
* 代理对象调用方法,就会触发此方法执行
*
* invoke方法的参数:
* 参数1:Object proxy,代理对象,不用!
* 参数2:Method method,代理对象调用的方法,封装Method对象
* 参数3:Object[] args,数组里存放的是代理对象调用目标方法传递的数据
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
log.info("方法名称:{},参数:{}", method.getName(), Arrays.asList(args));
log.info("target Method execute before");
Object result = method.invoke(target, args);
log.info("目标方法返回结果:{}",result);
System.out.println("target Method execute after");
return result;
}
});
System.out.println("proxyStar = " + proxyStar.getClass());
String result = proxyStar.sing("奢香夫人");
System.out.println("result = " + result);
}
}