一、本文摘要
- 实现AOP的方式采用Spring+Aspectj+Maven+XML配置;
- 介绍五种通知方式:前置通知、后置通知、环绕通知、异常通知、异常后置通知;
二、在POM中引入依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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>
<groupId>com.yale</groupId>
<artifactId>spring-aop</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<spring.version>4.2.8.RELEASE</spring.version>
</properties>
<dependencies>
<!-- spring core -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- spring test -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.2</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
三、创建一个接口和实现类
package com.yale.service;
public interface StudentService {
void insert(String name);
void delete(int id);
void update(int id, String name);
void select(String name);
}
package com.yale.service;
public class StudentServiceImpl implements StudentService {
public void insert(String name) {
System.out.println("插入数据:" + name);
}
public void delete(int id) {
System.out.println("删除数据:" + id);
}
public void update(int id, String name) {
System.out.println("更新数据:" + name);
}
public void select(String name) {
System.out.println("查询数据:" + name);
}
}
四、创建一个通知类
package com.yale.advice;
import org.aspectj.lang.ProceedingJoinPoint;
public class MyAdvice {
//前置通知
public void before(){
System.out.println("前置通知");
}
//后置通知,无论是否出现异常都会调用
public void after(){
System.out.println("后置通知,无论是否出现异常都会调用");
}
//后置通知,出现异常不调用
public void afterReturning(){
System.out.println("后置通知,出现异常不调用");
}
//异常通知
public void afterException(){
System.out.println("异常通知");
}
//环绕通知
public Object around(ProceedingJoinPoint point) throws Throwable{
System.out.println("环绕通知前置");
Object object = point.proceed();
System.out.println("环绕通知后置");
return object;
}
}
五、创建一个spring配置文件:spring-aop.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="studentService" class="com.yale.service.StudentServiceImpl" />
<!-- 通知对象 -->
<bean id="myAdvice" class="com.yale.advice.MyAdvice" />
<!-- 将通知对象织入目标对象 -->
<aop:config>
<aop:pointcut id="pointcut" expression="execution(* com.yale.service..*.*(..))" />
<aop:aspect ref="myAdvice">
<aop:before method="before" pointcut-ref="pointcut" />
</aop:aspect>
</aop:config>
</beans>
六、创建一个测试类
package com.yale.advice;
import com.yale.service.StudentService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import javax.annotation.Resource;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:spring-aop.xml")
public class MyAdviceTest {
@Resource
private StudentService studentService;
@Test
public void test(){
studentService.insert("tom");
}
}
1.测试前置通知 myAdvice.before()
直接运行上面的test()方法,返回结果如下:
前置通知
插入数据:tom
ok, 在studentService.insert()方法前成功调用了myAdvice.before()方法。
2.测试后置通知 myAdvice.after()
修改 StudentServiceImpl 中 delete(int id) 方法
public void delete(int id) {
System.out.println("删除数据:" + id);
throw new ArithmeticException("arithmeticException");
}
修改 spring-aop.xml 中的 aop:aspect
<aop:aspect ref="myAdvice">
<!--<aop:before method="before" pointcut-ref="pointcut" />-->
<aop:after method="after" pointcut-ref="pointcut" />
</aop:aspect>
在 MyAdviceTest 中添加 test2()
@Test
public void test2(){
try {
studentService.delete(1);
}catch (ArithmeticException e){
System.out.println(e.getMessage());
}
}
运行 test2() 方法后,返回结果如下:
删除数据:1
后置通知,无论是否出现异常都会调用
arithmeticException
ok, 尽管有异常,还是调用了myAdvice.after()方法。
3.测试异常后置通知 myAdvice.afterReturning()
修改 spring-aop.xml 中的 aop:aspect
<aop:aspect ref="myAdvice">
<!--<aop:before method="before" pointcut-ref="pointcut" />-->
<!--<aop:after method="after" pointcut-ref="pointcut" />-->
<aop:after-returning method="afterReturning" pointcut-ref="pointcut" />
</aop:aspect>
运行 test2() 方法后,返回结果如下:
删除数据:1
arithmeticException
ok,myAdvice.afterReturning()中的打印语句并没有输出,证明遇到异常后并没有调用afterReturning()方法。
4.测试异常后置通知 myAdvice.afterException()
修改 spring-aop.xml 中的 aop:aspect
<aop:aspect ref="myAdvice">
<!--<aop:before method="before" pointcut-ref="pointcut" />-->
<!--<aop:after method="after" pointcut-ref="pointcut" />-->
<!--<aop:after-returning method="afterReturning" pointcut-ref="pointcut" />-->
<aop:after-throwing method="afterException" pointcut-ref="pointcut" />
</aop:aspect>
运行 test2() 方法后,返回结果如下:
删除数据:1
异常通知
arithmeticException
ok, 遇见异常,调用了myAdvice.afterException()方法。
5.测试异常后置通知 myAdvice.around()
修改 spring-aop.xml 中的 aop:aspect
<aop:aspect ref="myAdvice">
<!--<aop:before method="before" pointcut-ref="pointcut" />-->
<!--<aop:after method="after" pointcut-ref="pointcut" />-->
<!--<aop:after-returning method="afterReturning" pointcut-ref="pointcut" />-->
<!--<aop:after-throwing method="afterException" pointcut-ref="pointcut" />-->
<aop:around method="around" pointcut-ref="pointcut" />
</aop:aspect>
运行 test() 方法,返回结果如下:
环绕通知前置
插入数据:tom
环绕通知后置
ok, 成功调用了myAdvice.around()方法。