自己动手写一个web框架(二):实现AOP

系列文章:

自己动手写一个web框架(一):实现IOC与MVC



一、基本介绍


实现功能:controller中所有的方法被调用时,计算调用所耗时长。
基本技术:动态代理

二、实现思路

既然要代理所有的controller类,那就用注解来区分是否为controller。定义一个Aspect注解:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Aspect {

	// 注解
	Class<? extends Annotation> value();

}

一个类可以被多重代理,比如既加上计算时间,又加上安全验证,这样的话我们可以用代理链的思路来解决,定义一个如下的接口和基本代理实现类:
public interface Proxy {
	// 执行链式代理
	Object doProxy(ProxyChain proxyChain) throws Throwable;
}
public class ProxyChain {
	private final Class<?> targetClass;
	private final Object targetObject;//目标对象
	private final Method targetMethod;//目标方法
	private final MethodProxy methodProxy; //代理方法
	private final Object[] methodParams; 
	private List<Proxy> proxyList = new ArrayList<Proxy>(); //代理对象列表
	private int proxyIndex = 0;

	public ProxyChain(Class<?> targetClass, Object targetObject, Method targetMethod, MethodProxy methodProxy,
			Object[] methodParams, List<Proxy> proxyList) {
		super();
		this.targetClass = targetClass;
		this.targetObject = targetObject;
		this.targetMethod = targetMethod;
		this.methodProxy = methodProxy;
		this.methodParams = methodParams;
		this.proxyList = proxyList;
	}

	public Class<?> getTargetClass() {
		return targetClass;
	}

	public Method getTargetMethod() {
		return targetMethod;
	}

	public Object[] getMethodParams() {
		return methodParams;
	}

	public Object doProxyChain() throws Throwable {
		Object methodResult;
		if (proxyIndex < proxyList.size()) {
			methodResult = proxyList.get(proxyIndex++).doProxy(this);
		} else {
			methodResult = methodProxy.invokeSuper(targetObject, methodParams);
		}
		return methodResult;
	}

public class AspectProxy implements Proxy {
	private static final Logger LOGGER = LoggerFactory.getLogger(AspectProxy.class);

	public final Object doProxy(ProxyChain proxyChain) throws Throwable {
		Object result = null;
		Class<?> cls = proxyChain.getTargetClass();
		Method method = proxyChain.getTargetMethod();
		Object[] params = proxyChain.getMethodParams();
		begin();
		try {
			if (intercept(cls, method, params)) {
				before(cls, method, params);
				result = proxyChain.doProxyChain();
				after(cls, method, params);
			} else {
				result = proxyChain.doProxyChain();
			}
		} catch (Exception e) {
			LOGGER.error("proxy fail", e);
			error(cls, method, params, e);
			throw e;
		} finally {
			end();
		}
		return result;
	}

	public void begin() {

	}

	public boolean intercept(Class<?> cls, Method method, Object[] params) throws Throwable {
		return true;
	}

	public void before(Class<?> cls, Method method, Object[] params) throws Throwable {

	}

	public void after(Class<?> cls, Method method, Object[] params) throws Throwable {

	}

	public void error(Class<?> cls, Method method, Object[] params, Throwable e) throws Throwable {

	}

	public void end() {

	}

}

上面两个类合在一块儿看,多看几遍就能明白整个的流程:
AspectProxy中用到了模版方法,来规范整个代理的操作顺序:先调用before,再判断是否是代理链上的最后一个代理,如果不是的话,继续下一个代理的操作,然后调用after;如果是最后一个,用反射调用原始的被代理的方法,然后调用after。


我们在自己的项目中(非框架),就可以定义这样的aspect:
@Aspect(value=Controller.class)
public class ControllerAspect extends AspectProxy {
	private static final Logger LOGGER = LoggerFactory.getLogger(ControllerAspect.class);
	private long begin;

	@Override
	public void before(Class<?> cls, Method method, Object[] params) throws Throwable {
		LOGGER.debug("-----begin-----");
		LOGGER.debug(String.format("class: %s", cls.getName()));
		LOGGER.debug(String.format("method: %s", method.getName()));
		begin = System.currentTimeMillis();
	}

	@Override
	public void after(Class<?> cls, Method method, Object[] params) throws Throwable {
		LOGGER.debug(String.format("time:%dms", System.currentTimeMillis() - begin));
		LOGGER.debug("-----end-----");
	}
}

至于创建代理的活,我们交给ProxyManager:
/**
 * 代码管理器
 * 
 * @author shen
 *
 */
public class ProxyManager {

	@SuppressWarnings("unchecked")
	public static <T> T createProxy(final Class<?> targetClass, final List<Proxy> proxyList) {
		return (T) Enhancer.create(targetClass, new MethodInterceptor() {
			public Object intercept(Object targetObject, Method targetMethod, Object[] methodParams,
					MethodProxy methodProxy) throws Throwable {
				return new ProxyChain(targetClass, targetObject, targetMethod, methodProxy, methodParams, proxyList)
						.doProxyChain();
			}
		});
	}

}

其中用到了cglib动态代理。

然后我们只需要在beanhelper中把相应的类实例换成代理对象即可:
public class AopHelper {

	private static final Logger LOGGER = LoggerFactory.getLogger(AopHelper.class);

	static {
		try {
			Map<Class<?>, Set<Class<?>>> proxyMap = createProxyMap();
			Map<Class<?>, List<Proxy>> targetMap = createTargetMap(proxyMap);
			for (Map.Entry<Class<?>, List<Proxy>> targetEntry : targetMap.entrySet()) {
				Class<?> targetClass = targetEntry.getKey();
				List<Proxy> proxyList = targetEntry.getValue();
				Object proxy = ProxyManager.createProxy(targetClass, proxyList);
				BeanHelper.setBean(targetClass, proxy);
			}
		} catch (Exception e) {
			LOGGER.error("aop fail", e);
		}
	}

	private static Map<Class<?>, Set<Class<?>>> createProxyMap() throws Exception {
		Map<Class<?>, Set<Class<?>>> proxyMap = new HashMap<Class<?>, Set<Class<?>>>();
		Set<Class<?>> proxyClassSet = ClassHelper.getClassSetBySuper(AspectProxy.class);
		for (Class<?> proxyClass : proxyClassSet) {
			System.out.println(proxyClass);
			if (proxyClass.isAnnotationPresent(Aspect.class)) {
				Aspect aspect = proxyClass.getAnnotation(Aspect.class);
				System.out.println(aspect.toString());
				Set<Class<?>> targetClassSet = createTargetClassSet(aspect);
				proxyMap.put(proxyClass, targetClassSet);
			}
		}
		return proxyMap;
	}

	private static Set<Class<?>> createTargetClassSet(Aspect aspect) throws Exception {
		Set<Class<?>> targetClassSet = new HashSet<Class<?>>();
		Class<? extends Annotation> annotation = aspect.value();
		if (annotation != null && !annotation.equals(Aspect.class)) {
			targetClassSet.addAll(ClassHelper.getClassSetByAnnotation(annotation));
		}
		return targetClassSet;
	}

	private static Map<Class<?>, List<Proxy>> createTargetMap(Map<Class<?>, Set<Class<?>>> proxyMap) throws Exception {
		Map<Class<?>, List<Proxy>> targetMap = new HashMap<Class<?>, List<Proxy>>();
		for (Map.Entry<Class<?>, Set<Class<?>>> proxyEntry : proxyMap.entrySet()) {
			Class<?> proxyClass = proxyEntry.getKey();
			Set<Class<?>> targetClassSet = proxyEntry.getValue();
			for (Class<?> targetClass : targetClassSet) {
				Proxy proxy = (Proxy) proxyClass.newInstance();
				if (targetMap.containsKey(targetClass)) {
					targetMap.get(targetClass).add(proxy);
				} else {
					List<Proxy> proxyList = new ArrayList<Proxy>();
					proxyList.add(proxy);
					targetMap.put(targetClass, proxyList);
				}
			}
		}
		return targetMap;
	}

}


这样,我们就完成了AOP的功能。


你可能感兴趣的:(动态代理,AOP,反射,cglib,web框架)