spring recipes读书笔记--理解AOP原理

引入一个简单的数值计算器的例子,首先创建计算器接口,然后提供一个简单的实现类,在实现类中,需要对传入参数进行验证,并且进行日志记录。


package com.aop.example;

public interface ArithmeticCalculator {
public double add(double a,double b);
public double sub(double a,double b);
}

package com.aop.example;

import com.sun.org.apache.commons.logging.Log;
import com.sun.org.apache.commons.logging.LogFactory;

public class ArithmeticCalculatorImpl implements ArithmeticCalculator {

private Log log=LogFactory.getLog(this.getClass());

public double add(double a, double b) {
// TODO Auto-generated method stub
log.info("the method add() begins with "+a+","+b);
validate(a);
validate(b);
double result = a+b;
System.out.println(a+"+"+b+" = "+result);
log.info("the method add() ends with "+result);
return result;
}

public double sub(double a, double b) {
// TODO Auto-generated method stub
log.info("the method add() begins with "+a+","+b);
validate(a);
validate(b);
double result = a-b;
System.out.println(a+"-"+b+" = "+result);
log.info("the method add() ends with "+result);
return result;
}

private void validate(double a) {
// TODO Auto-generated method stub
if(a<0){
throw new IllegalArgumentException("Illegal argument");
}
}
}

上述代码中,日志和验证属于非业务需求,将这类代码写入业务逻辑中,耦合性增大,并且带来了很多的重复性代码。如果日志和验证需求改变,必须修改所有模块。

[color=red]计算器应该只关心核心计算逻辑,需要将日志和验证关注点从其中分离出来。[/color]

采用动态代理的方法,建立InvocationHandler接口,并提供日志和验证实现类。


package com.aop.example;

public class ArithmeticCalculatorImpl implements ArithmeticCalculator {

public double add(double a, double b) {
// TODO Auto-generated method stub
double result = a+b;
System.out.println(a+"+"+b+" = "+result);
return result;
}

public double sub(double a, double b) {
// TODO Auto-generated method stub
double result = a-b;
System.out.println(a+"-"+b+" = "+result);
return result;
}
}

package com.aop.example;

import java.lang.reflect.Method;

public interface InvocationHandler {
public Object invoke(Object proxy,Method method,Object[] args) throws Throwable;
}

package com.aop.example;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;

import com.sun.org.apache.commons.logging.Log;
import com.sun.org.apache.commons.logging.LogFactory;

public class CalculatorLoggingHandler implements InvocationHandler {

private Log log = LogFactory.getLog(this.getClass());

private Object target;

public CalculatorLoggingHandler(Object target) {
this.target = target;
}

public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// TODO Auto-generated method stub
log.info("the method "+ method.getName()+" begins with "+Arrays.toString(args));
Object result=method.invoke(target, args);
log.info("the method "+method.getName()+" ends with "+result);
return result;
}

public static Object createProxy(Object target){
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(), new CalculatorLoggingHandler(target));
}
}

package com.aop.example;

import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class CalculatorValidationHandler implements InvocationHandler {

private Object target;

public CalculatorValidationHandler(Object target) {
super();
this.target = target;
}

public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// TODO Auto-generated method stub
for(Object arg:args){
validate((Double)arg);
}
Object result = method.invoke(target, args);
return result;
}

private void validate(double a){
if(a<0){
throw new IllegalArgumentException("illegal argument");
}
}
public static Object createProxy(Object target){
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(), new CalculatorLoggingHandler(target));
}
}

最后做一下测试


package com.aop.example;

public class AopTest {
public static void main(String[] args){
ArithmeticCalculator arithmeticCalculatorImpl= new ArithmeticCalculatorImpl();
ArithmeticCalculator arithmeticCalculator = (ArithmeticCalculator) CalculatorValidationHandler.createProxy
(CalculatorLoggingHandler.createProxy(arithmeticCalculatorImpl));
arithmeticCalculator.add(1.0, 2.0);
arithmeticCalculator.add(-2.2, 2.0);
arithmeticCalculator.sub(3.0, 2.0);
}
}

这里[color=red]使用验证代理包装日志代理形成了一个代理链[/color]。所有计算器的调用首先经过验证代理,然后再是日志代理。

    原文作者:AOP
    原文地址: https://blog.csdn.net/passeddust/article/details/83802855
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞