本文參照《架構探險》一書。html
aop 無非是在原有的方法先後加入自定義的代碼。整體思想:java
JDK動態代理只能對實現了接口的類生成代理,而不能針對類 。 CGLIB是針對類實現代理,主要是對指定的類生成一個子類,覆蓋其中的方法 。 由於是繼承,因此該類或方法最好不要聲明成final ,final能夠阻止繼承和多態。架構
<aop:aspectj-autoproxy proxy-target-class="true"/> 強制使用cglib作動態代理框架
public class AopHelper { ... static { try { //從容器中找到代理類和被代理類的關係 Map<Class<?>, Set<Class<?>>> proxyMap = createProxyMap(); Map<Class<?>, List<Proxy>> targetMap = createTargetMap(proxyMap); for (Map.Entry<Class<?>, List<Proxy>> targetEntry : targetMap.entrySet()) { //1.建立代理類 Object proxy = ProxyManager.createProxy(targetEntry.getKey(), targetEntry.getValue()); //2.將容器中的class 換爲 代理類 BeanHelper.setBean(targetEntry.getKey(), proxy); } } catch (Exception e) { LOGGER.error("aop fail",e); } } ... }
@Aspect(Controller.class) public class ControllerAspect extends AspectProxy
extends AspectProxy 實現父類方法,也就是咱們要添加的操做。jvm
@Aspect(Controller.class) 表示這個代理類代理的是哪一個類(具體方法代理規則能夠在代理類方法中判斷,作不一樣處理)ide
/** * class集合中找到指定切面的集合 * @param aspect * @return * @throws Exception */ 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; } /** * 找到繼承AspectProxy的代理類 * 根據代理類的Aspect註解中value 找到被代理類 * 返回代理類和被代理類的映射 * proxyClass -> set<targetClass> * @return * @throws Exception */ private static Map<Class<?>, Set<Class<?>>> createProxyMap() throws Exception { Map<Class<?>, Set<Class<?>>> proxyMap = new HashMap<>(); //切面類 Set<Class<?>> proxyClassSet = ClassHelper.getClassSetBySuper(AspectProxy.class); for (Class<?> proxyCls : proxyClassSet) { if (proxyCls.isAnnotationPresent(Aspect.class)){//繼承了AspectProxy而且被Aspect標註 Aspect aspect = proxyCls.getAnnotation(Aspect.class); Set<Class<?>> targetClassSet = createTargetClassSet(aspect); proxyMap.put(proxyCls, targetClassSet); } } //添加事務代理 addTransactionProxy(proxyMap); return proxyMap; } private static void addTransactionProxy(Map<Class<?>, Set<Class<?>>> proxyMap) { Set<Class<?>> serviceClassSet = ClassHelper.getClassSetByAnnotation(Service.class); proxyMap.put(TransactionProxy.class, serviceClassSet); } /** * targetClass -> List<proxy instance> * @param proxyMap * @return * @throws Exception */ private static Map<Class<?>, List<Proxy>> createTargetMap(Map<Class<?>, Set<Class<?>>> proxyMap) throws Exception { HashMap<Class<?>, List<Proxy>> targetMap = new HashMap<>(); 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<>(); proxyList.add(proxy); targetMap.put(targetClass, proxyList); } } } return targetMap; }
//cglib 建立代理對象 public class ProxyManager { public static <T> T createProxy(final Class<T> targetClass, final List<Proxy> proxyList) { //CGLib提供建立代理對象,代理對象是一個代理鏈 return (T) Enhancer.create(targetClass, new MethodInterceptor() { @Override public Object intercept(Object targetObject, Method targetMethod, Object[] methodParams, MethodProxy methodProxy) throws Throwable { //返回代理對象 代理鏈 的結果 return new ProxyChain(targetClass, targetObject, targetMethod, methodProxy, methodParams, proxyList).doProxyChain(); } }); } }
代理對象是ProxyChain類型,由於同一個class可能有多個aop須要處理,因此是一條鏈。this
public class ProxyChain { private final Class<?> targetClass; private final Object targetObject; private final Method targetMethod; private final MethodProxy methodProxy; private final Object[] 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 abstract class AspectProxy implements Proxy{ private static final Logger LOGGER = LoggerFactory.getLogger(AspectProxy.class); @Override public Object doProxy(ProxyChain proxyChain) throws Throwable { Object result = null; Class<?> targetClass = proxyChain.getTargetClass(); Object[] methodParams = proxyChain.getMethodParams(); Method targetMethod = proxyChain.getTargetMethod(); begin(); try { if (intercept(targetClass, targetMethod, methodParams)) { before(targetClass, targetMethod, methodParams); result = proxyChain.doProxyChain(); after(targetClass, targetMethod, methodParams, result); } else { result = proxyChain.doProxyChain(); } } catch (Exception e) { LOGGER.error("proxy fail",e); error(targetClass, targetMethod, methodParams, e); throw e; } finally { end(); } return result; } private void begin() { } public boolean intercept(Class<?> cls, Method method, Object[] params) { return true; } public void before(Class<?> cls, Method method, Object[] params) { } public void after(Class<?> cls, Method method, Object[] params, Object result) { } public void error(Class<?> cls, Method method, Object[] params, Throwable e) { } public void end() {} }
public class TransactionProxy implements Proxy { //保證同一線程中事務控制相關邏輯只會執行一次? private static final ThreadLocal<Boolean> FLAG_HOLDER = new ThreadLocal<Boolean>(){ protected Boolean initialValue() { return false; } }; @Override public Object doProxy(ProxyChain proxyChain) throws Exception, Throwable { Boolean flag = FLAG_HOLDER.get(); Method method = proxyChain.getTargetMethod(); Object result = null; if (!flag && method.isAnnotationPresent(Transaction.class)) { FLAG_HOLDER.set(true); try { DatabaseHelper.beginTransaction(); LOGGER.debug("begin transaction"); result = proxyChain.doProxyChain(); DatabaseHelper.commitTransaction(); LOGGER.debug("commit transaction"); } catch (Exception e) { DatabaseHelper.rollbackTransaction(); LOGGER.debug("rollback transaction"); throw e; } finally { //DatabaseHelper.closeConnetion(); FLAG_HOLDER.remove(); } } else { result = proxyChain.doProxyChain(); } return result; } }
FLAG_HOLDER應該是防止事務的嵌套,好比兩個service都標註了@transaction,一個serviceA一個ServiceB, 可是ServiceA中又調用了ServiceB,這樣沒有FLAG_HOLDER就會先啓動A的事務,再啓動B的事務(A的事務還沒完)。加上FLAG_HOLDER就只會啓動A的事務,B看到已經有事務在執行就不啓動事務,默認加入了A的事務。.net