系列文章:
一、基本介绍
实现功能: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的功能。