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



上述代码中,日志和验证属于非业务需求,将这类代码写入业务逻辑中,耦合性增大,并且带来了很多的重复性代码。如果日志和验证需求改变,必须修改所有模块。
计算器应该只关心核心计算逻辑,需要将日志和验证关注点从其中分离出来。
采用动态代理的方法,建立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);
	}
}


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

你可能感兴趣的:(java,apache,spring,AOP,读书)