一、 使用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