• 代理模式【结构模式】


    代理模式

    Provide a surrogate or placeholder for another object to control access to it.
    为其他对象提供一个代理或占位符来控制对它的访问。
    

    静态代理

    public class StaticProxy {
        @Test
        public void all() {
            final Runner runner = new Runner();
            final RunProxy runProxy = RunProxy.builder().runner(runner).build();
            // 通过代理角色实现对真实角色的访问控制
            runProxy.run();
        }
    }
    
    /**
     * 1)需要执行代理的行为
     */
    interface IRun {
        void run();
    }
    
    /**
     * 2)实现行为的真实角色
     */
    @Slf4j
    class Runner implements IRun {
        @Override
        public void run() {
            log.info("真实角色的行为");
        }
    }
    
    /**
     * 3)持有真实角色的代理角色,可控制外部对代理的访问
     */
    @Builder
    @Slf4j
    class RunProxy implements IRun {
        private final IRun runner;
    
        @Override
        public void run() {
            if (ThreadLocalRandom.current().nextBoolean()) {
                // 执行真实角色的行为
                runner.run();
            } else {
                log.error("代理心情不好,拒绝处理");
            }
        }
    }
    
    

    动态代理

    public class DynamicProxy {
        /**
         * 代理模式:
         * Provide a surrogate or placeholder for another object to control access to it.
         * 为其他对象提供一个代理或占位符来控制对它的访问。
         */
        @Test
        public void all() {
            final TargetImpl targetImpl = new TargetImpl();
            final LogAdvice logAdvice = new LogAdvice();
            final SelfProxy selfProxy = SelfProxy.builder()
                    .target(targetImpl)
                    .advice(logAdvice).build();
            final Itarget target = (Itarget) selfProxy.proxy();
            target.show();
        }
    }
    
    /**
     * 1)需要执行动态代理的目标接口
     */
    interface Itarget {
        void show();
    }
    
    /**
     * 2)目标接口的实现类
     */
    @Slf4j
    class TargetImpl implements Itarget {
    
        @Override
        public void show() {
            log.info("调用目标方法");
            throw new RuntimeException("测试异常");
        }
    }
    
    /**
     * 3)动态织入的通知接口
     */
    interface Iadvice {
        // 前置通知
        void before();
    
        // 后置通知
        void after();
    
        // 环绕通知
        Object around(Object target, Method method, Object[] args);
    
        // 返回通知
        void afterReturning();
    
        // 异常通知
        void afterThrowing();
    }
    
    /**
     * 通知接口的抽象实现,以简化实现通知接口所需要的工作。
     */
    @Slf4j
    abstract class BaseAdvice implements Iadvice {
    
        @Override
        public void before() {
        }
    
        @Override
        public void after() {
        }
    
        @Override
        public Object around(Object target, Method method, Object[] args) {
            try {
                log.info("执行环绕方法", "around");
                return method.invoke(target, args);
            } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
                throw new IllegalStateException(e);
            }
        }
    
        @Override
        public void afterReturning() {
        }
    
        @Override
        public void afterThrowing() {
        }
    }
    
    /**
     * 4)具体的通知实现类
     */
    @Slf4j
    class LogAdvice extends BaseAdvice {
        private final ThreadLocal<Long> startTime = new ThreadLocal();
    
        @Override
        public void before() {
            log.info("开始执行方法 {}", "before");
            startTime.set(System.nanoTime());
        }
    
        @Override
        public void after() {
            final Long start = startTime.get();
            final long executeTime = System.nanoTime() - start;
            log.info("方法执行完毕 {}", "after");
            log.info("方法执行时间 {}", executeTime);
        }
    
        @Override
        public Object around(Object target, Method method, Object[] args) {
            try {
                log.info("执行环绕方法 {}", "around");
                return method.invoke(target, args);
            } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
                throw new IllegalStateException(e);
            }
        }
    
        @Override
        public void afterReturning() {
            log.info("方法返回 {}", "afterReturning");
        }
    
        @Override
        public void afterThrowing() {
            log.info("方法抛出异常 {}", "afterThrowing");
        }
    
    }
    
    /**
     * 5)动态代理类
     */
    @Builder
    @AllArgsConstructor
    class SelfProxy implements InvocationHandler {
        // 要代理的目标对象
        private final Object target;
        // 动态织入的通知接口
        private final Iadvice advice;
    
        @Override
        public Object invoke(Object target, Method method, Object[] args) throws Throwable {
            // 执行前置通知
            advice.before();
            try {
                // 执行环绕通知,此处方法的主体一定要是被代理对象。
                final Object around = advice.around(this.target, method, args);
                // 执行后置通知
                advice.after();
                return around;
            } catch (final Exception e) {
                // 执行异常通知
                advice.afterThrowing();
                throw new IllegalStateException(e);
            } finally {
                // 执行返回通知
                advice.afterReturning();
            }
        }
    
        public Object proxy() {
            // 获取指定接口的动态代理类,基于 JDK 的 Proxy 实现。
            return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
        }
    }
    
  • 相关阅读:
    jq绑定on事件无效
    数字以0补全
    redis常用操作
    mysql数据操作日常
    centos端口映射
    centos7防火墙操作
    mysql5.7order by问题
    centos无法上网解决方法
    面试题
    ztree 获取子节点所有父节点的name的拼接
  • 原文地址:https://www.cnblogs.com/zhuxudong/p/10164085.html
Copyright © 2020-2023  润新知