以下是Spring Boot中对同一接口定义多个切面的示例,分别通过接口方式和注解方式实现切面排序,并对比差异:
一、接口方式实现切面排序
1. 定义接口
// 服务接口
public interface MyService {
void methodA();
void methodB();
}
// 接口实现类
@Service
class MyServiceImpl implements MyService {
@Override
public void methodA() {
System.out.println("Executing methodA");
}
@Override
public void methodB() {
System.out.println("Executing methodB");
}
}
2. 定义切面(实现 Ordered
接口)
// 切面A:优先级高(Order=1)
@Component
@Aspect
public class AspectA implements Ordered {
@Override
public int getOrder() {
return 1; // 数值越小,优先级越高
}
@Before("execution(* com.example..MyService.*(..))")
public void beforeA() {
System.out.println("AspectA before advice");
}
}
// 切面B:优先级低(Order=2)
@Component
@Aspect
public class AspectB implements Ordered {
@Override
public int getOrder() {
return 2;
}
@Before("execution(* com.example..MyService.*(..))")
public void beforeB() {
System.out.println("AspectB before advice");
}
}
3. 测试类
@RunWith(SpringRunner.class)
@SpringBootTest
public class TestAspect {
@Autowired
private MyService myService;
@Test
public void testOrder() {
myService.methodA();
// 输出顺序:AspectA before -> AspectB before -> methodA
}
}
二、注解方式实现切面排序
1. 定义切面(使用 @Order
注解)
// 切面C:优先级高(Order=1)
@Component
@Aspect
@Order(1)
public class AspectC {
@Before("execution(* com.example..MyService.*(..))")
public void beforeC() {
System.out.println("AspectC before advice");
}
}
// 切面D:优先级低(Order=2)
@Component
@Aspect
@Order(2)
public class AspectD {
@Before("execution(* com.example..MyService.*(..))")
public void beforeD() {
System.out.println("AspectD before advice");
}
}
2. 测试类
@RunWith(SpringRunner.class)
@SpringBootTest
public class TestAspect {
@Autowired
private MyService myService;
@Test
public void testAnnotationOrder() {
myService.methodB();
// 输出顺序:AspectC before -> AspectD before -> methodB
}
}
三、两种方式的对比表格
特性 | 接口方式(Ordered ) | 注解方式(@Order ) |
---|---|---|
实现方式 | 实现 Ordered 接口,重写 getOrder() 方法 | 在切面类上添加 @Order(int value) 注解 |
优先级规则 | 数值越小,优先级越高 | 数值越小,优先级越高 |
适用场景 | 传统方式,需继承接口 | 推荐方式,更简洁 |
局限性 | 需要额外实现接口 | 无额外继承要求 |
Spring 内部处理 | 通过 OrderComparator 比较 | 直接解析 @Order 注解 |
四、关键点总结
-
切面执行顺序:
- 两者均通过数值控制优先级,
Order=1
的切面比Order=2
的切面先执行。 - 若未指定顺序,Spring 默认按声明顺序加载,但结果不可靠,建议显式设置。
- 两者均通过数值控制优先级,
-
推荐实践:
- 优先使用注解方式(
@Order
),代码更简洁且符合 Spring 的注解驱动风格。 - 若需复用排序逻辑,可结合
Ordered
接口实现通用排序策略。
- 优先使用注解方式(