Spring AOP——基于XML的AOP实现

基于XML的AOP实现

  因为Spring AOP的代理对象由IoC容器自动生成,所以开发者无须过多关注代理对象生成的过程,只需选择连接点、创建切面、定义切点并在XML文件中添加配置信息即可。

表1 配置Spring AOP的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这两个属性

表2 < aop:aspect >元素的id属性和ref属性
属性名称描述
id用于定义该切面的唯一标识
ref用于引用普通的Spring Bean

2.配置切入点

  在Spring的配置文件中,切入点是通过<aop:pointcut>元素来定义的,表示该切入点是全局切入点,它可被多个切面共享;当<aop:pointcut>元素作为<aop:aspect>元素的子元素时,表示该切入点只对当前切面有效。
  在定义<aop:aspect>元素时,通常会指定id和expression这两个属性

表3 < aop:pointcut >元素的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所示。

表4 < aop:aspect >元素的常用属性
属性描述
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实现了对目标对象的方法增强。

谢谢浏览!

  • 5
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring AOPSpring框架中的一个重要模块,它提供了面向切面编程(AOP)的支持。AOP是一种编程思想,它可以在不改变原有代码的情况下,通过在程序运行时动态地将代码“织入”到现有代码中,从而实现对原有代码的增强。 Spring AOP提供了基于注解的AOP实现,使得开发者可以通过注解的方式来定义切面、切点和通知等相关内容,从而简化了AOP的使用。 下面是一个基于注解的AOP实现的例子: 1. 定义切面类 ```java @Aspect @Component public class LogAspect { @Pointcut("@annotation(Log)") public void logPointcut() {} @Before("logPointcut()") public void beforeLog(JoinPoint joinPoint) { // 前置通知 System.out.println("执行方法:" + joinPoint.getSignature().getName()); } @AfterReturning("logPointcut()") public void afterLog(JoinPoint joinPoint) { // 后置通知 System.out.println("方法执行完成:" + joinPoint.getSignature().getName()); } @AfterThrowing(pointcut = "logPointcut()", throwing = "ex") public void afterThrowingLog(JoinPoint joinPoint, Exception ex) { // 异常通知 System.out.println("方法执行异常:" + joinPoint.getSignature().getName() + ",异常信息:" + ex.getMessage()); } } ``` 2. 定义业务逻辑类 ```java @Service public class UserService { @Log public void addUser(User user) { // 添加用户 System.out.println("添加用户:" + user.getName()); } @Log public void deleteUser(String userId) { // 删除用户 System.out.println("删除用户:" + userId); throw new RuntimeException("删除用户异常"); } } ``` 3. 在配置文件中开启AOP ```xml <aop:aspectj-autoproxy/> <context:component-scan base-package="com.example"/> ``` 在这个例子中,我们定义了一个切面类LogAspect,其中通过@Aspect注解定义了一个切面,通过@Pointcut注解定义了一个切点,通过@Before、@AfterReturning和@AfterThrowing注解分别定义了前置通知、后置通知和异常通知。 在业务逻辑类中,我们通过@Log注解标注了需要增强的方法。 最后,在配置文件中,我们通过<aop:aspectj-autoproxy/>开启了AOP功能,并通过<context:component-scan>扫描了指定包下的所有组件。 这样,当我们调用UserService中的方法时,就会触发LogAspect中定义的通知,从而实现对原有代码的增强。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值