指定切面的优先级 在同一个连接点上应用不止一个切面时, 除非明确指定, 否则它们的优先级是不确定的. 切面的优先级可以通过实现 Ordered 接口或利用 @Order 注解指定. 实现 Ordered 接口, getOrder() 方法的返回值越小, 优先级越高. 若使用 @Order 注解, 序号出现在注解中1
2
3
4
5
6
@Aspect
@Order(0)
public class Validate{}
@Aspect
@Order(1)
public class Logging{}
在编写 AspectJ 切面时, 可以直接在通知注解中书写切入点表达式. 但同一个切点表达式可能会在多个通知中重复出现. 在 AspectJ 切面中, 可以通过 @Pointcut
注解将一个切入点声明成简单的方法. 切入点的方法体通常是空的 , 因为将切入点定义与应用程序逻辑混在一起是不合理的. 切入点方法的访问控制符同时也控制着这个切入点的可见性. 如果切入点要在多个切面中共用, 最好将它们集中在一个公共的类中. 在这种情况下, 它们必须被声明为 public. 在引入这个切入点时, 必须将类名也包括在内. 如果类没有与这个切面放在同一个包中, 还必须包含包名. 其他通知可以通过方法名称引入该切入点.
用基于 XML 的配置声明切面
除了使用 AspectJ 注解声明切面, Spring 也支持在 Bean 配置文件中声明切面. 这种声明是通过 aop schema 中的 XML 元素完成的. 正常情况下, 基于注解的声明要优先于基于 XML 的声明 . 通过 AspectJ 注解, 切面可以与 AspectJ 兼容, 而基于 XML 的配置则是 Spring 专有的. 由于 AspectJ 得到越来越多的 AOP 框架支持, 所以以注解风格编写的切面将会有更多重用的机会.
基于 XML —- 声明切面 当使用 XML 声明切面时, 需要在 <beans>
根元素中导入 aop Schema 在 Bean 配置文件中, 所有的 Spring AOP 配置都必须定义在 <aop:config>
元素内部. 对于每个切面而言, 都要创建一个 <aop:aspect>
元素来为具体的切面实现引用后端 Bean 实例. 切面 Bean 必须有一个标示符, 供 <aop:aspect>
元素引用
基于 XML —- 声明切入点 切入点使用 <aop:pointcut>
元素声明 切入点必须定义在 <aop:aspect>
元素下, 或者直接定义在 <aop:config>
元素下. 定义在 <aop:aspect>
元素下: 只对当前切面有效 定义在 <aop:config>
元素下: 对所有切面都有效 基于 XML 的 AOP 配置不允许在切入点表达式中用名称引用其他切入点.
基于 XML —- 声明通知 在 aop Schema 中, 每种通知类型都对应一个特定的 XML 元素. 通知元素需要使用 <pointcut-ref>
来引用切入点, 或用 <pointcut>
直接嵌入切入点表达式. method 属性指定切面类中通知方法的名称.
示例: Arithmetic.java:1
2
3
4
5
6
public interface Arithmetic {
public int add(int i, int j);
public int sub(int i, int j);
public int mul(int i, int j);
public int div(int i, int j);
}
ArithmeticImpl.java:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class ArithmeticImpl implements Arithmetic {
@Override
public int add(int i, int j) {
// TODO Auto-generated method stub
int result = i + j;
return result;
}
@Override
public int sub(int i, int j) {
// TODO Auto-generated method stub
int result = i - j;
return result;
}
@Override
public int mul(int i, int j) {
// TODO Auto-generated method stub
int result = i * j;
return result;
}
@Override
public int div(int i, int j) {
// TODO Auto-generated method stub
int result = i / j;
return result;
}
}
Validate.java:1
2
3
4
5
public class Validate {
public void validate(JoinPoint joinPoint){
System.out.println("-->validate: " + Arrays.asList(joinPoint.getArgs()));
}
}
LoggingAspect.java:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public class LoggingAspect {
public void beforeMethod(JoinPoint joinPoint) {
String methodName = joinPoint.getSignature().getName();
Object [] args = joinPoint.getArgs();
System.out.println("The method " + methodName + "begins with" + Arrays.asList(args));
}
public void afterMethod(JoinPoint joinPoint) {
String methodName = joinPoint.getSignature().getName();
System.out.println("The method " + methodName + "ends");
}
public void afterReturning(JoinPoint joinPoint, Object result) {
String methodName = joinPoint.getSignature().getName();
System.out.println("The method " + methodName + "begins with" + result);
}
public Object aroundMethod(ProceedingJoinPoint pjd) {
Object result = null;
String methodName = pjd.getSignature().getName();
try{
//前置通知
System.out.println("The method " + methodName + "begins with" + Arrays.asList(pjd.getArgs()));
//执行目标方法
result = pjd.proceed();
//返回通知
System.out.println("The method " + methodName + "ends with" + result);
} catch(Throwable e) {
System.out.println("The method " + methodName + "occurs exception" + e);
throw new RuntimeException();
}
//后置通知
System.out.println("The method " + methodName + "ends");
return result;
}
}
Main.java:1
2
3
4
5
6
7
8
9
10
11
public class Main {
public static void main(String[] args) {
// 1.获取IOC容器
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext-xml.xml");
// 2.从IOC获取bean实例
Arithmetic arithmetic = (Arithmetic) ctx.getBean("arithmetic");
// 3.使用bean
int result = arithmetic.add(1, 2);
System.out.println("result: "+result);
}
}
applicationContext-xml.xml:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<!-- 配置bean -->
<bean id="arithmetic" class="com.aop_xml.ArithmeticImpl"></bean>
<!-- 配置切面的bean -->
<bean id="loggingAspect" class="com.aop_xml.LoggingAspect"></bean>
<bean id="validate" class="com.aop_xml.Validate"></bean>
<!-- 配置AOP -->
<aop:config>
<!-- 配置切点表达式 -->
<aop:pointcut expression="execution(* com.aop_xml.Arithmetic.*(int, int))" id="pointcut"/>
<!-- 配置切面通知 -->
<aop:aspect ref="loggingAspect" order="2">
<!--
<aop:before method="beforeMethod" pointcut-ref="pointcut" />
<aop:after method="afterMethod" pointcut-ref="pointcut" />
<aop:after-returning method="afterReturning" pointcut-ref="pointcut" returning="result" />
-->
<aop:around method="aroundMethod" pointcut-ref="pointcut"/>
</aop:aspect>
<aop:aspect ref="validate" order="1">
<aop:before method="validate" pointcut-ref="pointcut" />
</aop:aspect>
</aop:config>