日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

架构探险笔记5-使框架具备AOP特性(下)

發(fā)布時間:2025/3/21 编程问答 17 豆豆
生活随笔 收集整理的這篇文章主要介紹了 架构探险笔记5-使框架具备AOP特性(下) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

開發(fā)AOP框架

借鑒SpringAOP的風(fēng)格,寫一個基于切面注解的AOP框架。在進(jìn)行下面的步驟之前,確保已經(jīng)掌了動態(tài)代理技術(shù)。

定義切面注解

/*** 切面注解*/ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface Aspect {/*注解*/Class<? extends Annotation> value(); }

通過@Target(ElementType.TYPE)來設(shè)置該注解只能應(yīng)用在類上。該注解中包含一個名為value的屬性,它是一個注解類,用來定義Controller這類注解。

在使用切面注解之前,我們需要先搭建一個代理框架。

搭建代理框架

繼續(xù)在框架中添加一個名為Proxy的接口

/*** 代理接口*/ public interface Proxy {/*** 執(zhí)行鏈?zhǔn)酱?/span>*/Object doProxy(ProxyChain proxyChain) throws Throwable; }

這個接口中包括了一個doProxy方法,傳入一個ProxyChain,用于執(zhí)行“鏈?zhǔn)酱怼辈僮鳌?/p>

所謂鏈?zhǔn)酱?#xff0c;也就是說,可將多個代理通過一條鏈子串起來,一個個地區(qū)執(zhí)行,執(zhí)行順序取決于添加到鏈上的先后順序。

package com.autumn.aop;import net.sf.cglib.proxy.MethodProxy; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List;/*** 代理鏈*/ public class ProxyChain {private final Class<?> targetClass; //代理類private final Object targetObject; //目標(biāo)對象private final Method targetMethod; //目標(biāo)方法private final MethodProxy methodProxy; //方法代理private final Object[] methodParams; //方法參數(shù)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) {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()){ //如果代理索引小于代理列表大小//從列表中取出相應(yīng)的Proxy對象,調(diào)用器doProxy方法methodResult = proxyList.get(proxyIndex++).doProxy(this);}else { //所有代理遍歷完后methodResult = methodProxy.invokeSuper(targetObject,methodParams); //執(zhí)行目標(biāo)對象業(yè)務(wù) }return methodResult;} }

在ProxyChain類中,我們定義了一系列的成員變量,包括targetClass(目標(biāo)類)、targetObject(目標(biāo)對象)、targetMethod(目標(biāo)方法)、methodProxy(方法代理)、methodParams(方法參數(shù)),此外還包括proxyList(代理列表)、proxyIndex(代理索引),這些成員變量在構(gòu)造器中進(jìn)行初始化,并提供了幾個重要的獲值方法。

需要注意的是MethodProxy這個類,它是CGLib開源項目為我們提供的一個方法代理對象,在doProxyChain方法中被使用。

doProxyChain方法中,proxyIndex來充當(dāng)對象的計數(shù)器,若尚未達(dá)到proxyList的上限,則從proxyList中取出相應(yīng)的Proxy對象,并調(diào)用其doProxy方法。在Proxy接口中的實現(xiàn)中會提供相應(yīng)的橫切邏輯,并調(diào)用doProxyChain方法,隨后將再次調(diào)用當(dāng)前ProxyChain對象的doProxyChain方法,直到proxyIndex達(dá)到proxyList的上限為止,最后調(diào)用methodProxy的invokeSuper方法,執(zhí)行目標(biāo)對象的業(yè)務(wù)邏輯。

在pom.xml中添加CGLib的Maven依賴:

<!--不能超過3.0版本,這里用2.2--><dependency><groupId>cglib</groupId><artifactId>cglib</artifactId><version>2.2</version></dependency>

現(xiàn)在我們需要寫一個類,讓它提供一個創(chuàng)建代理對象的方法,輸入一個目標(biāo)類和一組Proxy接口實現(xiàn),輸出一個代理對象,將該類命名為ProxyManager,讓它來創(chuàng)建愛你所有的代理對象,代碼如下:

/*** 代理管理器*/ public class ProxyManager {public static <T> T createProxy(final Class<T> targetClass, final List<Proxy> proxyList){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();}});} }

使用CGLib提供的Enhancer.create()方法來創(chuàng)建代理對象,將intercept的參數(shù)傳入ProxyChain的構(gòu)造器中即可。

誰來調(diào)用ProxyManager呢?當(dāng)然是切面類了,因為在切面類中,需要在目標(biāo)方法被調(diào)用的前后增加相應(yīng)的邏輯。我們有必要寫一個抽象類,讓它提供一個模板方法,并在該抽象類的具體實現(xiàn)中擴(kuò)展相應(yīng)的抽象方法。我們將該抽象命名為AspectProxy。代碼如下

import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.lang.reflect.Method;/*** 切面代理*/ public abstract class AspectProxy implements Proxy{private static final Logger logger = LoggerFactory.getLogger(AspectProxy.class);/*** 執(zhí)行鏈?zhǔn)酱?/span>*/@Overridepublic Object doProxy(ProxyChain proxyChain) throws Throwable {Object result = null;Class<?> cls = proxyChain.getTargetClass();Method method = proxyChain.getTargetMethod();Object[] params = proxyChain.getMethodParams();begin(); //代理開始時執(zhí)行begin方法try {if (intercept(cls,method,params)){ //是否攔截此方法before(cls,method,params); //目標(biāo)方法執(zhí)行前代理方法before執(zhí)行result = proxyChain.doProxyChain(); //執(zhí)行目標(biāo)方法after(cls,method,result); //目標(biāo)方法執(zhí)行后代理方法after執(zhí)行}else {result = proxyChain.doProxyChain(); //執(zhí)行目標(biāo)方法 }}catch(Exception e){logger.error("proxy failure",e);error(cls,method,params,e); //拋出異常時代理方法error執(zhí)行throw e;}finally{end(); //代理結(jié)束時執(zhí)行方法end }return null;}/*方法開始前執(zhí)行*/public void begin(){}/*** 攔截* @param cls 目標(biāo)類* @param method 目標(biāo)方法* @param params 目標(biāo)方法參數(shù)* @return 返回是否攔截*/public boolean intercept(Class<?> cls, Method method, Object[] params) throws Throwable {return true;}/*** 前置增強(qiáng)* @param cls 目標(biāo)類* @param method 目標(biāo)方法* @param params 目標(biāo)方法參數(shù)*/public void before(Class<?> cls, Method method, Object[] params) throws Throwable {}/*** 后置增強(qiáng)* @param cls 目標(biāo)類* @param method 目標(biāo)方法* @param result 目標(biāo)方法返回結(jié)果*/public void after(Class<?> cls, Method method, Object result) throws Throwable {}/*** 拋出增強(qiáng)* @param cls 目標(biāo)類* @param method 目標(biāo)方法* @param params 目標(biāo)方法參數(shù)* @param e 異常* @throws Throwable*/public void error(Class<?> cls, Method method, Object[] params, Exception e) throws Throwable {}/*方法結(jié)束后執(zhí)行*/public void end(){} }

注意這里的AspectProxy類中的doProxy方法,我們從proxyChain參數(shù)中獲取了目標(biāo)類、目標(biāo)方法與方法參數(shù),隨后通過一個try...catch...finally代碼塊來實現(xiàn)調(diào)用框架,從框架中抽象出一系列的“鉤子方法”,這些抽象方法可在AspectProxy的子類中有選擇性的實現(xiàn),例如ControllerAspect

/*** 攔截所有Controller方法*/ @Aspect(Controller.class) public class ControllerAspect extends AspectProxy{private static final Logger LOGGER = LoggerFactory.getLogger(ControllerAspect.class);private long begin; //方法開始時間/*** 前置增強(qiáng)* @param cls 目標(biāo)類* @param method 目標(biāo)方法* @param params 目標(biāo)方法參數(shù)*/@Overridepublic 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();}/*** 后置增強(qiáng)* @param cls 目標(biāo)類* @param method 目標(biāo)方法* @param result 目標(biāo)方法返回結(jié)果*/@Overridepublic void after(Class<?> cls, Method method, Object result) throws Throwable {LOGGER.debug(String.format("time: %ds", System.currentTimeMillis()-begin));LOGGER.debug("---------end---------");} }

這里只實現(xiàn)了before與after方法,就可以在目標(biāo)方法執(zhí)行前后添加其他需要執(zhí)行的代碼了。

那么這樣就結(jié)束了嗎?當(dāng)然不是。我們需要在整個框架里使用ProxyManager來創(chuàng)建代理對象,并將該代理對象放入框架底層的BeanMap中,隨后才能通過IOC將被代理的對象注入到其他對象中。

加載AOP框架

按照之前的套路,為了加載AOP框架,我們需要一個名為AopHelper的類,然后將其添加到HelperLoader類中。

在AOPHelper中我們需要獲取所有的目標(biāo)類及其被攔截的切面類實例,并通過ProxyManager.createProxy方法來創(chuàng)建代理對象,最后將其放入BeanMap中。

首先,需要為BeanHelper類添加一個setBean方法,用于將Bean實例放入Bean?Map中(將實例替換為代理類用),代碼如下:

package org.smart4j.framework.helper;import org.smart4j.framework.util.ReflectionUtil;import java.util.HashMap; import java.util.Map; import java.util.Set;/*** Bean助手類**/ public class BeanHelper {/*** 定義bean映射(用于存放Bean類與Bean實例的映射關(guān)系)*/private static final Map<Class<?>,Object> BEAN_MAP = new HashMap<Class<?>, Object>();static{//獲取所有Controller和Service將類和實例放入Map中 }/*** 獲取Bean映射* @return*/public static Map<Class<?>, Object> getBeanMap() { return BEAN_MAP; }/*** 根據(jù)Class獲取bean實例* @param cls bean實例所屬的類* @param <T> 類的實例對象* @return*/public static <T> T getBean(Class<T> cls){}/*** 設(shè)置Bean實例 - 手動將cls - obj放入到BEANMAP中去(更多用于將實例替換為代理對象)* @param cls 類* @param obj 實例*/public static void setBean(Class<?> cls,Object obj){BEAN_MAP.put(cls,obj);} }

然后,我們需要擴(kuò)展AspectProxy抽象類的所有具體類getClassSetBySuper(),此外,還需要獲取帶有Aspect注解的所有類(即切面),因此需要在ClassHelper中添加一下兩個方法:

public class ClassHelper {/*** 定義類集合*/private static final Set<Class<?>> CLASS_SET;static {String basePackage = ConfigHelper.getAppBasePackage();CLASS_SET = ClassUtil.getClassSet(basePackage);}/*** 獲取應(yīng)用包名下的所有類* @return*/public static Set<Class<?>> getClassSet(){}/*** 獲取所有Controller類* @return*/public static Set<Class<?>> getControllerClassSet(){}/*** 獲取所有Service類* @return*/public static Set<Class<?>> getServiceClassSet(){}/*** 獲取應(yīng)用包名下的所有bean類(Controller和Service)* @return*/public static Set<Class<?>> getBeanClassSet(){}/*** 獲取應(yīng)用包名下某父類(接口)的所有子類(或?qū)崿F(xiàn)類)* @param superClass* @return*/public static Set<Class<?>> getClassSetBySuper(Class<?> superClass){Set<Class<?>> classSet = new HashSet<Class<?>>();for (Class<?> cls:CLASS_SET){if (superClass.isAssignableFrom(cls)&&superClass.equals(cls)){classSet.add(cls);}}return classSet;}/*** 獲取應(yīng)用包名下帶有注解的所有類* @param annotationClass* @return*/public static Set<Class<?>> getClassSetByAnnotation(Class<? extends Annotation> annotationClass){Set<Class<?>> classSet = new HashSet<Class<?>>();for (Class<?> cls : CLASS_SET){if (cls.isAnnotationPresent(annotationClass)){classSet.add(cls);}}return classSet;} }

有了上面連個方法后,createTargetClassSet方法獲取Aspect注解中設(shè)置的注解類,若該注解不是Aspect類,則可調(diào)用ClassHelper.getClassSetByAnnotation方法獲取相應(yīng)的類,并把這些類放入目標(biāo)類集合中,最終返回這個集合。

然后我們用createProxyMap方法獲取代理類及其目標(biāo)類直接按的映射關(guān)系,一個代理類可對應(yīng)一個或多個目標(biāo)類。需要強(qiáng)調(diào)的是,這里所說的代理類指的是切面類。

AOP順序:

代理類需要擴(kuò)展AspectProxy抽象類(通過getClassSetBySuper獲取所有子類(即切面))還需要帶有Aspect注解,只有滿足這兩個條件,才能根據(jù)Aspect注解中所定義的注解屬性去獲取該注解所對應(yīng)的目標(biāo)類集合(通過createTargetClassSet獲取目標(biāo)類集合),然后才能建立代理類與目標(biāo)類集合之間的映射關(guān)系,最終返回這個映射關(guān)系。

一旦獲取了代理類與目標(biāo)類集合之間的映射關(guān)系,createTargetMap方法就能根據(jù)這個關(guān)系分析出目標(biāo)類與代理對象列表之間的映射關(guān)系。

最后通過AOPHelper的靜態(tài)代碼塊初始化整個AOP框架,獲取代理類及其目標(biāo)類集合的映射關(guān)系,進(jìn)一步獲取目標(biāo)類與代理對象列表的映射關(guān)系,進(jìn)而遍歷這個映射關(guān)系,從中獲取目標(biāo)類與代理對象列表,調(diào)用ProxyManager.createProxy方法獲取代理對象調(diào)用BeanHelper.setBean方法,將該代理對象重新放入BeanMap中

import org.smart4j.framework.aop.Aspect; import org.smart4j.framework.aop.AspectProxy; import org.smart4j.framework.aop.Proxy; import org.smart4j.framework.aop.ProxyManager; import org.slf4j.Logger; import org.slf4j.LoggerFactory;import java.lang.annotation.Annotation; import java.util.*;/*** 方法攔截助手類*/ public class AopHelper {private static final Logger LOGGER = LoggerFactory.getLogger(AopHelper.class);static{try{Map<Class<?>,Set<Class<?>>> proxyMap = createProxyMap(); //獲取Map<代理類,Set<目標(biāo)類>>Map<Class<?>,List<Proxy>> targetMap = createTargetMap(proxyMap); //獲取Map<目標(biāo)類,List<代理實例>>for (Map.Entry<Class<?>,List<Proxy>> targetEntry:targetMap.entrySet()){ //遍歷Map<目標(biāo)類,List<代理實例>>Class<?> targetClass = targetEntry.getKey(); //目標(biāo)類List<Proxy> proxyList = targetEntry.getValue(); //代理類Object proxy = ProxyManager.createProxy(targetClass,proxyList); //根據(jù)目標(biāo)類和代理集合創(chuàng)建一個代理BeanHelper.setBean(targetClass,proxy); //將Bean容器中目標(biāo)類對應(yīng)的實體替換成代理 }}catch (Exception e){LOGGER.error("aop failure",e);}}/*** 根據(jù)Aspect注解(切點)獲取所有的代理目標(biāo)類集合(目標(biāo)類為Controller等注解的類)* @param aspect 代理類注解,用來指定目標(biāo)類的注解 例如:@Aspect(Controller.class)* @return 返回Aspect注解中指定value注解的目標(biāo)類 例如:帶Controller注解的所有類* 例如Aspect(Controller.class)是指獲取所有Controller注解的類*/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)){ //獲取的value注解不為null,且注解不為AspecttargetClassSet.addAll(ClassHelper.getClassSetByAnnotation(annotation)); //加入所有value(切點)指定的注解的類 }return targetClassSet; //返回所有目標(biāo)類 }/*** 創(chuàng)建所有Map<代理類,Set<代理目標(biāo)類>>的映射關(guān)系* @return Map<代理類,Set<代理目標(biāo)類>>* @throws Exception*/private static Map<Class<?>,Set<Class<?>>> createProxyMap() throws Exception{Map<Class<?>,Set<Class<?>>> proxyMap = new HashMap<Class<?>, Set<Class<?>>>(); //結(jié)果集<代理類,Set<代理目標(biāo)類>>//獲取所有的AspectProxy的子類(代理類集合),即切面,/*這個是入口,根據(jù)基類來查找所有的切面(代理類),獲取所有的切面!!!*/Set<Class<?>> proxyClassSet = ClassHelper.getClassSetBySuper(AspectProxy.class);for (Class<?> proxyClass : proxyClassSet){ //遍歷代理類(切面),如ControllerAspectif (proxyClass.isAnnotationPresent(Aspect.class)){ //驗證基類為AspectProxy且要有Aspect注解的才能為切面。如果代理類的的注解為Aspect(也就是說代理類一定要都切點(注解)才能是切面),例如ControllerAspect代理類的注解為@Aspect(Controller.class)Aspect aspect = proxyClass.getAnnotation(Aspect.class); //獲取代理類(切面)的注解/*根據(jù)注解獲取所有的目標(biāo)類*/Set<Class<?>> targetClassSet = createTargetClassSet(aspect); //獲取所有的代理目標(biāo)類集合 proxyMap.put(proxyClass,targetClassSet); //加入到結(jié)果集Map<代理類,Set<代理目標(biāo)類>>中 }}return proxyMap;}/*** 將Map<代理類,Set<目標(biāo)類>> proxyMap轉(zhuǎn)為Map<目標(biāo)類,List<代理類>> targetMap* @param proxyMap Map<代理類,Set<目標(biāo)類>>* @return Map<目標(biāo)類,List<代理類實例>>* @throws Exception*/private static Map<Class<?>,List<Proxy>> createTargetMap(Map<Class<?>,Set<Class<?>>> proxyMap) throws Exception{Map<Class<?>,List<Proxy>> targetMap = new HashMap<Class<?>,List<Proxy>>(); //class - list鍵值對的mapfor (Map.Entry<Class<?>,Set<Class<?>>> proxyEntry:proxyMap.entrySet()){ //遍歷cls - set鍵值對的mapClass<?> proxyClass = proxyEntry.getKey(); //獲取代理clsSet<Class<?>> targetClassSet = proxyEntry.getValue(); //獲取目標(biāo)Setfor (Class<?> targetClass:targetClassSet){ //遍歷目標(biāo)SetProxy proxy = (Proxy) proxyClass.newInstance(); //實例化代理類if (targetMap.containsKey(targetClass)){ //如果Map<Class<?>,List<Proxy>>包含該目標(biāo)類targetMap.get(targetClass).add(proxy); //直接將代理類添加到對應(yīng)目標(biāo)類的Map中}else{List<Proxy> proxyList = new ArrayList<Proxy>(); //如果沒有 proxyList.add(proxy);targetMap.put(targetClass,proxyList);}}}return targetMap;} }

最后,需要注意的是,AOPHelper要在IOCHelper之前加載,因為首先需要通過AopHelper獲取代理對象,然后才能通過IOCHelper進(jìn)行依賴注入。否則的話,IOCHelper先加載就會導(dǎo)致Bean容器中的是代理,而Bean中注入的是原本的實例對象。所以注入一定要最后進(jìn)行(IOCHelper一定要最后加載)

源碼?

轉(zhuǎn)載于:https://www.cnblogs.com/aeolian/p/9931922.html

總結(jié)

以上是生活随笔為你收集整理的架构探险笔记5-使框架具备AOP特性(下)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 午夜网站免费 | 一边摸上面一边摸下面 | 99久久婷婷国产精品综合 | 天天干,天天操,天天射 | 狠狠干狠狠操 | 日本熟妇一区二区三区 | 中文字幕人妻丝袜二区 | 亲切的金子餐桌片段的金子 | 中文字幕麻豆 | 99国产精品一区二区 | 人人妻人人澡人人爽精品日本 | 日本在线精品 | 国产欧美一区二区三区视频 | 综合图区亚洲 | 亚洲精品嫩草 | 18成人免费观看网站下载 | 操小妹影院 | 国产网址在线观看 | 国产乱欲视频 | 围产精品久久久久久久 | 丁香花免费高清完整在线播放 | 亚洲四虎av | 国产久精品 | 国产思思99re99在线观看 | 国产色91 | 日本美女动态图 | 草莓巧克力香氛动漫的观看方法 | 成人av影视在线 | 亚洲一卡二卡在线观看 | 特黄aaaaaaaaa毛片免费视频 | 女王人厕视频2ⅴk | 黄色av大全 | 久久888| 四虎永久地址 | 男女野外做受全过程 | 丁香婷婷激情 | 禁断介护av | 欧美日韩亚洲高清 | 国产成人毛毛毛片 | 91在线小视频 | 91热爆视频 | 国产乱轮视频 | 免费的毛片视频 | 一起草最新网址 | 国产黄色录相 | 1024手机看片日韩 | 又污又黄的网站 | 美女的诞生免费观看在线高清 | 国产精品自拍偷拍 | 成年人在线网站 | 欧美日韩字幕 | 91超级碰| 91视频h | 国产jjizz一区二区三区视频 | 国产一区二区三区精品在线观看 | 明星毛片 | 欧美videossex极品 | 成人在线免费网站 | 国产九九热视频 | 国产一级不卡毛片 | 粉嫩一区二区三区 | 成人拍拍 | 国内久久久 | 裸体黄色片 | 精品国产一区二区三区久久 | 欧美亚洲综合另类 | 超级碰在线视频 | 大肉大捧一进一出好爽 | 91精品久久人妻一区二区夜夜夜 | 欧洲av一区二区 | 鲁大师私人影院在线观看 | 99热激情| 男人天堂2024| wwwxxx色 | 原神淫辱系列同人h | 69久久夜色精品国产69 | 男女视频免费 | av在线手机观看 | 就去吻亚洲 | 日韩一区免费观看 | 成人免费影院 | 日韩欧美一区视频 | 成人性生交大片免费看r链接 | 欧美不卡在线 | 欧美精品一区二区三 | 欧美高h| 日韩在线一 | 美女脱得一干二净 | 国产二区视频在线观看 | 日韩中文在线一区 | 日韩欧美国产亚洲 | 国产美女无遮挡免费 | 欧美中文视频 | 日韩色图在线观看 | 国产日韩在线观看视频 | 久久澡 | 国产一区亚洲一区 | 免费观看毛片 | 超能一家人电影免费喜剧在线观看 |