Spring AOP 已经集成了 AspectJ,使用AspectJ实现时,不需要让自定义的通知类实现特定接口,需要在配置<aop:config>
标签的时候使用<aop:aspect>
标签配置切面,引用通知提供类。
我们先自定义一个定义了所需的通知方法的通知提供类。
package com.test.advice;
import org.aspectj.lang.ProceedingJoinPoint;
public class MyAdvice {
public void myBeforeAdvice() {
System.out.println("aspect before advice");
}
public void myAfterAdvice() {
System.out.println("aspect after advice");
}
public void myAfterReturningAdvice() {
System.out.println("aspect after returning advice");
}
public void myThrowsAdvice() {
System.out.println("aspect throws advice");
}
public void myArroundAdvice(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("aspect arround advice - before");
proceedingJoinPoint.proceed();
System.out.println("aspect arround advice - after");
}
}
需要注意的是,在环绕通知方法中,需要一个ProceedingJoinPoint类型的形参,在执行完环绕前置通知之后执行proceedingJoinPoint.proceed()方法让目标方法执行,然后才会执行环绕后置通知。简单理解,环绕通知=前置+目标方法执行+后置通知,proceed方法就是用于启动目标方法执行的。
然后再配置applicationContext.xml。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="demo" class="com.test.Demo"></bean>
<bean id="myAdvice" class="com.test.advice.MyAdvice"></bean>
<aop:config>
<aop:aspect ref="myAdvice">
<aop:pointcut expression="execution(* com.test.Demo.function2())"
id="mypointcut1" />
<aop:before method="myBeforeAdvice" pointcut-ref="mypointcut1"/>
<aop:after method="myAfterAdvice" pointcut-ref="mypointcut1"/>
<aop:after-returning method="myAfterReturningAdvice" pointcut-ref="mypointcut1"/>
<aop:after-throwing method="myThrowsAdvice" pointcut-ref="mypointcut1"/>
<aop:around method="myArroundAdvice" pointcut-ref="mypointcut1"/>
</aop:aspect>
</aop:config>
</beans>
被代理的Demo类如下。
package com.test;
public class Demo {
public void function1() {
System.out.println("Demo function1");
}
public void function2() {
System.out.println("Demo function2");
}
public void function3() {
System.out.println("Demo function3");
}
}
测试类。
package com.test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
public static void main(String[] args) {
// TODO Auto-generated method stub
@SuppressWarnings("resource")
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
Demo demo = ac.getBean("demo",Demo.class);
demo.function1();
demo.function2();
demo.function3();
}
}
执行结果如下:
需要注意的是,通知方法的执行顺序与<aop:aspec>
中配置的顺序有关。
使用注解实现
我们可以使用注解的方式替换掉在applicationContext.xml中配置<aop:config>
标签。
在通知方法提供类上使用@Aspect注解声明,通知方法使用各自的注解,并配置切点的路径。
package com.test.advice;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class MyAdvice {
@Before("com.test.Demo.function2()")
public void myBeforeAdvice() {
System.out.println("aspect before advice");
}
@After("com.test.Demo.function2()")
public void myAfterAdvice() {
System.out.println("aspect after advice");
}
@AfterReturning("com.test.Demo.function2()")
public void myAfterReturningAdvice() {
System.out.println("aspect after returning advice");
}
@AfterThrowing("com.test.Demo.function2()")
public void myThrowsAdvice() {
System.out.println("aspect throws advice");
}
@Around("com.test.Demo.function2()")
public void myArroundAdvice(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("aspect arround advice - before");
proceedingJoinPoint.proceed();
System.out.println("aspect arround advice - after");
}
}
在切点处使用@Pointcut注解,配置切点表达式。
package com.test;
import org.aspectj.lang.annotation.Pointcut;
public class Demo {
public void function1() {
System.out.println("Demo function1");
}
@Pointcut("execution(* com.test.Demo.function2())")
public void function2() {
System.out.println("Demo function2");
}
public void function3() {
System.out.println("Demo function3");
}
}
在applicationContext.xml中配置相关的bean和标签<aop:aspectj-autoproxy/>
开启aspectj注解支持。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="demo" class="com.test.Demo"></bean>
<bean id="myAdvice" class="com.test.advice.MyAdvice"></bean>
<aop:aspectj-autoproxy/>
</beans>
测试类中:
package com.test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
public static void main(String[] args) {
// TODO Auto-generated method stub
@SuppressWarnings("resource")
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
Demo demo = ac.getBean("demo",Demo.class);
demo.function1();
demo.function2();
demo.function3();
}
}
执行结果: