闲来无事,简单实现个 AOP 包装类,然而用处并不大,请酌情观看。
public class Test {
public static void main(String[] args) throws Exception {
Stu stu = new Stu();
// Person p = ProxyWrapper.newProxyInstance(stu, CallTimeEnum.atAfter, MethodPool::timeLog);
// Person p = ProxyWrapper.newProxyInstance(stu, CallTimeEnum.atBefore, MethodPool::timeLog);
Person p = ProxyWrapper.newProxyInstance(stu, CallTimeEnum.atException, MethodPool::whenEx);
p.talk();
p.walk();
p.eat();
}
}
/**
* 对 JDK 动态代理进行简单包装
*
* @Author zaiLuShang
*/
class ProxyWrapper {
private ProxyWrapper() {
}
/**
* newProxyInstance(一个需要被增强的对象,在什么时机,调用一个什么样的增强方法)
*
* @see CallTimeEnum 增强时机
* @see MethodPool 增强方法
*/
public static <T extends K, K> K newProxyInstance(T t, CallTimeEnum callTimeEnum, Con4<Method, Object[], Object, Object[]> biConsumer) {
Optional.ofNullable(t).orElseThrow(() -> new IllegalArgumentException("目标对象不能为空"));
Class<?> cls = t.getClass();
// 不需要再显示强转,但需用父接口接受
return (K) Proxy.newProxyInstance(cls.getClassLoader(), cls.getInterfaces(),
// 代理对象后续并没什么用,传参 1.调用方法 2.调用方法参数 3.需要被增强的目标对象 4.需要执行的增强方法
(proxy, method, args) -> callTimeMap.get(callTimeEnum).apply(method, args, t, biConsumer));
}
private static Map<CallTimeEnum, Fun4<Method, Object[], Object, Con4<Method, Object[], Object, Object[]>, Object>> callTimeMap = new HashMap<>() {{
// 前置增强
put(CallTimeEnum.atBefore, (method, args, target, con4) -> {
Object result;
try {
// 于目标方法调用之前执行,这里可以再传入一个执行列表 或者 忽略列表,于什么方法执行时才执行,对方法名进行判断
// 这里不做判断就会导致所有方法被增强
con4.accept(method, args, target, new Object[]{});// 最后一个数组用于额外参数的传递
result = method.invoke(target, args);
} catch (IllegalAccessException | InvocationTargetException e) {
result = null;
e.printStackTrace();
}
return result;
});
// 后置增强
put(CallTimeEnum.atAfter, (method, args, target, con4) -> {
Object result;
try {
result = method.invoke(target, args);
// 于目标方法调用成功之后执行
con4.accept(method, args, target, new Object[]{});
} catch (IllegalAccessException | InvocationTargetException e) {
result = null;
e.printStackTrace();
}
return result;
});
// 异常增强
put(CallTimeEnum.atException, (method, args, target, con4) -> {
Object result;
try {
result = method.invoke(target, args);
} catch (IllegalAccessException | InvocationTargetException e) {
result = null;
e.printStackTrace();
// 于异常发生时执行
con4.accept(method, args, target, new Object[]{e});
}
return result;
});
// 最终增强
put(CallTimeEnum.atFinally, (method, args, target, con4) -> {
Object result;
try {
result = method.invoke(target, args);
} catch (IllegalAccessException | InvocationTargetException e) {
result = null;
e.printStackTrace();
} finally {
// 于方法最终始终执行
con4.accept(method, args, target, new Object[]{});
}
return result;
});
}};
}
/**
* 增强方法的调用时机
*
* @Author zaiLuShang
*/
enum CallTimeEnum {
atBefore,
atAfter,
// around,
atException,
atFinally
}
/**
* 4个参数带返回值接口
*
* @Author zaiLuShang
*/
@FunctionalInterface
interface Fun4<P1, P2, P3, P4, R> {
R apply(P1 p1, P2 p2, P3 p3, P4 p4);
}
/**
* 消费型4参数接口
*
* @Author zaiLuShang
*/
@FunctionalInterface
interface Con4<P1, P2, P3, P4> {
void accept(P1 p1, P2 p2, P3 p3, P4 p4);
}
/**
* 增强方法封装,提供静态方法引用
*
* @Author zaiLuShang
*/
@Slf4j
class MethodPool {
// 执行日志
public static void timeLog(Method method, Object[] args, Object target, Object[] others) {
log.info("方法:{} 当前时间:{}", method.getName(), LocalDateTime.now());
}
// 异常处理策略
public static void whenEx(Method method, Object[] args, Object target, Object[] others) {
// 自旋尝试指定次数
int attempts = 3;
do {
try {
// 重复执行方法
method.invoke(target, args);
// 执行成功结束方法
return;
} catch (Exception e) {
attempts--;
log.error("重复执行失败", e);
}
} while (attempts > 0);
// 依旧失败,给负责人发邮件,发信息,加班 伪代码
// 判断异常等级 执行响应的逻辑 如:记录日志、给负责人提醒
// sendMex("你写的锤子代码?出错了,快来加班");
}
}
// 测试接口
interface Person {
default void walk() {
System.out.println("person walk ...");
}
default void talk() {
System.out.println("person talk ...");
}
default void eat() {
// if (1 == 1) throw new RuntimeException("天真热啊!");
System.out.println("person eat ...");
}
}
// 测试类
class Stu implements Person {
}
嗯 ~~?写的什么玩意?我还是用 AspectJ 吧。