基于XML的AOP实现
因为Spring AOP的代理对象由IoC容器自动生成,所以开发者无须过多关注代理对象生成的过程,只需选择连接点、创建切面、定义切点并在XML文件中添加配置信息即可。
元素 | 描述 |
---|---|
<aop:config> | Spring AOP配置的根元素 |
<aop:aspect> | 配置切面 |
<aop:advisor> | 配置通知器 |
<aop:pointcut> | 配置切入点 |
<aop:before> | 配置前置通知,在目标方法执行前实施增强,可以应用于权限管理等功能 |
<aop:after> | 配置后置通知,在目标方法执行前实施增强,可以应用于关闭流、上传文件、删除临时文件等功能 |
<aop:around> | 配置环绕通知,在目标方法执行前实施增强,可以应用于日志、事务管理等功能 |
<aop:after-running> | 配置返回通知,在目标方法执行之后调用通知 |
<aop:after-throw> | 配置异常通知,在方法抛出异常后实施增强,可以应用于处理异常记录日志等功能 |
1.配置切面
在Spring的配置文件中,配置切面使用的是<aop:aspect>元素,该元素会将一个已定义好的Spring Bean转换成切面Bean,因此,在使用<aop:aspect>元素之前,要在配置文件中先定义一个普通的Spring Bean。Spring Bean定义完成后,通过<aop:aspect>元素的ref属性即可引用该Bean。
配置<aop:aspect>元素时,通常会指定id和ref这两个属性
属性名称 | 描述 |
---|---|
id | 用于定义该切面的唯一标识 |
ref | 用于引用普通的Spring Bean |
2.配置切入点
在Spring的配置文件中,切入点是通过<aop:pointcut>元素来定义的,表示该切入点是全局切入点,它可被多个切面共享;当<aop:pointcut>元素作为<aop:aspect>元素的子元素时,表示该切入点只对当前切面有效。
在定义<aop:aspect>元素时,通常会指定id和expression这两个属性
属性名称 | 描述 |
---|---|
id | 用于指定切入点的唯一标识 |
expression | 用于指定切入点关联的切入点表达式 |
Spring AOP切入点表达式的基本格式如下:
execution(modifiers-pattern?ret-type-pattern
declaring-type-pattern?name-pattern(param-pattern) throws-pattern?)
在上述格式中,execution表达式各部分参数说明如下:
- modifiers-pattern: 表示定义的目标方法的访问修饰符,如public、private等。
- ret-type-pattern: 表示定义的目标方法的返回值类型,如void、String等。
- declaring-type-pattern: 表示定义的目标方法的类路径,如com.cqust.jdk.UserDaoImpl。
- name-pattern: 表示具体需要被代理的目标方法,如add()方法。
- param-pattern:表示需要被代理的目标方法包含的参数,文章示例中目标方法参数都为空。
- throws-pattern:表示需要被代理的目标方法抛出的异常类型。
其中,带有问号(?)的部分,如modifiers-pattern、declaring-type-pattern和throws-pattern表示可选配置项,而其他部分是必备配置项。
要想了解更多切入点表达式的配置信息,读者可以参考Spring官方文档的切入点声明(Declaring a pointcut)部分。
3.配置通知
在Spring的配置文件中,使用<aop:aspect>元素配置了5种常用通知,如表1所示,5种通知分别为前置通知、后置通知、环绕通知、返回通知和异常通知,<aop:aspect>元素的常用属性如表4所示。
属性 | 描述 |
---|---|
pointcut | 该属性用于指定一个切入点表达式,Spring将在匹配该表达式的连接点时织入该通知 |
pointcut-ref | 该属性用于指定一个已存在的切入点名称,入配置代码中的myPointCut。通常只需要使用pointcut和pointcut-ref这两个属性中的一个即可 |
method | 该属性指定一个方法名,指定将切面Bean中的该方法转换为增强处理 |
throwing | 该属性只对< after-throwing > 元素有效,用于指定一个形象名,异常通知方法可以通过该形参访问目标方法所抛出的异常 |
returning | 该属性只对< after-returning > 元素有效,用于指定一个形象名,后置通知方法可以通过该形参访问目标方法的返回值 |
了解了如何在XML中配置切面、切入点和通知后,下面通过一个案例演示如何在Spring中使用XML实现Spring AOP,具体实现步骤如下。
(1)在chapter07项目(自己在IDEA中新建一个)的pom.xml文件中导入AspectJ框架相关JAR包的依赖,在pom.xml中添加的代码如下:
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.9.1</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.6</version>
</dependency>
(2)在chapter07项目的src/main/java目录下创建一个com.cqust.dao包,在该包下创建接口UserDao,并在该接口中编写添加、删除、修改和查询的方法。UserDao接口具体代码如下:
package com.cqust.dao;
public interface UserDao {
public void insert();
public void delete();
public void update();
public void select();
}
(3)在com.cqust.dao包下创建UserDao接口的实现类UserDaoImpl,实现UserDao接口中的方法。
package com.cqust.dao;
public class UserDaoImpl implements UserDao{
public void insert(){
System.out.println("添加用户信息");
}
public void delete(){
System.out.println("删除用户信息");
}
public void update(){
System.out.println("更新用户信息");
}
public void select(){
System.out.println("查询用户信息");
}
}
(4)com.cqust.dao包下创建XmlAdvice类,用于定义通知。
package com.cqust.dao;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
public class XmlAdvice {
//前置通知
public void before(JoinPoint joinPoint){ //使用JoinPoint接口实例作为参数获得目标对象的类名和方法名
System.out.print("这是前置通知!");
System.out.print("目标类:" + joinPoint.getTarget());
System.out.println(",被织入增强处理的目标方法为:"+joinPoint.getSignature().getName());
}
//返回通知
public void afterReturning(JoinPoint joinPoint){//使用JoinPoint接口实例作为参数获得目标对象的类名和方法名
System.out.print("这是返回通知(方法不出现异常时调用)!");
System.out.println("被织入增强处理的目标方法为:"+joinPoint.getSignature().getName());
}
/**
* 环绕通知
* ProceedingJoinPoint是JoinPoint子接口,表示可以执行目标方法
* 1.必须是Object类型的返回值
* 2.必须接收一个参数,类型为ProceedingJoinPoint
* 3.必须throws Throwable
*/
public Object around(ProceedingJoinPoint point)throws Throwable{//使用ProceedingJoinPoint接口实例作为参数获得目标对象的类名和方法名
System.out.println("这是环绕通知之前的部分!");
//调用目标方法
Object object = point.proceed();
System.out.println("这是环绕通知之前的部分!");
return object;
}
//异常通知
public void afterException(){
System.out.println("异常通知!");
}
//后置通知
public void after(){
System.out.println("这是后置通知!");
}
}
需要注意的是,环绕通知必须接收一个类型为ProceedingJoinPoint的参数,返回值也必须是Object类型,且必须抛出异常。
(5)在chapter07项目的src/main/java目录下创建一个applicationContext.xml文件,在该文件中引入AOP命名空间,使用< bean >元素添加Spring AOP的配置信息。
<?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 https://www.springframework.org/schema/aop/spring-aop.xsd">
<!--注册Bean-->
<bean name="userDao" class="com.cqust.dao.UserDaoImpl"></bean>
<bean name="xmlAdvice" class="com.cqust.dao.XmlAdvice"></bean>
<!--配置Spring AOP-->
<aop:config>
<!--指定切入点-->
<aop:pointcut id="pointcut" expression="execution(*
com.cqust.dao.UserDaoImpl.*(..))"/>
<!--指定切面-->
<aop:aspect ref = "xmlAdvice">
<!--指定前置通知-->
<aop:before method="before" pointcut-ref="pointcut"/>
<!--指定返回通知-->
<aop:after-returning method="afterReturning" pointcut-ref="pointcut"/>
<!--指定环绕通知-->
<aop:around method="around" pointcut-ref="pointcut"/>
<!--指定异常通知-->
<aop:after-throwing method="afterException" pointcut-ref="pointcut"/>
<!--指定后置通知-->
<aop:after method="after" pointcut-ref="pointcut"/>
</aop:aspect>
</aop:config>
</beans>
(6)在src/test/java目录下创建测试类TestXml。
import com.cqust.dao.UserDao;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestXml {
public static void main(String[] args){
ApplicationContext context = new
ClassPathXmlApplicationContext("applicationContext.xml");
UserDao userDao = context.getBean("userDao",UserDao.class);
userDao.delete();
System.out.println();
userDao.insert();
System.out.println();
userDao.select();
System.out.println();
userDao.update();
}
}
在IDEA中启动TestXml类,控制台的输出结果如图所示。
由运行结果可知,程序执行了XmlAdvice类中的增强方法,表明Spring AOP实现了对目标对象的方法增强。
谢谢浏览!