天天看點

五分鐘入門SpringAOP

SpringAOP的使用

SpringAOP、過濾器、攔截器之間的差別

  • 過濾器:攔截web通路url位址,在攔截器之前,對所有的請求起作用。基于函數回調且依賴于servlet容器。
  • 攔截器:攔截web通路url位址,隻對controller起作用。基于java的反射機制,使用代理模式。
  • AOP:針對代碼的方法級别做攔截。
  • 應用場景:一般情況下請求都需要經過登入校驗,首先應該考慮到使用過濾器在最頂層最校驗。涉及到日志記錄,且要在業務邏輯完成前後做日志記錄的時候,可以考慮攔截器,但是攔截器是根據url進行比對,則不夠細緻,這次就考慮使用aop來實作,他是根據方法級别做攔截,很适合做日志記錄。

AOP術語

  • 連接配接點(Joinpoint):spring允許你通知的位置,指方法的前或後等。
  • 切點:(PointCut):例如一個方法有十幾個類,則連接配接點就有十幾個,但是我隻想對某些類進行通知,則就需要通過切點來篩選連接配接點。
@Pointcut("execution(* cn.text.controller..*.*(..))")
execution(): 表達式主體
第一個* 号位置:表示傳回類型,*表示所有的類型
cn.text.controller:表示需要攔截的包名
包名後的點:第一個.表示目前包,第二個點表示目前包的子包
第二個*号位置:表示類名,*号表示所有的類
*(..):*表示所有方法,括号裡的點表示參數,兩個點表示所有參數。
           
  • 通知(Advice):指在連接配接點上需要的功能。

    前置通知(@Before):在執行連接配接點代碼前做的操作。

    後置通知(@After):在執行連接配接點代碼後做的操作。

    異常通知(@AfterThrowing):在執行連接配接點代碼出現異常後做的操作。

    傳回通知(@AfterReturning):在執行連接配接點代碼後無異常後做的操作。

    環繞通知(@Around):可以在執行連接配接點代碼前後完成自定義的行為。它也會選擇是否繼續執行連接配接點或直接傳回它們自己的傳回值或抛出異常來結束執行。

  • 目标對象(Target):需要被通知的業務對象。
  • 織入(Weaving):将切面内容融入到目标對象來建立新的代理對象的過程。
  • 切面(Aspect):是通知和切入點的結合。
  • 代理(Proxy):AOP架構建立的對象,用于實作切面契約(通知方法執行等功能)。

配置

首先在applicationContext.xml中配置

proxy-target-class屬性值決定是基于接口的還是基于類的代理被建立。如果proxy-target-class 屬性值被設定為true,那麼基于類的代理将起作用(這時需要cglib庫)。如果proxy-target-class屬值被設定為false或者這個屬性被省略,那麼标準的JDK 基于接口的代理将起作用。如果目标類沒有生命接口,則Spring将自動使用CGLib動态代理。(故proxy-target-class可省略)

<aop:aspectj-autoproxy proxy-target-class="true"/>//啟動對@Aspectj的自動代理的支援
<context:component-scan base-package="cn.text.aspect" />//IOC自動掃包
           

依賴檔案

<!-- Spring AOP -->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
            <version>1.8.10</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.8.10</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>4.3.9.RELEASE</version>
        </dependency>
           

JoinPoint和ProceedingJoinPoint差別

AspectJ使用org.aspectj.lang.JoinPoint接口表示目标類連接配接點對象,如果是環繞通知時,使用org.aspectj.lang.ProceedingJoinPoint表示連接配接點對象,該類是JoinPoint的子接口。

1)JoinPoint

java.lang.Object[] getArgs():擷取連接配接點方法運作時的入參清單;

Signature getSignature() :擷取連接配接點的方法簽名對象;

java.lang.Object getTarget() :擷取連接配接點所在的目标對象;

java.lang.Object getThis() :擷取代理對象本身;

2)ProceedingJoinPoint

ProceedingJoinPoint繼承JoinPoint子接口,它新增了兩個用于執行連接配接點方法的方法:

java.lang.Object proceed() throws java.lang.Throwable:通過反射執行目标對象的連接配接點處的方法;

java.lang.Object proceed(java.lang.Object[] args) throws java.lang.Throwable:通過反射執行目标對象連接配接點處的方法,不過使用新的入參替換原來的入參。

執行個體

@Aspect//把目前類辨別為一個切面供容器讀取
@Component//把切面類注入到IOC容器中
@Slf4j
public class LogAspect {
    @Pointcut("execution(* cn.text.service..*(..))")
    public void pointCutService(){ }
    @Before("pointCutService()")
    public void ServiceBefore(JoinPoint joinPoint) {
        ServletRequestAttributes requestAttributes =
         (ServletRequestAttributes) RequestContextHolder
                .getRequestAttributes();
        HttpServletRequest request = requestAttributes.getRequest();
        log.info("===============請求内容===============");
        log.info("請求位址:" + request.getRequestURL().toString());
        log.info("請求方式:" + request.getMethod());
        log.info("請求類方法:" + joinPoint.getSignature());
        log.info("請求類方法參數:" + Arrays.toString(joinPoint.getArgs()));
        log.info("===============請求内容===============");
    }
}
           

繼續閱讀