代理模式【結構模式】
阿新 • • 發佈:2018-12-23
代理模式
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); } }