代理模式增强拒绝策略
一.静态代理与动态代理
1.概述
代理类型 | 含义 | 代码实现 | 典型应用 |
---|---|---|---|
静态代理 | 代理类在编译时已经写好,代理对象和被代理对象的代码明确存在 | 手写代理类,代理类实现同样接口或继承同样父类,组合被代理对象 | 日志、权限控制、事务处理等 |
动态代理 | 代理类在运行时通过反射动态生成,代理对象由系统自动创建 | 利用 Java Proxy 类和 InvocationHandler 反射机制 |
AOP、RPC 框架、接口增 |
2.原理与使用示例
静态代理:
静态代理是开发者事先编写一个代理类,代理类实现目标接口,持有目标对象引用,调用代理类方法时,代理类先做一些增强逻辑,再调用目标对象对应方法。
// 目标接口
public interface Service {
void execute();
}
// 目标实现
public class ServiceImpl implements Service {
@Override
public void execute() {
System.out.println("执行核心业务逻辑");
}
}
// 静态代理类
public class ServiceProxy implements Service {
private final Service target;
public ServiceProxy(Service target) {
this.target = target;
}
@Override
public void execute() {
System.out.println("执行前置增强");
target.execute();
System.out.println("执行后置增强");
}
}
优点 | 缺点 |
---|---|
逻辑清晰,易理解 | 每个接口需要写一个代理类,代码臃肿 |
调试方便,堆栈清晰 | 不灵活,扩展性差,新增接口需要增加代理类 |
适合接口少且业务简单 | 增加代码维护成本 |
动态代理:
动态代理是在运行时动态生成代理类,通过反射机制调用代理逻辑,实现统一代理。核心组件:
java.lang.reflect.Proxy
:用于创建动态代理实例。java.lang.reflect.InvocationHandler
:代理方法调用的处理器。
代理对象实现了目标接口,所有方法调用都会被 InvocationHandler
的 invoke
方法拦截处理。
关键接口和类
InvocationHandler
public interface InvocationHandler {
Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}
proxy
:代理对象本身,一般不直接调用。method
:当前被调用的方法。args
:方法参数。
Proxy
类
public class Proxy {
public static Object newProxyInstance(
ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h) {
// 生成代理类字节码,返回代理对象实例
}
}
loader
:类加载器,代理类由它加载。interfaces
:代理类实现的接口列表。h
:方法调用处理器。
实例:
public interface Service {
void execute();
}
public class ServiceImpl implements Service {
@Override
public void execute() {
System.out.println("执行核心业务");
}
}
public class ServiceInvocationHandler implements InvocationHandler {
private final Object target;
public ServiceInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("前置增强");
Object result = method.invoke(target, args);
System.out.println("后置增强");
return result;
}
}
调用:
Service target = new ServiceImpl();
Service proxy = (Service) Proxy.newProxyInstance(
target.getClass().getClassLoader(),
new Class[]{Service.class},
new ServiceInvocationHandler(target)
);
proxy.execute();
注意点:
优点 | 缺点 |
---|---|
代理类无需提前编写,灵活 | 只能代理接口(JDK 动态代理) |
统一拦截所有方法,减少代码量 | 调试难,异常堆栈不直观 |
运行时生成,支持高度动态 | 性能略低于静态代理 |
易扩展,广泛应用于 AOP、RPC | 不支持代理普通类(需 CGLIB) |
如果只想拦截特定方法:
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if ("targetMethodName".equals(method.getName())) {
// 只增强指定方法
System.out.println("执行增强逻辑");
}
// 调用目标对象方法
return method.invoke(target, args);
}
二.动态代理增强
@AllArgsConstructor
public class RejectedProxyInvocationHandler implements InvocationHandler {
private final Object target;
private final String threadPoolId;
private final AtomicLong rejectCount;
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
rejectCount.incrementAndGet();
// TODO 触发拒绝策略异常告警
try {
return method.invoke(target, args);
} catch (InvocationTargetException ex) {
throw ex.getCause();
}
}
}
在我们的自定义线程池内使用代理拒绝策略
public OneThreadExecutor(
@NonNull String threadPoolId,
int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
@NonNull TimeUnit unit,
@NonNull BlockingQueue<Runnable> workQueue,
@NonNull ThreadFactory threadFactory,
@NonNull RejectedExecutionHandler handler) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler);
// 通过动态代理设置拒绝策略执行次数
RejectedExecutionHandler rejectedProxy = (RejectedExecutionHandler) Proxy
.newProxyInstance(
handler.getClass().getClassLoader(),
new Class[]{RejectedExecutionHandler.class},
new RejectedProxyInvocationHandler(handler, threadPoolId, rejectCount)
);
setRejectedExecutionHandler(rejectedProxy);
// 设置动态线程池扩展属性:线程池 ID 标识
this.threadPoolId = threadPoolId;
}
三.静态代理增强
public class RejectCountingHandler implements RejectedExecutionHandler {
private final RejectedExecutionHandler delegate;
private final String threadPoolId;
private final AtomicLong rejectCount;
public RejectCountingHandler(RejectedExecutionHandler delegate, String threadPoolId, AtomicLong rejectCount) {
this.delegate = delegate;
this.threadPoolId = threadPoolId;
this.rejectCount = rejectCount;
}
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
rejectCount.incrementAndGet();
// 可插入报警逻辑
// log.warn("[线程池拒绝] id={},累计拒绝次数={}", threadPoolId, rejectCount.get());
delegate.rejectedExecution(r, executor); // 调用原始拒绝策略
}
}
在我们的自定义线程池内使用代理拒绝策略
RejectedExecutionHandler rejectedProxy = new RejectCountingHandler(handler, threadPoolId, rejectCount);