Spring AOP学习笔记(2):AOP前置通知&后置通知

一、 使用AOP之前的配置

我使用Spring来完成AOP的配置,AOP和IoC作为Spring两项最主要的特点受到良好的支持,另外使用Maven作为构建工具,在使用AOP前,先加入依赖包,完成pom.xml文件。
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-beans</artifactId>
    <version>4.2.2.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>4.2.2.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-core</artifactId>
    <version>4.2.2.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aop</artifactId>
    <version>4.2.2.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjrt</artifactId>
    <version>1.8.8</version>
</dependency>
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.8.8</version>
</dependency>

二、 AOP前置通知

在上一节中已经说到,连接点由表示连接的位置和程序执行点决定,这里首先说明前置通知,即在业务逻辑之前执行的功能。
先配置Spring的配置文件aop.xml:
<?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:context="http://www.springframework.org/schema/context"
       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 http://www.springframework.org/schema/aop/spring-aop.xsd
        "
        >
    <context:component-scan base-package="com.spring"/>
    <aop:aspectj-autoproxy/>
</beans>
<context:component-scan base-package="**"/>这就不用说了吧,基本上用过Spring的都知道,但是这里有一个问题,是我自己犯傻了,在base-package中的包表示的是一类,即,如上代码中,不仅com.spring包能被扫描到,任何前缀是它的包都能被扫描,所以我把这开始时写的很细,导致切面类没有包含进去,傻傻地还一直在找错误。
<aop:aspectj-autoproxy /> 光是看名字就知道它是什么作用,它使Aspectj的注解起作用,并且自动为满足切点的类生成在理对象,必须配置。
然后建立一个简单的业务功能,例如计算器;
package com.spring.service;

import org.springframework.stereotype.Component;

@Component
public class Calculator {

    public int add(int i, int j){
        return i+j;
    }

    public int sub(int i, int j){
        return i-j;
    }

    public int time(int i, int j){
        return i*j;
    }

    public int divide(int i, int j){
        return i/j;
    }
}
然后新建一个切面类:
@Component
@Aspect
public class LoggingAspect {
    protected Logger logger = LoggerFactory.getLogger(this.getClass());
    /**/
}
切面类必须用@Aspect注解标明这是一个切面类,同时还需要把该切面类放到Spring的IoC容器中,所以这里用@Component注解标识,同时用slf4j来完成日志功能。
下面就是主要的内容,完成前置通知,前置通知就是在目标方法前执行,实现很简单,就是一个注释的使用。除了用注解还有xml配置方式,具体内容看下面的链接。
@Before("execution(public int com.spring.service.Calculator.*(int, int))")
public void loggingBefore(JoinPoint joinPoint){
    logger.info("method begin with name {} and args {}", joinPoint.getSignature().getName(), joinPoint.getArgs());
}
这个@Before和junit@Before千万不能弄混了,每次自动导入时都可能出现这样的问题。
@Before中需要写的是要绑定该Advice的切点表达式。这里用的是
execution(public int com.spring.service.Calculator.*(int, int))
关于切点表达式的内容很多,这里不具体讲,但是用到的最多的就是这里的execution表达式,它用来匹配方法执行的连接点,许多其他的表达式可以在本文下面给出的链接中找。
另外可以通过JoinPoint来访问目标Target信息,包括各种标识符和参数,非常方便。
下面可以对代码进行测试一下:
ApplicationContext context = new ClassPathXmlApplicationContext("aop.xml");
Calculator service = context.getBean(Calculator.class);
int result = service.add(1,2);
System.out.println(result);
得到结果如下:

三、 AOP后置通知

有前置通知,就有后置通知,其他的和前置通知没有什么区别,只是换了一个注解而已,代替@Before使用@After, 后置通知在目标方法执行后 执行,无论是否发生异常都会执行
@After("execution(public int com.spring.service.Calculator.*(int, int))")
public void loggingAfter(JoinPoint joinPoint){
    logger.info("method end");
}
测试代码类似上边如下:
ApplicationContext context = new ClassPathXmlApplicationContext("aop.xml");
Calculator service = context.getBean(Calculator.class);
int result = service.divide(1,2);
System.out.println(result);
结果如下:

但是又有另外的结果如下:对于这个我不是很明白,是不是后置通知在另外的线程运行,我不是很确定,如果有大神能够指出,感激不尽。

另外在发生异常时,依然能够完成通知,结果如下:

另外要注意的 在后置通知中不能访问目标方法执行后返回的结果,要实现这一点要看下一节。

相关文章:
  • 切点表达式知识和相关的例子:http://sishuok.com/forum/posts/list/281.html
  • 类继承/接口实现时Spring AOP切入点注意事项:http://jinnianshilongnian.iteye.com/blog/1979919
  • Spring AOP 的xml配置方式:http://www.codeceo.com/article/java-spring-aop-config.html
  • 涵盖所有Spring AOP知识点:http://shouce.jb51.net/spring/aop.html

你可能感兴趣的:(spring,AOP,maven,后置通知,前置通知)