1. Spring AOP介绍
Spring 提供了很多的实现AOP的方式,有Spring 接口方式,schema配置方式和注解的三种,从Spring 2.0开始,可以使用基于schema及@AspectJ的方式来实现AOP,本文以一个简单的实例介绍了如何以@AspectJ方式在Spring中实现AOP。由于@Aspect是基于注解的,因此要求支持注解的5.0版本以上的JDK。
2.Spring AOP环境
要在项目中使用Spring AOP 则需要在项目中导入除了spring jar包之外,还有aspectjweaver.jar,aspectjrt.jar 和cglib.jar 。
在Spring MVC基本上只需另外加上aspectjweaver.jar和cglib.jar就可以了
- <dependency>
- <groupId>org.aspectj</groupId>
- <artifactId>aspectjweaver</artifactId>
- <version>1.7.1</version>
- </dependency>
- <dependency>
- <groupId>cglib</groupId>
- <artifactId>cglib</artifactId>
- <version>2.2.2</version>
- </dependency>
好了,前提工作准备完成。
3. 实例
这个实例是利用AOP实现对执行方法的环绕增强,即在执行目标方法前后各执行一段我们写好的方法,来达到执行前过滤,执行后记录log的功能
a.目标方法代码
- @Controller
- public class AccountApiController {
- @ResponseBody
- @RequestMapping(value="/openapi/v1/account/kp")
- public String kp(HttpServletRequest request) {
- System.out.println("kp:123");
- return "kp:123";
- }
- }
b.环绕增强的@AspectJ代码
- @Aspect
- public class ApiAspect {
- private static final Logger logger = LoggerFactory.getLogger("com.xxx.log");
- //通过within匹配目标方法的class
- @Around("within(com.xxx.api.*Controller)")
- public String arountAction(ProceedingJoinPoint pjp){
- //接口request参数检查,
- HttpServletRequest request = (HttpServletRequest) pjp.getArgs()[0];
- try {
- //TODO check
- } catch (Exception e) {
- //TODO log & return
- }
- String result = null;
- try {
- //执行目标方法
- result = (String) pjp.proceed();
- //TODO log
- } catch (Throwable e) {
- //TODO log & return
- }
- return result;
- }
- }
- <aop:aspectj-autoproxy />
- <beans:bean class="com.xxx.api.ApiAspect" />
- <context:component-scan base-package="com.xxx.api.*" />
这样就实现了所需的功能 ,AOP的优点就是对目标方法代码不做任何改动,就可以实现前后处理,另外在b中也可以用@Before,@After等其它注解来实现不同的功能,下面就介绍下@AspectJ的详细用法
4. @AspectJ的详细用法
在Spring AOP中目前只有执行方法这一个连接点,Spring AOP支持的AspectJ切入点指示符如下:
一些常见的切入点的例子
execution(public * * (. .)) 任意公共方法被执行时,执行切入点函数。
execution( * set* (. .)) 任何以一个“set”开始的方法被执行时,执行切入点函数。
execution( * com.demo.service.AccountService.* (. .)) 当接口AccountService 中的任意方法被执行时,执行切入点函数。
execution( * com.demo.service.*.* (. .)) 当service 包中的任意方法被执行时,执行切入点函数。 within(com.demo.service.*) 在service 包里的任意连接点。 within(com.demo.service. .*) 在service 包或子包的任意连接点。
this(com.demo.service.AccountService) 实现了AccountService 接口的代理对象的任意连接点。
target(com.demo.service.AccountService) 实现了AccountService 接口的目标对象的任意连接点。
args(java.io.Serializable) 任何一个只接受一个参数,且在运行时传入参数实现了 Serializable 接口的连接点
增强的方式:
@Before:方法前执行
@AfterReturning:运行方法后执行
@AfterThrowing:Throw后执行
@After:无论方法以何种方式结束,都会执行(类似于finally)
@Around:环绕执行