AOP框架实现
2019獨角獸企業重金招聘Python工程師標準>>>
本文參照《架構探險》一書。
aop 無非是在原有的方法前后加入自定義的代碼。總體思想:
JDK動態代理只能對實現了接口的類生成代理,而不能針對類 。 CGLIB是針對類實現代理,主要是對指定的類生成一個子類,覆蓋其中的方法 。 因為是繼承,所以該類或方法最好不要聲明成final ,final可以阻止繼承和多態。
<aop:aspectj-autoproxy proxy-target-class="true"/> 強制使用cglib做動態代理
AOP框架
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 AspectProxyextends AspectProxy 實現父類方法,也就是我們要添加的操作。
@Aspect(Controller.class) 表示這個代理類代理的是哪個類(具體方法代理規則可以在代理類方法中判斷,做不同處理)
從容器中找到代理類和被代理類的關系
/*** 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() {@Overridepublic 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需要處理,所以是一條鏈。
Enhancer.create
- Cglib的使用方法
ProxyChain的執行
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);@Overridepublic 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;}};@Overridepublic 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的事務。
轉載于:https://my.oschina.net/u/1245414/blog/1539386
總結
- 上一篇: Attribute class inva
- 下一篇: 67 个节省开发者时间的实用工具、库与资