宅男在线永久免费观看网直播,亚洲欧洲日产国码无码久久99,野花社区在线观看视频,亚洲人交乣女bbw,一本一本久久a久久精品综合不卡

全部
常見(jiàn)問(wèn)題
產(chǎn)品動(dòng)態(tài)
精選推薦

Spring Boot中使用AOP統(tǒng)一處理Web請(qǐng)求日志

管理 管理 編輯 刪除

AOP為Aspect Oriented Programming的縮寫(xiě),意為:面向切面編程,通過(guò)預(yù)編譯方式和運(yùn)行期動(dòng)態(tài)代理實(shí)現(xiàn)程序功能的統(tǒng)一維護(hù)的一種技術(shù)。AOP是Spring框架中的一個(gè)重要內(nèi)容,它通過(guò)對(duì)既有程序定義一個(gè)切入點(diǎn),然后在其前后切入不同的執(zhí)行內(nèi)容,比如常見(jiàn)的有:打開(kāi)數(shù)據(jù)庫(kù)連接/關(guān)閉數(shù)據(jù)庫(kù)連接、打開(kāi)事務(wù)/關(guān)閉事務(wù)、記錄日志等?;贏OP不會(huì)破壞原來(lái)程序邏輯,因此它可以很好的對(duì)業(yè)務(wù)邏輯的各個(gè)部分進(jìn)行隔離,從而使得業(yè)務(wù)邏輯各部分之間的耦合度降低,提高程序的可重用性,同時(shí)提高了開(kāi)發(fā)的效率。

下面主要講兩個(gè)內(nèi)容:

  • 一個(gè)是如何在Spring Boot中引入Aop功能
  • 二是如何使用Aop做切面去統(tǒng)一處理Web請(qǐng)求的日志

以下所有操作基于chapter4-2-2工程open in new window進(jìn)行。

#準(zhǔn)備工作

因?yàn)樾枰獙?duì)web請(qǐng)求做切面來(lái)記錄日志,所以先引入web模塊,并創(chuàng)建一個(gè)簡(jiǎn)單的hello請(qǐng)求的處理。

  • pom.xml中引入web模塊
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>





  • 實(shí)現(xiàn)一個(gè)簡(jiǎn)單請(qǐng)求處理:通過(guò)傳入name參數(shù),返回“hello xxx”的功能。
@RestController
public class HelloController {

    @RequestMapping(value = "/hello", method = RequestMethod.GET)
    @ResponseBody
    public String hello(@RequestParam String name) {
        return "Hello " + name;
    }

}











下面,我們可以對(duì)上面的/hello請(qǐng)求,進(jìn)行切面日志記錄。

#引入AOP依賴

在Spring Boot中引入AOP就跟引入其他模塊一樣,非常簡(jiǎn)單,只需要在pom.xml中加入如下依賴:


<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>





在完成了引入AOP依賴包后,一般來(lái)說(shuō)并不需要去做其他配置。也許在Spring中使用過(guò)注解配置方式的人會(huì)問(wèn)是否需要在程序主類中增加@EnableAspectJAutoProxy來(lái)啟用,實(shí)際并不需要。

可以看下面關(guān)于AOP的默認(rèn)配置屬性,其中spring.aop.auto屬性默認(rèn)是開(kāi)啟的,也就是說(shuō)只要引入了AOP依賴后,默認(rèn)已經(jīng)增加了@EnableAspectJAutoProxy。


# AOP
spring.aop.auto=true # Add @EnableAspectJAutoProxy.
spring.aop.proxy-target-class=false # Whether subclass-based (CGLIB) proxies are to be created (true) as
 opposed to standard Java interface-based proxies (false).





而當(dāng)我們需要使用CGLIB來(lái)實(shí)現(xiàn)AOP的時(shí)候,需要配置spring.aop.proxy-target-class=true,不然默認(rèn)使用的是標(biāo)準(zhǔn)Java的實(shí)現(xiàn)。

#實(shí)現(xiàn)Web層的日志切面

實(shí)現(xiàn)AOP的切面主要有以下幾個(gè)要素:

  • 使用@Aspect注解將一個(gè)java類定義為切面類
  • 使用@Pointcut定義一個(gè)切入點(diǎn),可以是一個(gè)規(guī)則表達(dá)式,比如下例中某個(gè)package下的所有函數(shù),也可以是一個(gè)注解等。
  • 根據(jù)需要在切入點(diǎn)不同位置的切入內(nèi)容
  • 使用@Before在切入點(diǎn)開(kāi)始處切入內(nèi)容
  • 使用@After在切入點(diǎn)結(jié)尾處切入內(nèi)容
  • 使用@AfterReturning在切入點(diǎn)return內(nèi)容之后切入內(nèi)容(可以用來(lái)對(duì)處理返回值做一些加工處理)
  • 使用@Around在切入點(diǎn)前后切入內(nèi)容,并自己控制何時(shí)執(zhí)行切入點(diǎn)自身的內(nèi)容
  • 使用@AfterThrowing用來(lái)處理當(dāng)切入內(nèi)容部分拋出異常之后的處理邏輯
@Aspect
@Component
public class WebLogAspect {

    private Logger logger = Logger.getLogger(getClass());

    @Pointcut("execution(public * com.didispace.web..*.*(..))")
    public void webLog(){}

    @Before("webLog()")
    public void doBefore(JoinPoint joinPoint) throws Throwable {
        // 接收到請(qǐng)求,記錄請(qǐng)求內(nèi)容
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();

        // 記錄下請(qǐng)求內(nèi)容
        logger.info("URL : " + request.getRequestURL().toString());
        logger.info("HTTP_METHOD : " + request.getMethod());
        logger.info("IP : " + request.getRemoteAddr());
        logger.info("CLASS_METHOD : " + joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
        logger.info("ARGS : " + Arrays.toString(joinPoint.getArgs()));

    }

    @AfterReturning(returning = "ret", pointcut = "webLog()")
    public void doAfterReturning(Object ret) throws Throwable {
        // 處理完請(qǐng)求,返回內(nèi)容
        logger.info("RESPONSE : " + ret);
    }

}
































可以看上面的例子,通過(guò)@Pointcut定義的切入點(diǎn)為com.didispace.web包下的所有函數(shù)(對(duì)web層所有請(qǐng)求處理做切入點(diǎn)),然后通過(guò)@Before實(shí)現(xiàn),對(duì)請(qǐng)求內(nèi)容的日志記錄(本文只是說(shuō)明過(guò)程,可以根據(jù)需要調(diào)整內(nèi)容),最后通過(guò)@AfterReturning記錄請(qǐng)求返回的對(duì)象。

通過(guò)運(yùn)行程序并訪問(wèn):http://localhost:8080/hello?name=didi,可以獲得下面的日志輸出


2016-05-19 13:42:13,156  INFO WebLogAspect:41 - URL : http://localhost:8080/hello
2016-05-19 13:42:13,156  INFO WebLogAspect:42 - HTTP_METHOD : http://localhost:8080/hello
2016-05-19 13:42:13,157  INFO WebLogAspect:43 - IP : 0:0:0:0:0:0:0:1
2016-05-19 13:42:13,160  INFO WebLogAspect:44 - CLASS_METHOD : com.didispace.web.HelloController.hello
2016-05-19 13:42:13,160  INFO WebLogAspect:45 - ARGS : [didi]
2016-05-19 13:42:13,170  INFO WebLogAspect:52 - RESPONSE:Hello didi







#優(yōu)化:AOP切面中的同步問(wèn)題

在WebLogAspect切面中,分別通過(guò)doBefore和doAfterReturning兩個(gè)獨(dú)立函數(shù)實(shí)現(xiàn)了切點(diǎn)頭部和切點(diǎn)返回后執(zhí)行的內(nèi)容,若我們想統(tǒng)計(jì)請(qǐng)求的處理時(shí)間,就需要在doBefore處記錄時(shí)間,并在doAfterReturning處通過(guò)當(dāng)前時(shí)間與開(kāi)始處記錄的時(shí)間計(jì)算得到請(qǐng)求處理的消耗時(shí)間。

那么我們是否可以在WebLogAspect切面中定義一個(gè)成員變量來(lái)給doBefore和doAfterReturning一起訪問(wèn)呢?是否會(huì)有同步問(wèn)題呢?

的確,直接在這里定義基本類型會(huì)有同步問(wèn)題,所以我們可以引入ThreadLocal對(duì)象,像下面這樣進(jìn)行記錄:


@Aspect
@Component
public class WebLogAspect {

    private Logger logger = Logger.getLogger(getClass());

    ThreadLocal<Long> startTime = new ThreadLocal<>();

    @Pointcut("execution(public * com.didispace.web..*.*(..))")
    public void webLog(){}

    @Before("webLog()")
    public void doBefore(JoinPoint joinPoint) throws Throwable {
        startTime.set(System.currentTimeMillis());

        // 省略日志記錄內(nèi)容
    }

    @AfterReturning(returning = "ret", pointcut = "webLog()")
    public void doAfterReturning(Object ret) throws Throwable {
        // 處理完請(qǐng)求,返回內(nèi)容
        logger.info("RESPONSE : " + ret);
        logger.info("SPEND TIME : " + (System.currentTimeMillis() - startTime.get()));
    }


}




























#優(yōu)化:AOP切面的優(yōu)先級(jí)

由于通過(guò)AOP實(shí)現(xiàn),程序得到了很好的解耦,但是也會(huì)帶來(lái)一些問(wèn)題,比如:我們可能會(huì)對(duì)Web層做多個(gè)切面,校驗(yàn)用戶,校驗(yàn)頭信息等等,這個(gè)時(shí)候經(jīng)常會(huì)碰到切面的處理順序問(wèn)題。

所以,我們需要定義每個(gè)切面的優(yōu)先級(jí),我們需要@Order(i)注解來(lái)標(biāo)識(shí)切面的優(yōu)先級(jí)。i的值越小,優(yōu)先級(jí)越高。假設(shè)我們還有一個(gè)切面是CheckNameAspect用來(lái)校驗(yàn)name必須為didi,我們?yōu)槠湓O(shè)置@Order(10),而上文中WebLogAspect設(shè)置為@Order(5),所以WebLogAspect有更高的優(yōu)先級(jí),這個(gè)時(shí)候執(zhí)行順序是這樣的:

  • @Before中優(yōu)先執(zhí)行@Order(5)的內(nèi)容,再執(zhí)行@Order(10)的內(nèi)容
  • @After@AfterReturning中優(yōu)先執(zhí)行@Order(10)的內(nèi)容,再執(zhí)行@Order(5)的內(nèi)容

所以我們可以這樣子總結(jié):

  • 在切入點(diǎn)前的操作,按order的值由小到大執(zhí)行
  • 在切入點(diǎn)后的操作,按order的值由大到小執(zhí)行

#代碼示例

本文的相關(guān)例子可以查看下面?zhèn)}庫(kù)中的chapter4-2-4目錄:


請(qǐng)登錄后查看

CRMEB 最后編輯于2025-01-22 16:43:35

快捷回復(fù)
回復(fù)
回復(fù)
回復(fù)({{post_count}}) {{!is_user ? '我的回復(fù)' :'全部回復(fù)'}}
排序 默認(rèn)正序 回復(fù)倒序 點(diǎn)贊倒序

{{item.user_info.nickname ? item.user_info.nickname : item.user_name}} LV.{{ item.user_info.bbs_level || item.bbs_level }}

作者 管理員 企業(yè)

{{item.floor}}# 同步到gitee 已同步到gitee {{item.is_suggest == 1? '取消推薦': '推薦'}}
{{item.is_suggest == 1? '取消推薦': '推薦'}}
沙發(fā) 板凳 地板 {{item.floor}}#
{{item.user_info.title || '暫無(wú)簡(jiǎn)介'}}
附件

{{itemf.name}}

{{item.created_at}}  {{item.ip_address}}
打賞
已打賞¥{{item.reward_price}}
{{item.like_count}}
{{item.showReply ? '取消回復(fù)' : '回復(fù)'}}
刪除
回復(fù)
回復(fù)

{{itemc.user_info.nickname}}

{{itemc.user_name}}

回復(fù) {{itemc.comment_user_info.nickname}}

附件

{{itemf.name}}

{{itemc.created_at}}
打賞
已打賞¥{{itemc.reward_price}}
{{itemc.like_count}}
{{itemc.showReply ? '取消回復(fù)' : '回復(fù)'}}
刪除
回復(fù)
回復(fù)
查看更多
打賞
已打賞¥{{reward_price}}
1300
{{like_count}}
{{collect_count}}
添加回復(fù) ({{post_count}})

相關(guān)推薦

快速安全登錄

使用微信掃碼登錄
{{item.label}} 加精
{{item.label}} {{item.label}} 板塊推薦 常見(jiàn)問(wèn)題 產(chǎn)品動(dòng)態(tài) 精選推薦 首頁(yè)頭條 首頁(yè)動(dòng)態(tài) 首頁(yè)推薦
取 消 確 定
回復(fù)
回復(fù)
問(wèn)題:
問(wèn)題自動(dòng)獲取的帖子內(nèi)容,不準(zhǔn)確時(shí)需要手動(dòng)修改. [獲取答案]
答案:
提交
bug 需求 取 消 確 定
打賞金額
當(dāng)前余額:¥{{rewardUserInfo.reward_price}}
{{item.price}}元
請(qǐng)輸入 0.1-{{reward_max_price}} 范圍內(nèi)的數(shù)值
打賞成功
¥{{price}}
完成 確認(rèn)打賞

微信登錄/注冊(cè)

切換手機(jī)號(hào)登錄

{{ bind_phone ? '綁定手機(jī)' : '手機(jī)登錄'}}

{{codeText}}
切換微信登錄/注冊(cè)
暫不綁定
CRMEB客服

CRMEB咨詢熱線 咨詢熱線

400-8888-794

微信掃碼咨詢

CRMEB開(kāi)源商城下載 源碼下載 CRMEB幫助文檔 幫助文檔
返回頂部 返回頂部
CRMEB客服