代理模式【结构模式】

代理模式

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);
    }
}

posted on 2018-12-23 13:43  竺旭东  阅读(121)  评论(0编辑  收藏  举报

导航