AOP (Aspect Oriented Programming)面向切面编程

-----不修改源代码的情况下给程序动态统一添加功能.

比如说,一个方法作为"切入点","切面"类中可以提供拦截方法分别对"切入点"方法之前和之后进行拦截,即不修改源程序,动态添加功能.

本篇主要是模拟拦截器链的实现,相应实现的功能主要有:
1.用户可以选择代理模式(JDK代理或者CGLIB代理);
2.用户可以选择类和方法,进行拦截(通过映射关系);
3.对于一个类的同一个方法,是允许形成拦截器链的;
4.允许"前置拦截",“后置拦截”,“异常拦截”;
5.前置拦截是允许用户终止方法的执行,此时拦截器链应终止;
6.允许前置拦截更改方法参数,允许后置拦截更改方法的返回值;
7.拦截器的拦截功能由用户决定;

首先实现三个接口,前置,后置,异常拦截:

public interface IBefore {
	boolean before();
}
public interface IAfter {
	Object after(Object result);
}
public interface IThrowable {
	void throwThrowable() throws Throwable;
}

这里我们将拦截器链又分为前置拦截器链和后置拦截器链,即由不同的拦截器构成的链表.
前置拦截器链的节点,即每一个前置拦截器:

public class BeforeIntercepterNode {
	private IBefore before;
	private BeforeIntercepterNode next;
	
	BeforeIntercepterNode() {
	}
	
	BeforeIntercepterNode(IBefore before) {
		this.before = before;
	}

	void setBefore(IBefore before) {
		this.before = before;
	}
	
	void addNode(BeforeIntercepterNode node) {
		if (next == null) {
			next = node;
			return;
		}
		
		next.addNode(node);
	}
	
	boolean doBefore() {
		boolean ok = before.before();
		if (!ok) {
			return ok;
		}
		if (next != null) {
			return next.doBefore();
		}
		return ok;
	}
	
}

同理,生成后置拦截器链的节点,即后置拦截器:

public class AfterIntercepterNode {
	private IAfter after;
	private AfterIntercepterNode next;
	
	AfterIntercepterNode() {
	}
	
	AfterIntercepterNode(IAfter after) {
		this.after = after;
	}

	void setAfter(IAfter after) {
		this.after = after;
	}
	
	void addNode(AfterIntercepterNode node) {
		if (next ==  null) {
			next = node;
			return;
		}
		
		next.addNode(node);
	}
	
	Object doAfter(Object result) {
		if (next == null) {
			return after.after(result);
		}
		//这里采用“起泡”式执行后置拦截;
		result = next.doAfter(result);
		result = after.after(result);
		
		return result;
	}
	
}

这里说一下,doAfter()方法,采用"起泡"式进行后置拦截,下图可以更好的理解:

spring 拦截器处理url转义 spring拦截器链_java


有了节点,就可以生成链表,前置拦截器链和后置拦截器链:

public class BeforeIntercepterLink {
	private BeforeIntercepterNode head;
	
	BeforeIntercepterLink() {
		this.head = null;
	}
	
	void addIntercepter(IBefore before) {
		BeforeIntercepterNode node = new BeforeIntercepterNode(before);

		if (head == null) {
			head = node;
		}
		
		head.addNode(node);
	}
	
	boolean before() {
		if (head == null) {
			return true;
		}
		
		return head.doBefore();
	}
	
}
public class AfterIntercepterLink {
	private AfterIntercepterNode head;
	
	AfterIntercepterLink() {
		this.head = null;
	}
	
	void addIntercepter(IAfter after) {
		AfterIntercepterNode node = new AfterIntercepterNode(after);
		
		if (head == null) {
			head = node;
			return;
		}
		
		head.addNode(node);
	}
	
	Object after(Object result) {
		if (head == null) {
			return result;
		}
		
		return head.doAfter(result);
	}
	
}

由前置拦截器链和后置拦截器链构成拦截器链:

public class IntercepterLink {
	private BeforeIntercepterLink beforeLink;
	private AfterIntercepterLink afterLink;
	
	private JoinPoint joinPoint;
	
	IntercepterLink() {
		this.beforeLink = null;
		this.afterLink = null;
	}
	
	JoinPoint getJoinPoint() {
		return joinPoint;
	}

	void setJoinPoint(JoinPoint joinPoint) {
		this.joinPoint = joinPoint;
	}

	void addIntercepter(IBefore before) {
		if (beforeLink == null) {
			beforeLink = new BeforeIntercepterLink();
		}
		beforeLink.addIntercepter(before);
	}
	
	void addIntercepter(IAfter after) {
		if (afterLink == null) {
			afterLink = new AfterIntercepterLink();
		}
		afterLink.addIntercepter(after);
	}
	
	boolean before() {
		if (beforeLink == null) {
			return true;
		}
		return beforeLink.before();
	}
	
	Object after(Object result) {
		if (afterLink == null) {
			return result;
		}
		return afterLink.after(result);
	}
	
}

同样,拦截器链中提供addIntercepter()方法和拦截方法before(),after(),可以发现从拦截器(节点)到前置或后置拦截器链再到拦截器链,这几个类中都相应存在增加拦截器和拦截方法,类似于一种由底向上的层次关系.

JoinPoint类是封装了被拦截方法相关的信息:

public class JoinPoint {
	private Class<?> klass;
	private Object object;
	private Method method;
	private Object[] paraValues;
	private Class<?>[] paraTypes;
	private ReturnValue returnValue;

这里的ReturnValue类是封装了被拦截方法的返回值及返回值类型:

public class ReturnValue {
	private Class<?> returnType;
	private Object value;

接下来就是对拦截方法的拦截功能,利用反射机制:

public class BeforeIntercepter implements IBefore {
	private IntercepterLink intercepterLink;
	private Method method;
	private Object object;
	
	public BeforeIntercepter() {
	}

	void setIntercepterLink(IntercepterLink intercepterLink) {
		this.intercepterLink = intercepterLink;
	}

	void setMethod(Method method) {
		this.method = method;
	}

	void setObject(Object object) {
		this.object = object;
	}
	
	private Object[] getParaValues() {
		Object[] paraValues = new Object[] { };
		int paraCount = method.getParameterCount();
		
		if (paraCount > 0) {
			Class<?>[] methodParaTypes = method.getParameterTypes();
			JoinPoint joinPoint = intercepterLink.getJoinPoint();
			Object[] paraValue = joinPoint.getParaValues();
			
			if (paraCount == 1 && methodParaTypes[0].equals(JoinPoint.class)) {
				return new Object[] { joinPoint };
			}
			paraValues = new Object[paraCount];
			Class<?>[] paraTypes = joinPoint.getParaTypes();
			for (int index = 0; index < paraCount; index++) {
				if (!methodParaTypes[index].equals(paraTypes[index])) {
					continue;
				}
				paraValues[index] = paraValue[index];
			}
		}
		
		return paraValues;
	}

	@Override
	public boolean before() {
		Object[] paraValues = getParaValues();
		Object result = null;
		try {
			result = method.invoke(object, paraValues);
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		}
		
		if (result != null && method.getReturnType().equals(boolean.class)) {
			return (boolean) result;
		}
		
		return true;
	}

}

前置拦截处理参数的时候,分为三种情况:
1.无参;
2.一个参数,JoinPoint类型;
3.多参,被拦截方法相应的参数;

处理后置拦截也是类似的:

public class AfterIntercepter implements IAfter {
	private IntercepterLink intercepterLink;
	private Method method;
	private Object object;
	
	public AfterIntercepter() {
	}

	void setIntercepterLink(IntercepterLink intercepterLink) {
		this.intercepterLink = intercepterLink;
	}

	void setMethod(Method method) {
		this.method = method;
	}

	void setObject(Object object) {
		this.object = object;
	}
	
	private Object[] getParaValues() {
		Object[] paraValues = new Object[] { };
		int paraCount = method.getParameterCount();
		
		if (paraCount <= 0) {
			return paraValues;
		}
		if (paraCount > 1) {
			return paraValues;
		}
		Class<?>[] methodParaTypes = method.getParameterTypes();
		JoinPoint joinPoint = intercepterLink.getJoinPoint();
		if (methodParaTypes[0].equals(JoinPoint.class)) {
			return new Object[] { joinPoint };
		} else if (methodParaTypes[0].equals(ReturnValue.class)) {
			return new Object[] { joinPoint.getReturnValue() };
		}
			
		return paraValues;
	}

	@Override
	public Object after(Object result) {
		Object[] paraValues = getParaValues();
		Object res = null;
		try {
			res = method.invoke(object, paraValues);
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		}
		if (res == null) {
			return result;
		}
		ReturnValue returnValue = new ReturnValue();
		returnValue.setValue(res);
		intercepterLink.getJoinPoint().setReturnValue(returnValue);
		
		return res;
	}

}

后置拦截处理参数,也分三种情况:
1.无参;
2.一个参数,JoinPoint类型;
3.一个参数,ReturnValue类型;