Spring中的Aop(三)通过spring的XML配置来实现AOP

一、使用Aop来改造我们的代码

在前两篇文章中,我们讲述了代理的概念,以及如何使用代理来改造我们的事务代码;将事务抽出来,放到代理类中,业务代码保持纯净来实现我们的事务控制;
这一章我们来实践如果使用spring中aop来改造我们的代码;

二、Aop的常用术语

JoinPoint(连接点):被拦截到的点,在Spring中这些点都是方法;
PointCut(切入点):是指对哪些JoinPoint进行拦截的定义
Advice(通知/增强):拦截到JoinPoint之后,要做的事情就是通知;
通知的类型有前置通知、后置通知、异常通知、最终通知和环绕通知;
Target(目标对象):代理的目标对象;
Weaving(织入):把增强应用到目标对象来创建新的代理对象的过程;
Proxy(代理):一个类被Aop织入增强后,就产生一个增强的代理类;
Aspect(切面):是切入点和通知的结合。

三、代码演示

为了更好的理解aop,我们写一个简单的示例来学习;

3.1 创建项目并引入maven包

选择创建maven项目

引入maven包,如下:

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.2.6.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.5</version>
        </dependency>
    </dependencies>

3.2 编写目标对象

创建一个模拟的service接口和实现:

package org.study.service;
public interface IAccountService {
    void getList();
    int getCount();
    void updateUserAccount(int id);
}

实现类如下:

package org.study.service.impl;
import org.study.service.IAccountService;
public class AccountServiceImpl implements IAccountService {
    @Override
    public void getList() {
        System.out.println("getList 执行了...");
    }

    @Override
    public int getCount() {
        System.out.println("getCount 执行了...");
        return 0;
    }
    
    @Override
    public void updateUserAccount(int id) {
        System.out.println("updateUserAccount 执行了...");
    }
}

3.3 编写通知(advice)类

我们的通知类是也是一个模拟类,用于增强方法,该类中我们写了五个方法,分别模拟前置通知、后置通知、异常通知、最终通知和环绕通知;
代码如下:

package org.study.util;
import org.aspectj.lang.ProceedingJoinPoint;
public class Logger {    
    public void beforePrintLog(){
        System.out.println("Logger.beforePrintLog...");
    }

    public void afterPrintLog(){
        System.out.println("Logger.afterPrintLog...");
    }

    public void throwingPrintLog(){
        System.out.println("Logger.throwingPrintLog...");
    }

    public void finallyPrintLog(){
        System.out.println("Logger.finallyPrintLog...");
    }

    /**
     * 环绕通知
     */
    public Object aroundPrintLog(ProceedingJoinPoint pjp) {
        try {
            Object returnVal;
            Object[] args = pjp.getArgs();
            System.out.println("Logger.前置...");
            returnVal = pjp.proceed(args);
            System.out.println("Logger.return...");
            return returnVal;
        } catch (Throwable throwable) {
            System.out.println("Logger.Exception...");
            throw new RuntimeException(throwable);
        } finally {
            System.out.println("Logger.finally...");
        }
    }
}

3.4 配置XML来实现方法增强

接下来我们开始在xml文件中进行配置:
配置的步骤如下:
(1)配置目标对象
(2)配置切面类
(3)配置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
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd">

    <!--配置目标对象-->
    <bean id="accountService" class="org.study.service.impl.AccountServiceImpl" >
    </bean>
    <!--配置切面类-->
    <bean id="logger" class="org.study.util.Logger">
    </bean>
    <aop:config>
        <!--定义切入点表达式-->
        <aop:pointcut expression=" execution(* org.study.service.*.*(..))" id="myPointCut"/>
        <aop:aspect id="aspect" ref="logger">
            <!--前置-->
            <aop:before method="beforePrintLog" pointcut-ref="myPointCut"/>
            <!--后置通知-->
            <aop:after-returning method="afterPrintLog" pointcut-ref="myPointCut"/>
            <!--异常通知-->
            <aop:after-throwing method="throwingPrintLog" pointcut-ref="myPointCut"/>
            <!--最终通知-->
            <aop:after method="finallyPrintLog" pointcut-ref="myPointCut"/>
<!--            <aop:around method="aroundPrintLog" pointcut-ref="myPointCut"/>-->
        </aop:aspect>
    </aop:config>
</beans>

编写测试方法:

package org.study;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.study.service.IAccountService;

public class AccountServiceTest {
    public static void main(String[] args) {
        ApplicationContext context=new ClassPathXmlApplicationContext("bean.xml");
        IAccountService accountService=context.getBean("accountService", IAccountService.class);
        int count= accountService.getCount();
    }
}

查看运行结果:

3.5 环绕通知的配置

通过上面的代码,我们可以发现,我们在配置xml文件时,注释掉了环绕通知,这一步我们把环绕通知的注释打开,运行一下测试类

我们发现,环绕通知的结果和配置四种不同的通知结果一致。

四、总结

1、我们通过spring框架的aop很方便快捷地帮我们实现了代码的增强;
2、通过aop我们可以把很多重复代码提取到公共类中,比如记录日志、事务控制等,这样业务代码会更清爽,便于阅读。

posted @ 2020-06-10 17:34  独钓寒江到酒家  阅读(171)  评论(0编辑  收藏  举报