接上一篇 spring学习笔记(九):使用注解方式实现 AOP 编程
接口 IUserDao.java:
public interface IUserDao {
void save();
}
目标对象类型 UserDao.java,实现 IUserDao 接口:
/**
* 目标对象:实现 IUserDao 接口,spring 会自动选择 JDK代理
*/
public class UserDao implements IUserDao{
@Override
public void save() {
System.out.println("------ 保存数据 -----");
}
}
目标对象类型 OrderDao.java,不实现接口:
/**
* 目标对象:没有实现接口,spring 会自动选择 cglib 代理
*/
public class OrderDao {
public void save() {
System.out.println("------ 保存数据 -----");
// 当目标方法执行异常时,会执行 @AfterThrowing 注解,此时 @AfterReturning 注解不会执行;
// @After 注解不管目标方法有没有异常,都会执行。
int i = 1 / 0;
}
}
切面类 Aop.java:
/**
* 切面类
*/
public class Aop {
public void begin(){
System.out.println("开启事务...");
}
public void after(){
System.out.println("提交事务...");
}
public void afterReturning(){
System.out.println("afterReturning()");
}
public void afterThrowing(){
System.out.println("afterThrowing()");
}
public void around(ProceedingJoinPoint pjo) throws Throwable {
System.out.println("环绕前..."); // 在执行目标方法之前执行
pjo.proceed(); // 执行目标方法
System.out.println("环绕后..."); // 在执行目标方法之后执行
}
}
配置文件 bean.xml:
<?xml version="1.0" encoding="UTF-8"?>
<!--suppress ALL -->
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
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/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 创建目标对象 -->
<bean id="userDao" class="com.spring.demo.UserDao"/>
<bean id="orderDao" class="com.spring.demo.OrderDao"/>
<!-- 创建 AOP 对象 -->
<bean id="aop" class="com.spring.demo.Aop"/>
<!-- AOP 配置 -->
<aop:config>
<!-- 定义一个切入点表达式:指定拦截哪些方法 需要动态植入切面代码 -->
<aop:pointcut expression="execution(* com.spring.demo.*.*(..))" id="pointCut"/>
<!-- 指定切面类 -->
<aop:aspect ref="aop">
<!-- 前置通知:在执行目标方法之前执行(引用前面定义的 切入点表达式) -->
<aop:before method="begin" pointcut-ref="pointCut"/>
<!-- 后置通知:在执行目标方法之后执行(无论是否出现异常,最后都会执行) -->
<aop:after method="after" pointcut-ref="pointCut"/>
<!-- 返回后通知:在调用目标方法结束后执行(出现异常不执行) -->
<aop:after-returning method="afterReturning" pointcut-ref="pointCut"/>
<!-- 异常通知:当目标方法出现异常时执行 -->
<aop:after-throwing method="afterThrowing" pointcut-ref="pointCut"/>
<!-- 环绕通知:环绕目标方法执行(相当于 前置通知 + 后置通知) -->
<aop:around method="around" pointcut-ref="pointCut"/>
</aop:aspect>
</aop:config>
</beans>
测试程序 Demo.java:
public class Demo {
// 如果目标对象有实现接口,spring 会自动选择 “JDK代理”
@Test
public void testJDK(){
// 加载配置文件
ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
// 从 IOC 容器中获取对象
IUserDao userDao = (IUserDao) context.getBean("userDao");
System.out.println(userDao.getClass());
userDao.save();
}
// 如果目标对象没有实现接口,spring 会自动选择 “Cglib代理”
@Test
public void testCglib(){
// 加载配置文件
ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
// 从 IOC 容器中获取对象
OrderDao orderDao = (OrderDao) context.getBean("orderDao");
System.out.println(orderDao.getClass());
orderDao.save();
}
}