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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

Spring容器装饰者模式应用之实现业务类与服务类自由组合的解决方式

發(fā)布時間:2025/3/21 javascript 15 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Spring容器装饰者模式应用之实现业务类与服务类自由组合的解决方式 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

在不論什么一個項目中都不可或缺的存在兩種bean,一種是實現(xiàn)系統(tǒng)核心功能的bean,我們稱之為業(yè)務類,第二種是與系統(tǒng)核心業(yè)務無關(guān)但同一時候又提供十分重要服務bean,我們稱之為服務類。業(yè)務類的bean依據(jù)每一個系統(tǒng)自身核心功能的不同能夠有隨意多個,可是服務類的種類在各個系統(tǒng)之間的差異卻并非非常大。在系統(tǒng)中經(jīng)經(jīng)常使用到的服務有下面幾種。權(quán)限服務,日志服務。緩存服務,事務服務以及預警服務等。在整個系統(tǒng)的不斷進化過程中。服務類與業(yè)務類的關(guān)系也不斷的發(fā)生著變化,由當初垂直模式變?yōu)闄M切模式,這也是編程思想不斷演化過程。服務類與業(yè)務類本來就不應耦合在一起,否則不但會造成大量的代碼冗余同一時候也難以對服務進行可控性變更。

那么怎樣解決依據(jù)不同業(yè)務類自身要求為其提供不同服務的問題呢?spring?aop給出了完美解決?方案。Spring解決這個難題的核心思想是將服務類與業(yè)務類統(tǒng)統(tǒng)交由spring容器管理。依據(jù)不同業(yè)務類的不同要求動態(tài)配置服務類。也即動態(tài)聯(lián)編服務類與業(yè)務類實現(xiàn)兩者的自由組合。至于業(yè)務類與服務類之間的關(guān)系演變能夠用下圖簡單呈現(xiàn)一下:

這張圖是最原始的業(yè)務-服務關(guān)系圖,看到這連想都不敢想了,相同的服務反復出如今N多個業(yè)務中,想想也是醉了,假設哪天服務內(nèi)容改變除了跳樓預計也沒有別的選擇了,還好Spring AOP的出現(xiàn)將這個讓人頭疼的問題。使用Spring 注解方式將切面類橫切到各個服務類中就能夠一絕解決代碼冗余。難于維護的問題


本圖在代碼中的提現(xiàn)例如以下:

package com.test.util;@Aspect public class AuthorityService {@Autowiredprivate LogManager logManager;@Before("execution(* com.test.web.*.*(..))")public void logAll(JoinPoint point) throws Throwable {System.out.println("======authority-before======");}@After("execution(* com.test.web.*.*(..))")public void after() {System.out.println("=========authority-after=========");}// 方法運行的前后調(diào)用@Around("execution(* com.test.web.*.*(..))")public Object around(ProceedingJoinPoint point) throws Throwable {System.out.println("======authority-around開始之前before======");HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();// 獲得具體時間SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");// Calendar ca = Calendar.getInstance();// String operDate = df.format(ca.getTime());Log sysLog = new Log();// 開始時間sysLog.setStartTime(df.format(new Date()));// 獲取ip地址String ip = TCPIPUtil.getIpAddr(request);String loginName;String name;String methodRemark = getMthodRemark(point);String methodName = point.getSignature().getName();String packages = point.getThis().getClass().getName();if (packages.indexOf("$$EnhancerByCGLIB$$") > -1) { // 假設是CGLIB動態(tài)生成的類try {packages = packages.substring(0, packages.indexOf("$$"));} catch (Exception ex) {ex.printStackTrace();}}Object object;try {// method_param = point.getArgs(); //獲取方法參數(shù)// String param=(String) point.proceed(point.getArgs());object = point.proceed();} catch (Exception e) {// 異常處理記錄日志..log.error(e);throw e;}sysLog.setIp(ip);sysLog.setClazz(packages);sysLog.setMethod(methodName);sysLog.setMessage(methodRemark);// 結(jié)束時間sysLog.setEndTime(df.format(new Date()));// 返回結(jié)果if (object == null) {sysLog.setResult("無返回值");} else {sysLog.setResult(object.toString());}logManager.addLog(sysLog);System.out.println("======authority-around開始之前after======");return object;}@AfterReturning("execution(* com.test.web.*.*(..))")public void x(){System.out.println("-------authority-afterreturning-------");}// 獲取方法的中文備注____用于記錄用戶的操作日志描寫敘述public static String getMthodRemark(ProceedingJoinPoint joinPoint)throws Exception {String targetName = joinPoint.getTarget().getClass().getName();String methodName = joinPoint.getSignature().getName();Object[] arguments = joinPoint.getArgs();Class targetClass = Class.forName(targetName);Method[] method = targetClass.getMethods();String methode = "";for (Method m : method) {if (m.getName().equals(methodName)) {Class[] tmpCs = m.getParameterTypes();if (tmpCs.length == arguments.length) {Logger methodCache = m.getAnnotation(Logger.class);// 獲得標記,為空時沒有標記if (methodCache != null) {methode = methodCache.remark();}break;}}}return methode;}}
從上面代碼能夠看出該權(quán)限服務類切入到了com.test.web包下的全部類的全部方法上。同理我們能夠再建立緩存服務類。日志服務類等分別切入到其它業(yè)務類中,如今看來這個令人頭疼的問題似乎被spring基于@Aspect風格的aop解決掉了,可是我們細致想一想問題真的攻克了嗎?大家都知道這種切入方式粒度實在是太粗了,并非同樣包下的全部類的全部方法都須要這種服務,舉個非常easy的樣例。就拿緩存服務和日志服務來講,日志服務是須要具體記錄的它能夠切入不論什么類的不論什么方法上??墒蔷彺娣諈s并非這樣。緩存服務僅僅可能存在于類的獲取數(shù)據(jù)的方法上,此時將緩存服務切入到類的改動。刪除等方法上就顯得非常奇葩了,再通俗的將就是不論什么一個服務都可能僅僅存在于特定類的特定方法上,這個不確定性決定了僅僅使用Spring @Aspect注解方式是難以解決下圖問題的

此時我們須要如何做呢?還好Spring同一時候提供了基于xml配置方式的aop,這種方式在相當大的程度上彌補了@Aspect不足,他能夠依據(jù)不同的配置方式將不同的服務切入到不同類的不同方法上。這樣細的粒度足以讓我們實現(xiàn)各種服務對業(yè)務的動態(tài)組合。說道這可能會有人問既然spring提供了基于xml配置的aop。那我們僅僅須要將不同的服務均配置在xml文件里不是相同能夠?qū)崿F(xiàn)業(yè)務與服務的動態(tài)組合嗎?聽上去似乎非常有道理,果真這種話似乎基于注解的aop似乎就能夠被替代了??墒浅绦蛐实膯栴}又讓我們不得不正確xml配置方式和注解方式進行再次衡量。

因為xml是在執(zhí)行期動態(tài)聯(lián)編確定切面的,解析xml的過程毫無疑問的會占用系統(tǒng)資源,假設將大量的aop配置配置在xml文件里將會得不償失,而@Aspect方式支持編譯期織入且不須要生成代理,這樣就使得效率上會有優(yōu)勢。如此來看僅僅要將xml方式與@Aspect方式混合使用。將粗粒度的服務(如日志和權(quán)限服務)使用@Aspect方式進行切入,對于細粒度的服務(如緩存服務)使用xml方式配置在spring中就能夠完美解決以上問題了。

以下是兩種方式結(jié)合使用的實例。先來看配置文件:

<?

xml version="1.0" encoding="UTF-8"?

> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd"> <!-- 注解掃描包 --> <context:component-scan base-package="com.test" /> <!-- 開啟注解 --> <mvc:annotation-driven /> <!-- 靜態(tài)資源(js/image)的訪問 --> <mvc:resources location="/js/" mapping="/js/**" /> <!-- 定義視圖解析器 --> <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/"></property> <property name="suffix" value=".jsp"></property> </bean> <!-- 啟用Spring對基于@AspectJ aspects的配置支持 --> <aop:aspectj-autoproxy></aop:aspectj-autoproxy> <bean id="logService" class="com.test.util.LogService"></bean> <bean id="cacheService" class="com.test.util.CacheService"></bean> <aop:config proxy-target-class="true"> <aop:aspect ref="cacheService"> <aop:pointcut id="log" expression="execution(* com.test.web.UserController.getAllUser(..))"/> <aop:before pointcut-ref="log" method="logAll"/> <aop:after pointcut-ref="log" method="after"/> <aop:after-returning pointcut-ref="log" method="x"/> <aop:around pointcut-ref="log" method="around"/> </aop:aspect> </aop:config> </beans>


接下來是日志服務類:

package com.test.util;@Aspect public class LogService {@Autowiredprivate LogManager logManager;@Before("execution(* com.test.web.*.*(..))")public void logAll(JoinPoint point) throws Throwable {System.out.println("======log-before======");}@After("execution(* com.test.web.*.*(..))")public void after() {System.out.println("=========cache-after=========");}// 方法運行的前后調(diào)用@Around("execution(* com.test.web.*.*(..))")public Object around(ProceedingJoinPoint point) throws Throwable {System.out.println("======log-around開始之前before======");HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();// 獲得具體時間SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");Log sysLog = new Log();// 開始時間sysLog.setStartTime(df.format(new Date()));// 獲取ip地址String ip = TCPIPUtil.getIpAddr(request);String loginName;String name;String methodRemark = getMthodRemark(point);String methodName = point.getSignature().getName();String packages = point.getThis().getClass().getName();if (packages.indexOf("$$EnhancerByCGLIB$$") > -1) { // 假設是CGLIB動態(tài)生成的類try {packages = packages.substring(0, packages.indexOf("$$"));} catch (Exception ex) {ex.printStackTrace();}}// String operatingcontent = "";// Object[] method_param = null;Object object;try {// method_param = point.getArgs(); //獲取方法參數(shù)// String param=(String) point.proceed(point.getArgs());object = point.proceed();} catch (Exception e) {// 異常處理記錄日志..log.error(e);throw e;}sysLog.setIp(ip);sysLog.setClazz(packages);// 包名.+方法名// packages + "." + methodNamesysLog.setMethod(methodName);sysLog.setMessage(methodRemark);// 結(jié)束時間sysLog.setEndTime(df.format(new Date()));// 返回結(jié)果if (object == null) {sysLog.setResult("無返回值");} else {sysLog.setResult(object.toString());}logManager.addLog(sysLog);System.out.println("======log-around開始之前after======");return object;}@AfterReturning("execution(* com.test.web.*.*(..))")public void x(){System.out.println("-------log-afterreturning-------");}// 獲取方法的中文備注____用于記錄用戶的操作日志描寫敘述public static String getMthodRemark(ProceedingJoinPoint joinPoint)throws Exception {String targetName = joinPoint.getTarget().getClass().getName();String methodName = joinPoint.getSignature().getName();Object[] arguments = joinPoint.getArgs();Class targetClass = Class.forName(targetName);Method[] method = targetClass.getMethods();String methode = "";for (Method m : method) {if (m.getName().equals(methodName)) {Class[] tmpCs = m.getParameterTypes();if (tmpCs.length == arguments.length) {Logger methodCache = m.getAnnotation(Logger.class);// 獲得標記,為空時沒有標記if (methodCache != null) {methode = methodCache.remark();}break;}}}return methode;}}
再接下來是緩存服務類;

package com.test.util;public class LogService {@Autowiredprivate CacheManager logManager;public void pointcut() {}public void logAll(JoinPoint point) throws Throwable {System.out.println("======cache-before======");}public void after() {System.out.println("=========cache-after=========");}// 方法運行的前后調(diào)用public Object around(ProceedingJoinPoint point) throws Throwable {System.out.println("======cache-around開始之前before======");HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();// 獲得具體時間SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");// Calendar ca = Calendar.getInstance();// String operDate = df.format(ca.getTime());Log sysLog = new Log();// 開始時間sysLog.setStartTime(df.format(new Date()));// 獲取ip地址String ip = TCPIPUtil.getIpAddr(request);String loginName;String name;String methodRemark = getMthodRemark(point);String methodName = point.getSignature().getName();String packages = point.getThis().getClass().getName();if (packages.indexOf("$$EnhancerByCGLIB$$") > -1) { // 假設是CGLIB動態(tài)生成的類try {packages = packages.substring(0, packages.indexOf("$$"));} catch (Exception ex) {ex.printStackTrace();}}Object object;try {// method_param = point.getArgs(); //獲取方法參數(shù)// String param=(String) point.proceed(point.getArgs());object = point.proceed();} catch (Exception e) {// 異常處理記錄日志..log.error(e);throw e;}sysLog.setIp(ip);sysLog.setClazz(packages);// 包名.+方法名// packages + "." + methodNamesysLog.setMethod(methodName);sysLog.setMessage(methodRemark);// 結(jié)束時間sysLog.setEndTime(df.format(new Date()));// 返回結(jié)果if (object == null) {sysLog.setResult("無返回值");} else {sysLog.setResult(object.toString());}logManager.addLog(sysLog);System.out.println("======cache-around開始之前after======");return object;}public void x(){System.out.println("-------cache-afterreturning-------");}}
日志服務類和緩存服務類僅僅在詳細處理過程中不一樣,本文在日志服務的基礎上稍加修改簡化處理。大家能夠在使用時依據(jù)自身情況進行緩存處理和日志處理。在詳細運行過程中細心的朋友可能會發(fā)如今配置文件里不同服務的出現(xiàn)順序決定了兩個服務的運行順序。也就是說在spring aop運行切入動作是通過裝飾者模式來完畢,採用類似棧的先進后出方式來詳細運行服務這一點大家一定要注意啊。

總結(jié)

以上是生活随笔為你收集整理的Spring容器装饰者模式应用之实现业务类与服务类自由组合的解决方式的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

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

主站蜘蛛池模板: 在线免费黄色网 | 天天想你在线观看完整版高清 | 男插女视频在线观看 | 性一交一乱一伧老太 | 91好色先生tv | 一区二区美女视频 | 91插插影库 | av字幕在线 | 欧美性视屏 | 欧美精品一区二区三区在线 | 国产综合精品 | 在线不卡 | 手机看片99| 欧美日韩高清在线 | 日本特级片| 先锋资源网av | 直接看毛片 | 精品国产一区二区三 | 久久福利精品 | 欧美另类老妇 | 狠狠操在线| 亚洲精品无码永久在线观看 | 亚洲图片欧美 | 亚洲欧洲免费无码 | 亚洲色偷偷色噜噜狠狠99网 | 黑人操中国女人视频 | 免费高清成人 | 婷婷在线网 | 国产视频在线观看网站 | 女同在线观看 | 色草在线| 日本免费黄色 | 综合激情久久 | 六月丁香婷婷网 | 国产福利一区在线 | 天天射天天操天天干 | 99久久精品国产一区二区成人 | 国产手机在线视频 | 成人一级大片 | √8天堂资源地址中文在线 欧美精品在线一区二区 | 日批在线 | 日韩精品中文字幕在线 | 久久青娱乐| 波多野结衣操 | 肉丝袜脚交视频一区二区 | 播播成人网 | 果冻传媒18禁免费视频 | 激情一区二区三区 | 日韩在线视频免费看 | 成人99 | 日韩人妻一区二区三区蜜桃视频 | 亚洲免费一 | 香港三级在线视频 | 国外亚洲成av人片在线观看 | 欧美精品手机在线 | 6090伦理| 男生舔女生胸 | 手机在线一区二区 | 美女三级黄色片 | 精品人妻无码中文字幕18禁 | 五十路在线观看 | 操日韩 | 人妻互换一二三区激情视频 | 亚洲性猛交xxxx乱大交 | 中出亚洲 | 亚洲av无码一区二区三区人 | 午夜小影院 | 男女男精品视频网站 | 精品久久免费 | 亚洲精品电影网 | 亚洲成人久| 日韩精品 欧美 | 国产黄色免费观看 | 亚洲高h | 黄页网站在线播放 | 99av国产精品欲麻豆 | 黑人玩弄人妻一区二区三区 | 成人91看片 | 亚洲成av人在线观看 | 男男gay动漫 | 色5566| 亚洲xxxx视频 | 秋霞成人网 | 亚洲国产aⅴ精品一区二区 日韩黄色在线视频 | 无码国产精品久久一区免费 | 国产吞精囗交免费视频 | 国产一区二区在线视频 | 日本少妇xx| 免费在线观看国产精品 | 免费的黄色网址 | 69精品丰满人妻无码视频a片 | 黄色一级片. | 我和单位漂亮少妇激情 | 亚洲欧美国产日韩精品 | 黄色片美女 | 国产真实在线 | 麻豆影视在线播放 | 色av免费 | 久久成人激情 |