前言:aop即
Aspect Oriented-Programming
,面向切面编程是对面向对象编程思想的补充,在众多的aop资料介绍中,我推荐大家可查看Spring Aop详尽教程和Spring Aop实例
我这里主要通过实例来简单介绍Spring aop在Springboot中的使用及自己踩的小坑
- 搭建springboot环境,直接附上一份
pom.xml
配置文件,此份文件结合了Mybatis+mysql
<groupId>com.jing.sprintboot</groupId>
<artifactId>TestSpringBoot</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>TestSpringBoot</name>
<url>https://mvnrepository.com</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spring.version>4.2.3.RELEASE</spring.version>
<spring.boot.version>1.3.0.RELEASE</spring.boot.version>
<tomcat.version>8.0.28</tomcat.version>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.3.0.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope><!-- 编译需要而发布不需要的jar包 -->
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>${spring.boot.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freeMarker</artifactId>
<version>1.3.0.RELEASE</version>
</dependency>
<!-- mybatis -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.1.1</version>
</dependency>
<!-- mysql -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring.boot.version}</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
<defaultGoal>compile</defaultGoal>
</build>
```
-
添加aop环境,主要是添加aspectjweaver.jar依赖
<!-- aop --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency>
-
aop示例代码如下:
package com.jing.springboot.aop; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; @Aspect @Component public class RequestAopInterceptor { private static final Logger REQ_LOGGER = LoggerFactory.getLogger(RequestAopInterceptor.class); // 匹配语法为:注解 修饰符 返回值类型 类名 方法名(参数列表) 异常列表 具体可查看 // http://blog.csdn.net/wangpeng047/article/details/8556800 @Pointcut("execution(* com.jing.springboot.controller..*(..)) and @annotation(org.springframework.web.bind.annotation.RequestMapping)") public void interceptor() { } // 指定声明的pointcut @Before("interceptor()") public void before() { REQ_LOGGER.info("before the requestMapping"); } @After("interceptor()") public void after() { REQ_LOGGER.info("requestMapping is over"); } @AfterReturning(pointcut = "interceptor()", returning = "result") public void doAfterReturing(Object result) { REQ_LOGGER.info("请求返回的信息为: " + result); } @Around("interceptor()") public Object doRound(ProceedingJoinPoint joinPoint) { Object result = null; REQ_LOGGER.info("doRound before"); try { result = joinPoint.proceed(); } catch (Throwable e) { e.printStackTrace(); } REQ_LOGGER.info("doRound after"); return result; }
}
```
- 注意
@Around
注解,其返回值是Object,不可写为void,不然将会导致前台获取数据不得的情况 - 罗列下Spring aop中的
@Before
、@After
、@AfterReturning
、@AfterThrowing
、@Around
的执行顺序@Around
前半部分@Before
代码逻辑@Around
后半部分@After
代码逻辑@AfterReturing
/@AfterThrowing
代码逻辑,前者是在正确返回时触发,后者在出现异常时触发,其中的触发条件也可根据参数来指定,具体可见前言
的链接博客
- 回到示例,写个
Hello World
package com.jing.springboot.controller; import javax.annotation.Resource; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.servlet.ModelAndView; import com.jing.springboot.model.Person; import com.jing.springboot.mysql.mapper.UserDao; //@author jingsir @RestController @RequestMapping(value = "/hello") public class HelloWorldControl { @Resource private UserDao userDao; public HelloWorldControl() { } @RequestMapping(value = "", method = RequestMethod.GET) public Person returnPerson() { Person person = new Person(); person.setName("jingtj"); person.setAge(23); return person; } //可测试@AfterReturning的返回值参数 @RequestMapping(value = "/", method = RequestMethod.GET) public String hello() { return "hello world"; } //此段可忽略 @RequestMapping(value = "/freemarker") public ModelAndView helloFreemaker() { ModelAndView indexView = new ModelAndView("index"); indexView.addObject("user", "jingsir"); return indexView; }
}
```
* 其中在application.properties的配置信息如下:
```
server.port=9901
server.contextPath=/springboot
* 浏览器访问localhost:9901/springboot/hello/便可,查看后台控制台的内容为(对照上述的第五点执行顺序便可明白):
2017-03-19 20:25:44.074 INFO 502 --- [nio-9901-exec-3] c.j.s.aop.RequestAopInterceptor : doRound before
2017-03-19 20:25:44.074 INFO 502 --- [nio-9901-exec-3] c.j.s.aop.RequestAopInterceptor : before the requestMapping
2017-03-19 20:25:44.074 INFO 502 --- [nio-9901-exec-3] c.j.s.aop.RequestAopInterceptor : doRound after
2017-03-19 20:25:44.074 INFO 502 --- [nio-9901-exec-3] c.j.s.aop.RequestAopInterceptor : requestMapping is over
2017-03-19 20:25:44.074 INFO 502 --- [nio-9901-exec-3] c.j.s.aop.RequestAopInterceptor : doAfterReturing-->请求返回的信息为: hello world
```