4.1 提出问题

情景:数学计算器器
●要求
①执行加减乘除运算
②日志:在程序执行期间追踪正在发生的活动
③验证:希望计算器只能处理正数的运算
image.png
●常规实现
image.png
●问题
○代码混乱:越来越多的非业务需求(日志和验证等)加入后,原有的业务方法急剧膨胀。每个方法在处理核心逻辑的同时还必须兼顾其他多个关注点。
○代码分散: 以日志需求为例,只是为了满足这个单一需求,就不得不在多个模块(方法)里多次重复相同的日志代码。如果日志需求发生变化,必须修改所有模块。
image.png
image.png

4.2 动态代理

代理设计模式的原理:使用一个代理将对象包装起来,然后用该代理对象取代原始对象。任何对原始对象的调用都要通过代理。代理对象决定是否以及何时将方法调用转到原始对象上。
image.png

  1. public class logUtils {
  2. public static void logStart(Method method,Object... args) {
  3. System.out.println("【" + method.getName() + "】方法开始执行,使用参数列表【" + Arrays.asList(args) + "】");
  4. }
  5. public static void logReturn(Method method,Object result) {
  6. System.out.println("【" + method.getName() + "】方法执行完成,计算结果是:" + result);
  7. }
  8. public static void logException(Method method, Exception e) {
  9. System.out.println("【" + method.getName() + "】方法出现了异常,异常信息是:" + e.getCause() );
  10. }
  11. public static void logEnd(Method method) {
  12. System.out.println("【" + method.getName() + "】方法最终结束了" );
  13. }
  14. }
  1. package com.hao.proxy;
  2. import java.lang.reflect.InvocationHandler;
  3. import java.lang.reflect.Method;
  4. import java.lang.reflect.Proxy;
  5. import java.util.ArrayList;
  6. import java.util.Arrays;
  7. import com.hao.inter.Calculator;
  8. import com.hao.utils.logUtils;
  9. public class CalculatorProxy {
  10. /**
  11. * 为传入的对象创建一个动态代理对象
  12. * @param calculator
  13. * @return
  14. *
  15. * Calculator calculator:被代理对象
  16. */
  17. public static Calculator getProxy(Calculator calculator) {
  18. //方法执行器。帮我们目标对象执行目标方法
  19. InvocationHandler h = new InvocationHandler() {
  20. /**
  21. * Object proxy:代理对象:给jdk使用,任何时候都不要动这个对象
  22. * Method method:当前将要执行的目标对象的方法
  23. * Object[] args:这个方法调用时外界传入的参数值
  24. */
  25. @Override
  26. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  27. // TODO Auto-generated method stub
  28. System.out.println("这是动态代理");
  29. Object result = null;
  30. try {
  31. logUtils.logStart(method, args);
  32. //利用反射执行目标方法
  33. result = method.invoke(calculator, args);
  34. logUtils.logReturn(method, result);
  35. } catch (Exception e) {
  36. // TODO: handle exception
  37. logUtils.logException(method,e);
  38. }finally {
  39. logUtils.logEnd(method);
  40. }
  41. return result;
  42. }
  43. };
  44. //获取类加载器
  45. ClassLoader loader = calculator.getClass().getClassLoader();
  46. //获取实现的所有接口
  47. Class<?>[] interfaces = calculator.getClass().getInterfaces();
  48. //Proxy为目标对象创建代理对象;
  49. Object proxy = Proxy.newProxyInstance(loader, interfaces, h);
  50. return (Calculator)proxy;
  51. }
  52. }
public class AOPTest {

    @Test
    public void test() {
        Calculator calculator = new MyMathCalculator();

        Calculator proxy = CalculatorProxy.getProxy(calculator);
        proxy.add(2, 1);
        proxy.div(2, 0);
    }
}

image.png