目录
概念解释
切点(Pointcut):在Spring AOP(面向切面编程)中,切点用于定义在哪些连接点(Join Point)上应用通知(Advice)。连接点是程序执行过程中的一个特定点,例如方法的执行、异常的抛出等。
切点表达式:切点表达式是一种用于匹配连接点的表达式语言。Spring AOP使用AspectJ的切点表达式语言来定义切点。
切点表达式的语法
Spring AOP支持多种切点表达式,常用的有:
- execution:用于匹配方法执行的连接点。
- within:用于匹配特定类型内的所有方法执行。
- @annotation:用于匹配带有特定注解的方法。
- args:用于匹配方法参数。
1. execution表达式
execution
是最常用的切点表达式,用于匹配方法执行的连接点。其基本语法如下:
execution(modifiers-pattern? ret-type-pattern declaring-type-pattern?name-pattern(param-pattern) throws-pattern?)
modifiers-pattern
:方法的修饰符(可选)。ret-type-pattern
:返回类型。declaring-type-pattern
:方法所在的类(可选)。name-pattern
:方法名。param-pattern
:参数类型。throws-pattern
:异常类型(可选)。
切点表达式的语法规则:
- 方法的访问修饰符可以省略
- 返回值可以使用
*
号代替(任意返回值类型) - 包名可以使用
*
号代替,代表任意包(一层包使用一个*
) - 使用
..
配置包名,标识此包以及此包下的所有子包 - 类名可以使用
*
号代替,标识任意类 - 方法名可以使用
*
号代替,表示任意方法 - 可以使用
*
配置参数,一个任意类型的参数 - 可以使用
..
配置参数,任意个任意类型的参数 - 可以使用 且(&&)、或(||)、非(!) 来组合比较复杂的切点表达式。
示例:
@Pointcut("execution(* com.example.service.*.*(..))")
private void anyServiceMethod() {}
这个表达式匹配com.example.service
包下的所有类的所有方法。
2. within表达式
within
用于匹配特定类型内的所有方法执行。其基本语法如下:
within(declaring-type-pattern)
示例:
@Pointcut("within(com.example.service.*)")
private void anyServiceMethod() {}
这个表达式匹配com.example.service
包下的所有类的所有方法。
3. @annotation表达式
@annotation
用于匹配带有特定注解的方法。其基本语法如下:
@annotation(annotation-type)
示例:
@Pointcut("@annotation(com.example.annotation.Loggable)")
private void loggableMethods() {}
这个表达式匹配所有带有@Loggable
注解的方法。
4. args表达式
args
用于匹配方法参数。其基本语法如下:
args(param-pattern)
示例:
@Pointcut("args(java.lang.String)")
private void methodWithStringArg() {}
这个表达式匹配所有带有一个String
类型参数的方法。
编程示例
下面是一个完整的Spring Boot项目示例,展示了如何使用切点表达式。
1. 创建Spring Boot项目
首先,创建一个Spring Boot项目,并添加必要的依赖(如Spring AOP)。
2. 定义服务类
package com.example.service;
import org.springframework.stereotype.Service;
@Service
public class MyService {
public void doSomething() {
System.out.println("Doing something...");
}
public void doSomethingWithArg(String arg) {
System.out.println("Doing something with arg: " + arg);
}
}
3. 定义切面类
package com.example.aspect;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class LoggingAspect {
@Pointcut("execution(* com.example.service.*.*(..))")
private void anyServiceMethod() {}
@Before("anyServiceMethod()")
public void logBefore() {
System.out.println("Before executing service method");
}
}
4. 配置Spring Boot应用
在application.properties
中添加必要的配置,或者在主类上添加@EnableAspectJAutoProxy
注解。
package com.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
@SpringBootApplication
@EnableAspectJAutoProxy
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
5. 测试
创建一个测试类来测试切面是否生效。
package com.example;
import com.example.service.MyService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
@Component
public class TestRunner implements CommandLineRunner {
@Autowired
private MyService myService;
@Override
public void run(String... args) throws Exception {
myService.doSomething();
myService.doSomethingWithArg("test");
}
}
运行项目,你应该会看到如下输出:
Before executing service method
Doing something...
Before executing service method
Doing something with arg: test
这表明切面成功地在服务方法执行前插入了日志。
总结
通过以上讲解和示例,你应该对Spring Boot中的切点表达式有了更深入的理解。切点表达式是Spring AOP的核心,掌握它们可以帮助你更灵活地实现面向切面编程。