JDK中的动态代理是通过反射类Proxy以及InvocationHandler回调接口实现的;
JDK中所要进行动态代理的类必须要实现一个接口
需求:
计算一个类中,每个被调用的方法运行时长
package design.patterns.proxy;
public interface IProduct {
String sell(Float money);
void afterSell();
}
package design.patterns.proxy;
import java.util.concurrent.TimeUnit;
public class Product implements IProduct {
@Override
public String sell(Float money) {
System.out.println("代理员交给工厂:" + money);
return "aaa";
}
@Override
public void afterSell() {
System.out.println("代理员做售后。。等待5秒");
try {
TimeUnit.SECONDS.sleep(5);
} catch (Exception ignore) {
}
}
}
package design.patterns.proxy;
import java.lang.reflect.InvocationHandler;
/**
* 类名: MyHandler
* 描述: 添加获取目标实例的方法
* 日期: 2022/6/28-14:08
*/
public abstract class MyHandler<T> implements InvocationHandler {
protected T targetInstance;
public MyHandler(T targetInstance) {
this.targetInstance = targetInstance;
}
public T getTargetInstance() {
return targetInstance;
}
}
动态计算方法运行时长
package design.patterns.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* 类名: CalcTimeHandler
* 描述: 动态计算方法运行时长
* 日期: 2022/6/28-10:59
*/
public class CalcTimeHandler<T> extends MyHandler<T> implements InvocationHandler {
public CalcTimeHandler(T targetInstance) {
super(targetInstance);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//这些方法不进行增强处理控制 //边界判断
if ("equals getClass hashCode toString wait notifyAll".contains(method.getName())) {
return method.invoke(targetInstance, args);
}
long startTime = System.currentTimeMillis();
Object invoke = method.invoke(targetInstance, args);
long end = System.currentTimeMillis();
System.out.format("%s方法执行时间:%s毫秒%n", method.getName(), end - startTime);
return invoke;
}
}
该静态工厂使用的是泛型类
package design.patterns.proxy;
import design.patterns.decorate.CalcTimeHandler;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
/**
* 类名: MyJdkProxyFactory
* 描述:
* 日期: 2022/6/27-17:25
*
*/
public class MyJdkProxyFactory {
/**
* 泛型静态工厂方法:
* 被代理的对象一定要实现一个接口
* @param interfaces
* 被代理对象实例.getClass().getInterfaces()
* @param handler
* {@link InvocationHandler} 接口的实现类
* @param <T>
* @return
*/
private static <T> T getProxy(Class<?>[] interfaces, InvocationHandler handler) {
return (T) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), interfaces, handler);
}
/**
* 对 {@link #getProxy(Class[], InvocationHandler)} 方法的简化
* 增加了一层抽象父类,以方便获取目标实例的class对象 方便扩展
* 泛型静态工厂方法:
* 被代理的对象一定要实现一个接口
* @param handler {@link MyHandler} 接口的实现类
* @param <T>
* @return
*/
private static <T> T getProxy(MyHandler handler) {
return (T) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), handler.getTargetInstance().getClass().getInterfaces(), handler);
}
private static <T> T getProxy2(MyHandler handler) {
return (T) Proxy.newProxyInstance(handler.getClass().getClassLoader(), handler.getTargetInstance().getClass().getInterfaces(), handler);
}
}
public static void main(String[] args) {
IProduct product = new Product();
IProduct productProxy = MyJdkProxyFactory.getProxy(new CalcTimeHandler<>(product));
//无感地对代码进行了动态的增强控制
//调用代理实例的方法对原实例进行动态增强
System.out.println(productProxy.sell(3f));
productProxy.afterSell();
System.out.println(productProxy.hashCode());
System.out.println(product.hashCode());
}
提示:这里对文章进行总结:
在不改变原有代码的基础上对代理对象的方法进行了动态的增强
核心代码逻辑:对代理对象的每个方法进行计算方法调用运行时长