本文主要介紹spring aop中9種切入點表達式的寫法java
攔截任意公共方法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
表達式格式:包名.* 或者 包名..*this
攔截包中任意方法,不包含子包中的方法
within(com.xyz.service.*)
複製代碼
攔截service包中任意類的任意方法
攔截包或者子包中定義的方法
within(com.xyz.service..*)
複製代碼
攔截service包及子包中任意類的任意方法
代理對象爲指定的類型會被攔截
目標對象使用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
複製代碼
@EnableAspectJAutoProxy:表示若spring建立的對象若是實現了接口,默認使用jdk動態代理,若是沒有實現接口,使用cglib建立代理對象
因此 service 是使用jdk動態代理生成的對象,service instanceof ServiceImpl 爲 false
@Pointcut("this(com.ms.aop.jthis.demo1.ServiceImpl)")表示被spring代理以後生成的對象必須爲com.ms.aop.jthis.demo1.ServiceImpl纔會被攔截,可是service不是ServiceImpl類型的對象了,因此不會被攔截
修改代碼**@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(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 的不一樣點
匹配方法中的參數
@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(com.ms.aop.jtarget.Annotation1)
複製代碼
目標對象中包含com.ms.aop.jtarget.Annotation1註解,調用該目標對象的任意方法都會被攔截
指定匹配必須包含某個註解的
@within(com.ms.aop.jwithin.Annotation1)
複製代碼
聲明有com.ms.aop.jwithin.Annotation1註解的類中的全部方法都會被攔截
@target(註解A):判斷被調用的目標對象中是否聲明瞭註解A,若是有,會被攔截
@within(註解A): 判斷被調用的方法所屬的類中是否聲明瞭註解A,若是有,會被攔截
@target關注的是被調用的對象,@within關注的是調用的方法所在的類
匹配有指定註解的方法(註解做用在方法上面)
@annotation(com.ms.aop.jannotation.demo2.Annotation1)
複製代碼
被調用的方法包含指定的註解
方法參數所屬的類型上有指定的註解,被匹配
注意:是方法參數所屬的類型上有指定的註解,不是方法參數中有註解
@args(com.ms.aop.jargs.demo1.Anno1)
複製代碼
@args(com.ms.aop.jargs.demo1.Anno1,com.ms.aop.jargs.demo1.Anno2)
複製代碼
@args(com.ms.aop.jargs.demo2.Anno1,..)
複製代碼