《架构探险》之面向切面编程(AOP)(下)
程序员文章站
2022-06-13 21:59:42
...
spring主要的特点之一就是面向切面编程,为了实现切面编程需要借助动态代理技术。
首先,定义一个代理管理类,用来创建创建的代理,在代理中调用切面的实现逻辑:
public class ProxyManager { public static <T> T createProxy(final Class<?> targetClass, final List<Proxy> proxyList){ 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(); } }); } }
多个切面使用链表来管理,组成一个切面链,:
public Object doProxyChain() throws Throwable { Object methodResult; if(proxyIndex < proxyList.size()){ Proxy proxy = proxyList.get(proxyIndex); proxyIndex++; methodResult = proxy.doProxy(this); }else { methodResult = methodProxy.invokeSuper(targetObject, methodParams); } return methodResult; }
以事务切面的实现为例:
public class TransactionAspect extends AspectProxy { private static final Logger LOGGER = LoggerFactory.getLogger(AspectProxy.class); private static final ThreadLocal<Boolean> FLAG_HOLDER = new ThreadLocal<Boolean>(); @Override public final Object doProxy(ProxyChain proxyChain)throws Throwable{ Object result = null; Method method = proxyChain.getTargetMethod(); Boolean flag = FLAG_HOLDER.get(); if(flag == null && method.isAnnotationPresent(Transaction.class)){ try { FLAG_HOLDER.set(true); DatabaseHelper.beginTransaction(); result = proxyChain.doProxyChain(); DatabaseHelper.endTransaction(); } catch (Exception e) { LOGGER.error("proxy failure", e); DatabaseHelper.rollbackTransaction(); throw e; } finally { FLAG_HOLDER.remove(); } }else { result = proxyChain.doProxyChain(); } return result; } }
接下来,就需要在框架的对象管理池中在切点出使用动态代理替代原有的对象,这样当调用对象方法时会去调用代理的处理逻辑,实现面向切面的编程。
//根据代理类找到目标类,然后反过来对目标类生成代理类(链) 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) { e.printStackTrace(); } } private static Set<Class<?>> createTargetClassSet(Aspect aspect){ 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<?>, Set<Class<?>>> createProxyMap(){ Map<Class<?>, Set<Class<?>>> proxyMap = new HashMap<Class<?>, Set<Class<?>>>(); Set<Class<?>> proxyClassSet = ClassHelper.getClassSetBySuper(AspectProxy.class); for(Class<?> proxyClass : proxyClassSet){ if(proxyClass.isAnnotationPresent(Aspect.class)){ Aspect aspect = proxyClass.getAnnotation(Aspect.class); Set<Class<?>> targetClassSet = createTargetClassSet(aspect); proxyMap.put(proxyClass, targetClassSet); } } Set<Class<?>> transactionServiceSet = ClassHelper.getClassSetByAnnotation(Service.class); proxyMap.put(TransactionAspect.class, transactionServiceSet); return proxyMap; } private static Map<Class<?>, List<Proxy>> createTargetMap(Map<Class<?>, Set<Class<?>>> proxyMap) throws IllegalAccessException, InstantiationException { 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; }