亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Spring AOP 切面@Around注解的用法說(shuō)明

 更新時(shí)間:2021年02月19日 10:51:28   作者:lichuangcsdn  
這篇文章主要介紹了Spring AOP 切面@Around注解的用法說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧

@Around注解可以用來(lái)在調(diào)用一個(gè)具體方法前和調(diào)用后來(lái)完成一些具體的任務(wù)。

比如我們想在執(zhí)行controller中方法前打印出請(qǐng)求參數(shù),并在方法執(zhí)行結(jié)束后來(lái)打印出響應(yīng)值,這個(gè)時(shí)候,我們就可以借助于@Around注解來(lái)實(shí)現(xiàn);

再比如我們想在執(zhí)行方法時(shí)動(dòng)態(tài)修改參數(shù)值等

類(lèi)似功能的注解還有@Before等等,用到了Spring AOP切面思想,Spring AOP常用于攔截器、事務(wù)、日志、權(quán)限驗(yàn)證等方面。

完整演示代碼如下:

需要說(shuō)明的是,在以下例子中,我們即可以只用@Around注解,并設(shè)置條件,見(jiàn)方法run1();也可以用@Pointcut和@Around聯(lián)合注解,見(jiàn)方法pointCut2()和run2(),這2種用法是等價(jià)的。如果我們還想利用其進(jìn)行參數(shù)的修改,則調(diào)用時(shí)必須用joinPoint.proceed(Object[] args)方法,將修改后的參數(shù)進(jìn)行回傳。如果用joinPoint.proceed()方法,則修改后的參數(shù)并不會(huì)真正被使用。

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; 
import javax.persistence.EntityManager;
 
/**
 * 控制器切面
 *
 * @author lichuang
 */
 
@Component
@Aspect
public class ControllerAspect {
 
 private static final Logger logger = LoggerFactory.getLogger(ControllerAspect.class);
 
 @Autowired
 private EntityManager entityManager;
 
 /**
  * 調(diào)用controller包下的任意類(lèi)的任意方法時(shí)均會(huì)調(diào)用此方法
  */
 @Around("execution(* com.company.controller.*.*(..))")
 public Object run1(ProceedingJoinPoint joinPoint) throws Throwable {
  //獲取方法參數(shù)值數(shù)組
  Object[] args = joinPoint.getArgs();
  //得到其方法簽名
  MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
  //獲取方法參數(shù)類(lèi)型數(shù)組
  Class[] paramTypeArray = methodSignature.getParameterTypes();
  if (EntityManager.class.isAssignableFrom(paramTypeArray[paramTypeArray.length - 1])) {
   //如果方法的參數(shù)列表最后一個(gè)參數(shù)是entityManager類(lèi)型,則給其賦值
   args[args.length - 1] = entityManager;
  }
  logger.info("請(qǐng)求參數(shù)為{}",args);
  //動(dòng)態(tài)修改其參數(shù)
  //注意,如果調(diào)用joinPoint.proceed()方法,則修改的參數(shù)值不會(huì)生效,必須調(diào)用joinPoint.proceed(Object[] args)
  Object result = joinPoint.proceed(args);
  logger.info("響應(yīng)結(jié)果為{}",result);
  //如果這里不返回result,則目標(biāo)對(duì)象實(shí)際返回值會(huì)被置為null
  return result;
 }
 
 @Pointcut("execution(* com.company.controller.*.*(..))")
 public void pointCut2() {}
 
 @Around("pointCut2()")
 public Object run2(ProceedingJoinPoint joinPoint) throws Throwable {
  //獲取方法參數(shù)值數(shù)組
  Object[] args = joinPoint.getArgs();
  //得到其方法簽名
  MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
  //獲取方法參數(shù)類(lèi)型數(shù)組
  Class[] paramTypeArray = methodSignature.getParameterTypes();
  if (EntityManager.class.isAssignableFrom(paramTypeArray[paramTypeArray.length - 1])) {
   //如果方法的參數(shù)列表最后一個(gè)參數(shù)是entityManager類(lèi)型,則給其賦值
   args[args.length - 1] = entityManager;
  }
  logger.info("請(qǐng)求參數(shù)為{}",args);
  //動(dòng)態(tài)修改其參數(shù)
  //注意,如果調(diào)用joinPoint.proceed()方法,則修改的參數(shù)值不會(huì)生效,必須調(diào)用joinPoint.proceed(Object[] args)
  Object result = joinPoint.proceed(args);
  logger.info("響應(yīng)結(jié)果為{}",result);
  //如果這里不返回result,則目標(biāo)對(duì)象實(shí)際返回值會(huì)被置為null
  return result;
 }
}

補(bǔ)充:Spring Aop實(shí)例(AOP 如此簡(jiǎn)單)@Aspect、@Around 注解方式配置

IoC相關(guān)的基本內(nèi)容告一段落,本次介紹Spring的第二個(gè)特性,AOP,面向切面編程,術(shù)語(yǔ)聽(tīng)起來(lái)比較不容易理解,沒(méi)關(guān)系,一切盡在實(shí)例中,讓我們看一個(gè)簡(jiǎn)單的實(shí)例,就能明白。

實(shí)例

項(xiàng)目工程目錄結(jié)構(gòu)和代碼獲取地址

獲取地址(版本Log將會(huì)注明每一個(gè)版本對(duì)應(yīng)的課程)

https://github.com/laiyijie/SpringLearning

目錄結(jié)構(gòu)

運(yùn)行工程

運(yùn)行具有Main函數(shù)的 App.java

得到如下輸出

method start time:1480223298250
userHello
method end time:1480223299250

項(xiàng)目詳解

從App.java入手

App.java

package me.laiyijie.demo;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import me.laiyijie.demo.service.HelloInterface;
public class App {
 public static void main(String[] args) {
  ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("root-context.xml");
  HelloInterface userService = context.getBean(HelloInterface.class);
  userService.sayHello();
  context.close();
 }
}

調(diào)用的是HelloInterface的sayHello方法

HelloInterface.java

package me.laiyijie.demo.service;
public interface HelloInterface{
 
 void sayHello();
 
} 

其實(shí)現(xiàn)類(lèi)為UserServiceImpl.java

UserServiceImpl.java

package me.laiyijie.demo.service;
import org.springframework.stereotype.Service;
@Service
public class UserServiceImpl implements HelloInterface {
 public void sayHello() {
  try {
   Thread.sleep(1000);
  } catch (InterruptedException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
  System.out.println("userHello");
 }
 
} 

誒?情況跟我們看到的代碼有出入?

sayHello 應(yīng)該只輸出 userHello,前后兩行輸出從何出現(xiàn)?

在Main函數(shù)中找不到一點(diǎn)兒線(xiàn)索!

這就是AOP的一個(gè)強(qiáng)大特性:

無(wú)侵入性,不改變?cè)械拇a,卻能增加功能!

那么究竟是如何增加功能的呢?

讓我們看看TimeMonitor.java

TimeMonitor.java

package me.laiyijie.demo.aop;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Service;
@Service
@Aspect
public class TimeMonitor {
 @Around("execution(* me.laiyijie.demo.service.UserServiceImpl.sayHello(..))")
 public void monitorAround(ProceedingJoinPoint pjp) throws Throwable {
  System.out.println("method start time:" + System.currentTimeMillis());
  Object re = pjp.proceed();
  System.out.println("method end time:" + System.currentTimeMillis());
 }
}

終于看到了 method start time:1480223298250 和 method end time:1480223299250這兩行輸出是從哪兒出現(xiàn)的了!

讓我們來(lái)仔細(xì)解讀一下這個(gè)類(lèi)

類(lèi)有兩個(gè)注釋?zhuān)謩e是@Service和@Aspect,第一個(gè)注解是使得TimeMonitor受Spring托管并實(shí)例化。@Aspect就是使得這個(gè)類(lèi)具有AOP功能(你可以這樣理解)兩個(gè)注解缺一不可

類(lèi)里面只有一個(gè)方法,名字叫做monitorAroud,其實(shí)就是為了檢測(cè)函數(shù)執(zhí)行時(shí)間的!

那么關(guān)鍵點(diǎn)來(lái)了,兩個(gè)輸出語(yǔ)句是怎么插入到sayHello方法的前后的呢!

看這個(gè)注解:

@Around("execution(* me.laiyijie.demo.service.UserServiceImpl.sayHello(..))")

@Around表示包圍一個(gè)函數(shù),也就是可以在函數(shù)執(zhí)行前做一些事情,也可以在函數(shù)執(zhí)行后做一些事情

execution(* me.laiyijie.demo.service.UserServiceImpl.sayHello(..)) 

這個(gè)比較好理解,就是使用表達(dá)式的方式指定了要對(duì)哪個(gè)函數(shù)進(jìn)行包圍?。ǔ薳xecution以外還有很多,可以搜索AspectJ語(yǔ)法來(lái)學(xué)習(xí))

也就是說(shuō),這個(gè)注解完整的說(shuō)明了,應(yīng)該在函數(shù)的什么位置插入變化,也就是所謂的切點(diǎn)

之后是函數(shù)的定義:

public Object monitorAround(ProceedingJoinPoint pjp)

這里引入了ProceedingJoinPoint,在使用了@Around之后可以帶入這個(gè)參數(shù),代表的其實(shí)就是sayHello這個(gè)函數(shù),不過(guò)做了一些封裝

而 Object re = pjp.proceed(); 就是相當(dāng)于執(zhí)行了 sayHello方法!

剩下的代碼就不用過(guò)多解釋了,就是在執(zhí)行這個(gè)函數(shù)的前后分別進(jìn)行了系統(tǒng)時(shí)間的獲取。

我們把這個(gè)函數(shù)體,也就是定義了要做那些事情的代碼,稱(chēng)作增強(qiáng)

而包含切點(diǎn)和增強(qiáng)結(jié)合起來(lái)就稱(chēng)作切面

面向切面由此而來(lái)!

Spring AOP 開(kāi)啟需要的配置

需要配置兩項(xiàng)

1、pom.xml增加依賴(lài)(因?yàn)橐玫紸OP還需要不同的JAR包)

2、root-context.xml中增加切面相關(guān)配置

root-context.xml

<?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:context="http://www.springframework.org/schema/context"
 xmlns:aop="http://www.springframework.org/schema/aop"
 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
  http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
  http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
  
 <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
 <context:component-scan base-package="me.laiyijie.demo"></context:component-scan>
</beans>

root-context.xml 增加了兩行

1、xmlns:aop="http://www.springframework.org/schema/aop"

代表加入命名空間

2、<aop:aspectj-autoproxy></aop:aspectj-autoproxy>

使用1中引入的aop命名空間開(kāi)起自動(dòng)代理(自動(dòng)代理具體含義后續(xù)慢慢解釋?zhuān)?jiǎn)單的理解就是AOP的實(shí)現(xiàn)是依靠自動(dòng)代理實(shí)現(xiàn)的)

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 <modelVersion>4.0.0</modelVersion>
 <groupId>me.laiyijie</groupId>
 <artifactId>demo</artifactId>
 <version>0.0.1-SNAPSHOT</version>
 <packaging>jar</packaging>
 <dependencies>
  <!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-context</artifactId>
   <version>4.3.2.RELEASE</version>
  </dependency>
  
  <!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
  <dependency>
   <groupId>org.aspectj</groupId>
   <artifactId>aspectjweaver</artifactId>
   <version>1.8.9</version>
  </dependency>
 </dependencies>
</project>

增加了一個(gè)依賴(lài)

AspectJ 一個(gè)強(qiáng)大的AOP框架,也就是@Aspect和@Around以及ProceedingJoinPoint這些注解和方法的提供者

小結(jié)

增強(qiáng):定義了應(yīng)該怎么把額外的動(dòng)作加入到指定函數(shù)中

切點(diǎn):定義了你應(yīng)該把增強(qiáng)插入到哪個(gè)函數(shù)的什么位置

切面:切點(diǎn)和增強(qiáng)組合起來(lái)的稱(chēng)呼

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教。

相關(guān)文章

  • 23種設(shè)計(jì)模式(6)java裝飾者模式

    23種設(shè)計(jì)模式(6)java裝飾者模式

    這篇文章主要為大家詳細(xì)介紹了23種設(shè)計(jì)模式之java裝飾者模式,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-11-11
  • Intellij?IDEA根據(jù)maven依賴(lài)名查找它是哪個(gè)pom.xml引入的(圖文詳解)

    Intellij?IDEA根據(jù)maven依賴(lài)名查找它是哪個(gè)pom.xml引入的(圖文詳解)

    這篇文章主要介紹了Intellij?IDEA根據(jù)maven依賴(lài)名查找它是哪個(gè)pom.xml引入的,本文通過(guò)圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-08-08
  • Java中的JVM虛擬機(jī)內(nèi)存分配詳解

    Java中的JVM虛擬機(jī)內(nèi)存分配詳解

    這篇文章主要介紹了Java中的JVM虛擬機(jī)內(nèi)存分配詳解,虛擬機(jī)是一種能夠執(zhí)行 Java 字節(jié)碼的虛擬機(jī),它是 Java 語(yǔ)言的核心組成部分,負(fù)責(zé)將 Java 代碼轉(zhuǎn)換為機(jī)器碼并執(zhí)行,JVM 提供了內(nèi)存管理、垃圾回收、線(xiàn)程管理等功能,需要的朋友可以參考下
    2023-10-10
  • Java輸入輸出語(yǔ)句舉例詳解(通俗易懂!)

    Java輸入輸出語(yǔ)句舉例詳解(通俗易懂!)

    這篇文章主要給大家介紹了關(guān)于Java輸入輸出語(yǔ)句的相關(guān)資料,作為一種常用的編程語(yǔ)言,Java提供了多種輸入輸出的方式,用于與用戶(hù)進(jìn)行數(shù)據(jù)交互或處理文件數(shù)據(jù),需要的朋友可以參考下
    2023-10-10
  • JAVAsynchronized原理詳解

    JAVAsynchronized原理詳解

    這篇文章主要介紹了Java中synchronized實(shí)現(xiàn)原理詳解,涉及synchronized實(shí)現(xiàn)同步的基礎(chǔ),Java對(duì)象頭,Monitor,Mark Word,鎖優(yōu)化,自旋鎖等相關(guān)內(nèi)容,具有一定借鑒價(jià)值,需要的朋友可以參考下
    2021-08-08
  • java?線(xiàn)程池存在的意義

    java?線(xiàn)程池存在的意義

    這篇文章主要介紹了java線(xiàn)程池存在的意義,通過(guò)多線(xiàn)程案例模擬鎖的產(chǎn)生的情況展開(kāi)對(duì)主題的詳細(xì)介紹,具有一定的參考價(jià)值,需要的朋友可以參考一下
    2022-06-06
  • Spring框架構(gòu)造注入type屬性實(shí)例詳解

    Spring框架構(gòu)造注入type屬性實(shí)例詳解

    這篇文章主要介紹了Spring框架構(gòu)造注入type屬性實(shí)例詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-12-12
  • 淺談Strut2如何對(duì)請(qǐng)求參數(shù)的封裝

    淺談Strut2如何對(duì)請(qǐng)求參數(shù)的封裝

    這篇文章主要介紹了淺談Strut2如何對(duì)請(qǐng)求參數(shù)的封裝,具有一定借鑒價(jià)值,需要的朋友可以參考下
    2017-12-12
  • Java基礎(chǔ)之Web服務(wù)器與Http詳解

    Java基礎(chǔ)之Web服務(wù)器與Http詳解

    無(wú)論你是前端開(kāi)發(fā)者還是后端開(kāi)發(fā)者,以及測(cè)試工程師,這篇文章的知識(shí)都是你需要弄懂的。讀完這一篇文章,將全面弄懂 HTTP 協(xié)議、TCP 協(xié)議,面試官再也難不倒你相關(guān)知識(shí)
    2021-09-09
  • Java 將一個(gè)字符重復(fù)n遍過(guò)程詳解

    Java 將一個(gè)字符重復(fù)n遍過(guò)程詳解

    這篇文章主要介紹了Java 將一個(gè)字符重復(fù)n遍過(guò)程詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-10-10

最新評(píng)論