JDK 动态代理/手写 AOP/Proxy 增强

闲来无事,简单实现个 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 吧。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值