Spring--8.aop

来源:互联网 发布:java 多线程 回调函数 编辑:程序博客网 时间:2024/06/03 15:09

1       动态代理

1.1  目的

       增强原有方法

       代理对象,一个假的对象(实现原有对象的方法并加强)

 

1.2  问题

需求1-日志:在程序执行期间追踪正在发生的活动

需求2-验证:希望计算器只能处理正数的运算

 

public class ArithmeticCalculatorImpl implements ArithmeticCalculator {     @Override    public int add(int i, int j) {       System.out.println("这个方法  add  开始于 ["+ i+ ","+j+"]");       int result = i + j;       System.out.println("这个方法  add  结束于 "+ result);       return result;    }     @Override    public int sub(int i, int j) {       System.out.println("这个方法  sub  开始于 ["+ i+ ","+j+"]");       int result = i - j;       System.out.println("这个方法  sub  结束于 "+ result);       return result;    }     @Override    public int mul(int i, int j) {       System.out.println("这个方法  mul  开始于 ["+ i+ ","+j+"]");       int result = i * j;       System.out.println("这个方法  sub  结束于 "+ result);       return result;    }     @Override    public int div(int i, int j) {       System.out.println("这个方法  div  开始于 ["+ i+ ","+j+"]");       int result = i / j;       System.out.println("这个方法  div  结束于 "+ result);       return result;    } }

 

       代码混乱:越来越多的非业务需求(日志和验证等)加入后, 原有的业务方法急剧膨胀.  每个方法在处理核心逻辑的同时还必须兼顾其他多个关注点.

       代码分散: 以日志需求为例, 只是为了满足这个单一需求, 就不得不在多个模块(方法)里多次重复相同的日志代码. 如果日志需求发生变化, 必须修改所有模块.

 

1.3  使用动态代理解决上述问题

 

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

 

 

ArithmeticCalculatorImpl

 

public class ArithmeticCalculatorImpl implements ArithmeticCalculator {     @Override    public int add(int i, int j) {       int result = i + j;       return result;    }     @Override    public int sub(int i, int j) {       int result = i - j;       return result;    }     @Override    public int mul(int i, int j) {       int result = i * j;       return result;    }     @Override    public int div(int i, int j) {       int result = i / j;       return result;    } } 

LoggingProxy:

public class LoggingProxy {     //要代理的对象    private ArithmeticCalculator target;       public LoggingProxy(ArithmeticCalculator target) {       super();       this.target = target;    }     public ArithmeticCalculator getLoggingProxy(){        ArithmeticCalculator proxy = null;                //代理对象由哪个类加载器负责加载        ClassLoader loader = target.getClass().getClassLoader();                //代理对象的类型,即其中有哪些方法        Class [] interfaces = newClass[]{ArithmeticCalculator.class};                //当调用代理对象其中方法时,执行该代码        InvocationHandler h = newInvocationHandler() {           /**            * proxy:正在返回的那个代理对象,一般情况下,在 invoke 方法都不使用该对象            * method:正在被调用的方法            * args:调用方法时,传入的参数            */           @Override           public Object invoke(Object proxy, Method method, Object[] args)                  throws Throwable {              String methodName = method.getName();              //日志              System.out.println("此方法" + methodName + "开始于" + Arrays.asList(args));              //执行方法              Object result = method.invoke(target, args);              //日志              System.out.println("此方法" + methodName + "结束于" + result);              return result;           }       };                proxy =(ArithmeticCalculator) Proxy.newProxyInstance(loader, interfaces, h);              return proxy;    }}

2       AOP

2.1  概念

       是一种新的方法论, 是对传统 OOP(面向对象编程) 的补充.

    Aop(AspectOriented Programing):面向切面(方面)编程,用来封装横切关注点,扩展功能不修改源代码实现

 

2.2  原理

       AOP是面向切面编程,是通过动态代理的方式为程序添加统一功能,集中解决一些公共问题。

 

2.3  主要编程对象

       AOP采取横向抽取机制,取代了传统纵向继承体系重复性代码

       AOP的主要编程对象是切面(aspect), 而切面模块化横切关注点.

       在应用 AOP 编程时, 仍然需要定义公共功能, 但可以明确的定义这个功能在哪里, 以什么方式应用, 并且不必修改受影响的类. 这样一来横切关注点就被模块化到特殊的对象(切面)里.

 

2.4  好处:

1.各个步骤之间的良好隔离性耦合性大大降低

2.源代码无关性,再扩展功能的同时不对源码进行修改操作。

 

 

3       AOP原理—解决动态代理

画图分析原理

 

aop底层使用动态代理实现

(1)第一种情况,有接口情况,使用动态代理创建接口实现类代理对象

(2)第二种情况,没有接口情况,使用动态代理创建类的子类代理对象

 

 

 

 

4       AOP操作术语