必備技能:spring aop 切入點表達式,你都會麼?

本文主要介紹spring aop中9種切入點表達式的寫法java

  • execute
  • within
  • this
  • target
  • args
  • @target
  • @within
  • @annotation
  • @args

一、execute表達式

攔截任意公共方法spring

execution(public * *(..))
複製代碼

攔截以set開頭的任意方法apache

execution(* set*(..))
複製代碼

攔截類或者接口中的方法bash

execution(* com.xyz.service.AccountService.*(..))
複製代碼

攔截AccountService(類、接口)中定義的全部方法maven

攔截包中定義的方法,不包含子包中的方法ide

execution(* com.xyz.service.*.*(..))
複製代碼

攔截com.xyz.service包中全部類中任意方法,不包含子包中的類spring-boot

攔截包或者子包中定義的方法測試

execution(* com.xyz.service..*.*(..))
複製代碼

攔截com.xyz.service包或者子包中定義的全部方法ui

二、within表達式

表達式格式:包名.* 或者 包名..*this

攔截包中任意方法,不包含子包中的方法

within(com.xyz.service.*)
複製代碼

攔截service包中任意類的任意方法

攔截包或者子包中定義的方法

within(com.xyz.service..*)
複製代碼

攔截service包及子包中任意類的任意方法

三、this表達式

代理對象爲指定的類型會被攔截

目標對象使用aop以後生成的代理對象必須是指定的類型纔會被攔截,注意是目標對象被代理以後生成的代理對象和指定的類型匹配纔會被攔截

this(com.xyz.service.AccountService)
複製代碼

示例 this表達式的使用,可能不是很好理解,用示例說明一下:

<?xml version="1.0" encoding="UTF-8"?>
<projectxmlns="http://maven.apache.org/POM/4.0." xmlns:xsi="http://www.w3.org/2001/XMLSchemainsance"
   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>   
   <parent>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-parent</artifactId>
      <version>2.1.4.RELEASE</version>
      <relativePath/> <!-- lookup parent from repository -->
   </parent>   
   <groupId>com.ms</groupId>   
   <artifactId>spring-aop-demo   </artifactId>
   <version>0.0.1-SNAPSHOT</version>
   <name>spring-aop-demo</name>
   <description>Demo project for Spring Boot</description>

   <properties>
      <java.version>1.8</java.version>
   </properties>

   <dependencies>
      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-aop</artifactId>
      </dependency>
      <dependency>
         <groupId>org.projectlombok</groupId>
         <artifactId>lombok</artifactId>
      </dependency>
      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-test</artifactId>
         <scope>test</scope>
      </dependency>
   </dependencies>

   <build>
      <plugins>
         <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
         </plugin>
      </plugins>
   </build>
</project>
複製代碼
package com.ms.aop.jthis.demo1;

public interface IService {
    void m1();
}
複製代碼
package com.ms.aop.jthis.demo1;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

@Slf4j
@Component
public class ServiceImpl implements IService {
    @Override
    public void m1() {
        log.info("切入點this測試!");
    }
}
複製代碼
package com.ms.aop.jthis.demo1;

import lombok.extern.slf4j.Slf4j;
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.springframework.stereotype.Component;
@Aspect
@Component
@Slf4j
public class Interceptor1 {

    @Pointcut("this(com.ms.aop.jthis.demo1.ServiceImpl)")
    public void pointcut() {
    }

    @Around("pointcut()")
    public Object invoke(ProceedingJoinPoint invocation) throws Throwable {
        log.info("方法執行以前");
        Object result = invocation.proceed();
        log.info("方法執行完畢");
        return result;
    }
}
複製代碼
package com.ms.aop.jthis.demo1;

import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@ComponentScan(basePackageClasses = {Client.class})
@EnableAspectJAutoProxy
@Slf4j
public class Client {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(Client.class);
        IService service = annotationConfigApplicationContext.getBean(IService.class);
        service.m1();
        log.info("{}", service instanceof ServiceImpl);
    }
}
複製代碼

執行結果

10:27:12.277 [main] INFO com.ms.aop.jthis.demo1.ServiceImpl - 切入點this測試!
10:27:12.277 [main] INFO com.ms.aop.jthis.demo1.Client - false
複製代碼
  1. @EnableAspectJAutoProxy:表示若spring建立的對象若是實現了接口,默認使用jdk動態代理,若是沒有實現接口,使用cglib建立代理對象

  2. 因此 service 是使用jdk動態代理生成的對象,service instanceof ServiceImplfalse

  3. @Pointcut("this(com.ms.aop.jthis.demo1.ServiceImpl)")表示被spring代理以後生成的對象必須爲com.ms.aop.jthis.demo1.ServiceImpl纔會被攔截,可是service不是ServiceImpl類型的對象了,因此不會被攔截

  4. 修改代碼**@EnableAspectJAutoProxy(proxyTargetClass=true)**,使用cglib來生成代理對象

執行結果:

10:34:50.736[main]INFO com.ms.aop.jthis.demo1.Interceptor1-方法執行以前

10:34:50.755[main]INFO com.ms.aop.jthis.demo1.ServiceImpl-切入點this測試!

10:34:50.756[main]INFO com.ms.aop.jthis.demo1.Interceptor1-方法執行完畢

10:34:50.756[main]INFO com.ms.aop.jthis.demo1.Client-true
複製代碼

service 爲 ServiceImpl類型的對象,因此會被攔截

四、target表達式

目標對象爲指定的類型被攔截

target(com.xyz.service.AccountService)
複製代碼

目標對象爲AccountService類型的會被代理

示例

package com.ms.aop.target;

public interface IService {
    void m1();}
複製代碼
package com.ms.aop.target;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

@Slf4j
@Component
public class ServiceImpl implements IService {
    @Override
    public void m1() {
        log.info("切入點target測試!");
    }
}
複製代碼
package com.ms.aop.target;

import lombok.extern.slf4j.Slf4j;
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.springframework.stereotype.Component;

@Aspect
@Component
@Slf4j
public class Interceptor1 {

    @Pointcut("target(com.ms.aop.target.ServiceImpl)")
    public void pointcut() {
    }

    @Around("pointcut()")
    public Object invoke(ProceedingJoinPoint invocation) throws Throwable {
        log.info("方法執行以前");
        Object result = invocation.proceed();
        log.info("方法執行完畢");
        return result;
    }
}
複製代碼
package com.ms.aop.target;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@ComponentScan(basePackageClasses = {Client.class})
@EnableAspectJAutoProxy
public class Client {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(Client.class);
        IService service = annotationConfigApplicationContext.getBean(IService.class);
        service.m1();
    }
}
複製代碼

執行結果:

10:49:01.674 [main] INFO com.ms.aop.targetInterceptor1 - 方法執行以前
10:49:01.674 [main] INFO com.ms.aop.target.ServiceImpl - 切入點target測試!
10:49:01.674 [main] INFO com.ms.aop.target.Interceptor1 - 方法執行完畢
複製代碼

this 和 target 的不一樣點

  1. this做用於代理對象,target做用於目標對象
  2. this表示目標對象被代理以後生成的代理對象和指定的類型匹配會被攔截,匹配的是代理對象
  3. target表示目標對象和指定的類型匹配會被攔截,匹配的是目標對象

五、args 表達式

匹配方法中的參數

@Pointcut("args(com.ms.aop.args.demo1.UserModel)")
複製代碼

匹配只有一個參數,且類型爲com.ms.aop.args.demo1.UserModel

匹配多個參數

args(type1,type2,typeN)
複製代碼

匹配任意多個參數

@Pointcut("args(com.ms.aop.args.demo1.UserModel,..)")
複製代碼

匹配第一個參數類型爲com.ms.aop.args.demo1.UserModel的全部方法, .. 表示任意個參數

六、@target表達式

匹配的目標對象的類有一個指定的註解

@target(com.ms.aop.jtarget.Annotation1)
複製代碼

目標對象中包含com.ms.aop.jtarget.Annotation1註解,調用該目標對象的任意方法都會被攔截

七、@within表達式

指定匹配必須包含某個註解的

@within(com.ms.aop.jwithin.Annotation1)
複製代碼

聲明有com.ms.aop.jwithin.Annotation1註解的類中的全部方法都會被攔截

@target 和 @within 的不一樣點
  1. @target(註解A):判斷被調用的目標對象中是否聲明瞭註解A,若是有,會被攔截

  2. @within(註解A): 判斷被調用的方法所屬的類中是否聲明瞭註解A,若是有,會被攔截

@target關注的是被調用的對象,@within關注的是調用的方法所在的類

八、@annotation表達式

匹配有指定註解的方法(註解做用在方法上面)

@annotation(com.ms.aop.jannotation.demo2.Annotation1)
複製代碼

被調用的方法包含指定的註解

九、@args表達式

方法參數所屬的類型上有指定的註解,被匹配

注意:是方法參數所屬的類型上有指定的註解,不是方法參數中有註解

  • 匹配1個參數,且第1個參數所屬的類中有Anno1註解
@args(com.ms.aop.jargs.demo1.Anno1)
複製代碼
  • 匹配多個參數,且多個參數所屬的類型上都有指定的註解
@args(com.ms.aop.jargs.demo1.Anno1,com.ms.aop.jargs.demo1.Anno2)
複製代碼
  • 匹配多個參數,且第一個參數所屬的類中有Anno1註解
@args(com.ms.aop.jargs.demo2.Anno1,..)
複製代碼
相關文章
相關標籤/搜索