Spring整理系列(13)——基于配置方式实现spring AOP

1、实现spring AOP所需要的jar

AOP所需要的jar:

  • aspectjrt.jar
  • aspectjweaver.jar
  • cglib.jar

同时需要spring框架相关jar:

  • spring-context.jar
  • spring-context-support.jar
  • spring-tx.jar

单元测试jar

  • junit.jar

项目基于maven进行管理,完整的pom.xml配置文件如下:

<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.test.spring</groupId>
  <artifactId>support</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>jar</packaging>

  <name>support</name>
  <url>http://maven.apache.org</url>

  <properties>
    <spring.version>4.2.6.RELEASE</spring.version>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

  <dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>${spring.version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context-support</artifactId>
        <version>${spring.version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-tx</artifactId>
        <version>${spring.version}</version>
    </dependency>

    <!-- AOP begin -->
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjrt</artifactId>
        <version>1.7.4</version>
    </dependency>
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>1.7.4</version>
    </dependency>
    <dependency>
        <groupId>cglib</groupId>
        <artifactId>cglib</artifactId>
        <version>3.1</version>
    </dependency>
    <!-- AOP end -->

    <!-- TEST begin -->
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.11</version>
        <scope>test</scope>
    </dependency>
    <!-- TEST end -->
  </dependencies>
</project>

2、基于配置的spring-context.xml文件规范、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"
        xmlns:tx="http://www.springframework.org/schema/tx"
        xsi:schemaLocation="
            http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
            http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
            http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">

    <!-- 注册登录业务bean -->
    <bean name="loginService" class="com.test.spring.aop.LoginServiceImpl"></bean>

    <!-- 注册登录业务日志切面bean -->
    <bean name="loginLogAspect" class="com.test.spring.aop.LoginLogAspect"></bean>

    <!-- 配置spring AOP,设置aop:config的proxy-target-class="true"则强制使用CGLIB代理 -->
    <aop:config>

        <!-- 配置切面 -->
        <aop:aspect id="llAspect" ref="loginLogAspect">

            <!-- 配置切入点表达式,即连接点断言 -->
            <aop:pointcut id="loginPointcut" expression="execution(* com.test.spring.aop.*.*(..))"/>

            <!-- 配置通知,pointcut-ref属性指向上面的切入点,可以直接使用pointcut属性,配置执行表达式 -->
            <aop:before method="beforeLogin" pointcut-ref="loginPointcut"/>
            <aop:after method="afterLogin" pointcut-ref="loginPointcut"/>
            <aop:around method="aroundLogin" pointcut-ref="loginPointcut"/>
            <aop:after-returning method="afterReturningLogin" pointcut="execution(* com.test.spring.aop.*.*(..))"/>
            <aop:after-throwing method="afterThrowingLogin" pointcut="execution(* com.test.spring.aop.*.*(..))"/>
        </aop:aspect>
    </aop:config>

</beans>

<beans>是Spring的配置标签,beans里面几个重要的属性:

  • xmlns:是默认的xml文档解析格式,即spring的beans。地址是http://www.springframework.org/schema/beans
    通过设置这个属性,所有在beans里面声明的属性,可以直接通过<>来使用,比如<bean>等等。

  • xmlns:xsi:是xml需要遵守的规范,通过URL可以看到,是w3的统一规范,后面通过xsi:schemaLocation来定位所有的解析文件。

  • xmlns:aop:这个是重点,是我们这里需要使用到的一些语义规范,与面向切面AOP相关。

  • xmlns:tx:Spring中与事务相关的配置内容。

Spring所有的切面和通知器都必须放在一个<aop:config>内(可以配置包含多个<aop:config>元素),每一个<aop:config>可以包含pointcut,advisor和aspect元素(如何全部存在,它们必须按照这个顺序进行相应的声明和配置)


pointcut切面表达式配置简单介绍:

  • execution(public**(..)) 切入点为执行所有public方法时
  • execution(set(..))切入点为执行所有set方法开始的方法时
  • execution(com.xyz.service.AccountService.(..))切入点为执行AccountService类中的所有方法时
  • execution(*com.xyz.service..(..)) 切入点为执行com.xyz.service包下的所有方法时
  • execution(*com.xyz.service…(..)) 切入点为执行com.xyz.service包及其子包下的所有方法时

以下只有Spring中才能用,还有很多配置,可以查阅spring的官方文档

  • within(com.xyz.service.*)
  • within(com.xyz.service..*)within用于匹配制定类型内的方法执行
  • this(com.xyz.service.AccountService) this用于匹配当前AOP代理对象类型的执行方法
  • taget用于匹配当前目标对象类型的执行方法

3、业务接口、业务实现类和切面类、通知

业务接口:

package com.test.spring.aop;
/** 
 * @Description: 业务接口
 */
public interface LoginService {
    public void login() throws Exception;
}

业务实现类:

package com.test.spring.aop;
/** 
 * @Description: 业务实现类
 */
public class LoginServiceImpl implements LoginService {

    @Override
    public void login() throws Exception {
        System.out.println("LoginServiceImpl login 登录成功。。。");
        //业务方法出现异常,则触发抛出异常后通知
        //throw new Exception("");
    }
}

登录业务日志的切面:

package com.test.spring.aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
/** 
 * @Description: 登录业务日志的切面
 */
public class LoginLogAspect {

    //前置通知,除了环绕通知,其它所有通知第一个参数可以是JoinPoint类型
    public void beforeLogin(JoinPoint point){
        System.out.println("前置通知。。。");
    }

    //后置通知
    public void afterLogin(){
        System.out.println("后置通知。。。");
    }

    //环绕通知,有返回值,第一个参数必须是ProceedingJoinPoint类型
    public Object aroundLogin(ProceedingJoinPoint point) throws Throwable{
        System.out.println("环绕通知,业务方法执行之前。。。");

        Object obj = point.proceed();//向下执行业务方法

        System.out.println("环绕通知,业务方法执行之后。。。");
        return obj;
    }

    //返回后通知
    public void afterReturningLogin(){
        System.out.println("返回后通知。。。");
    }

    //抛出异常后通知
    public void afterThrowingLogin(){
        System.out.println("抛出异常后通知。。。");
    }
}

单元测试类:

/** 
 * @Description: 单元测试类
 */
public class TestSpringAop {
    @Test
    public void testSpringAop(){
        LoginService loginService = this.getBean("loginService");
        try {
            //触发业务方法,即触发连接点
            loginService.login();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //以下为容器实例声明及初始化、销毁
    private ClassPathXmlApplicationContext context;

    @Before
    public void before(){

        try {
            context = new ClassPathXmlApplicationContext("spring-context.xml");
            context.start();

        } catch (BeansException e) {
            e.printStackTrace();
        }
    }

    @After
    public void after(){
        context.destroy();
    }

    /**
     * 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.
     */
    @SuppressWarnings("unchecked")
    public <T> T getBean(String name) {
        return (T) context.getBean(name);
    }

    /**
     * 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.
     */
    public <T> T getBean(Class<T> requiredType) {
        return context.getBean(requiredType);
    }
}

执行结果如下:

前置通知。。。
环绕通知,业务方法执行之前。。。
LoginServiceImpl login 登录成功。。。
返回后通知。。。
环绕通知,业务方法执行之后。。。
后置通知。。。


如果同时配置所有类型通知,它们的执行顺序是:前置通知、环绕通知业务方法执行之前、业务方法、(返回后通知、环绕通知业务方法执行之后)/抛出异常后通知、后通知、

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值