原文:https://github.com/x113773/testall/issues/12

1. 还是首先添加依赖(使用当前springboot的默认版本)
```
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>

```
- 参考下面[官方文档](http://docs.spring.io/spring-boot/docs/1.5.4.RELEASE/reference/htmlsingle/)的部分配置说明,可见aop是默认开启的,自动添加了@EnableAspectJAutoProxy注解
```
# AOP
spring.aop.auto=true # Add @EnableAspectJAutoProxy.
spring.aop.proxy-target-class=false # Whether subclass-based (CGLIB) proxies are to be created (true) as opposed to standard Java interface-based proxies (false).
```

2. 编写一个切面类,[AspectAdviceConfig.java](https://github.com/x113773/testall/blob/master/src/main/java/com/ansel/testall/aop/AspectAdviceConfig.java),里面定义了一个切点指示器和各种通知(Advice,也译作 增强)

```
package com.ansel.testall.aop;

import java.lang.reflect.Method;
import java.util.Arrays;

import javax.servlet.http.HttpServletRequest;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.DeclareParents;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

@Aspect
@Component
public class AspectAdviceConfig {
private Logger logger = LoggerFactory.getLogger(this.getClass());

/**
* 定义切点指示器:com.ansel.testall.aop包下,带@RestController注解的类。
*/
@Pointcut("execution(* com.ansel.testall.aop..*(..)) and @annotation(org.springframework.web.bind.annotation.RestController)")
public void myPointcut() {
}

/**
* 前置通知,在目标方法完成之后调用通知,此时不会关 心方法的输出是什么
*/
@Before("myPointcut()")
public void beforeAdvice() {
System.out.println("Before--通知方法会在目标方法调用之前执行");
}

/**
* 后置通知,在目标方法完成之后调用通知,此时不会关 心方法的输出是什么
*/
@After("myPointcut()")
public void afterAdvice() {
System.out.println("After--通知方法会在目标方法返回或抛出异常后调用");
}

/**
* 返回通知,在目标方法成功执行之后调用,可以获得目标方法的返回值,但不能修改(修改也不影响方法的返回值)
*
* @param jp
* JoinPoint接口,可以获得连接点的一些信息
*
* @param retVal
* 目标方法返回值,和jp一样会由spring自动传入
*/
@AfterReturning(returning = "retVal", pointcut = "myPointcut()")
public void afterReturningAdvice(JoinPoint jp, Object retVal) {
retVal = retVal + " (@AfterReturning can read the return value, but it can't change the value!)";
System.out.println("AfterReturning--通知方法会在目标方法返回后调用; retVal = " + retVal);
System.out.println(jp.toLongString());
}

/**
* 异常通知,在目标方法抛出异常后调用通知
*/

@AfterThrowing("myPointcut()")
public void afterThrowingAdvice() {
System.out.println("AfterThrowing--通知方法会在目标方法抛出异常后调用");
}

/**
* 环绕通知,可以在目标方法调用前后,自定义执行内容。可以修改目标方法的返回值
*
* @param pjp
*/
@Around("myPointcut()")
public Object aroundAdvice(ProceedingJoinPoint pjp) {
Object retVal = null;
try {
System.out.println("Around--目标方法调用之前执行");

ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();

MethodSignature signature = (MethodSignature) pjp.getSignature();
Method method = signature.getMethod(); // 获取被拦截的方法
String methodName = method.getName(); // 获取被拦截的方法名

logger.info("requset method name is: " + methodName);
logger.info("request URL is: " + request.getRequestURL().toString());
logger.info("request http method: " + request.getMethod());
logger.info("request arguments are: " + Arrays.toString(pjp.getArgs()));

retVal = pjp.proceed();
retVal = retVal + " (@Around can change the return value!)";

System.out.println("Around--目标方法返回后调用");
} catch (Throwable e) {
System.out.println("Around--目标方法抛出异常后调用");
}
return retVal;
}
}

```
3. 通过Advice可以某些方法增加一些功能,若要为某个对象增加新的方法,则要用到Introduction,编写另外一个切面AspectIntroductionConfig.java

```
package com.ansel.testall.aop;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.DeclareParents;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class AspectIntroductionConfig {

/**
* DeclareParents注解所标注的静态属性指明了要引入的接口;
* value属性指定了哪种类型的bean要引入该接口;
* defaultImpl属性指定了为引入功能提供实现的类。
*/
@DeclareParents(value = "com.ansel.testall.aop.AopService+", defaultImpl = IntroductionServiceImpl.class)
public static IntroductionService introductionService;
}

```
4. 编写两个接口AopService、IntroductionService,和2个实现AopServiceImpl、IntroductionServiceImpl

```
package com.ansel.testall.aop;

public interface AopService {
String myOwnMethod();
}
/***********************************/
package com.ansel.testall.aop;

public interface IntroductionService {
String IntroductionMethod();
}
/***********************************/
package com.ansel.testall.aop;

import org.springframework.stereotype.Service;

@Service
public class AopServiceImpl implements AopService {

@Override
public String myOwnMethod() {
return "this method is from AopService";
}

}
/***********************************/
package com.ansel.testall.aop;

import org.springframework.stereotype.Service;

@Service
public class IntroductionServiceImpl implements IntroductionService {

@Override
public String IntroductionMethod() {
return "this method from Introduction.";
}

}
```

5. 编写一个切点实例[AopController.java](https://github.com/x113773/testall/blob/master/src/main/java/com/ansel/testall/aop/AopController.java) (其实就是个普通的controller)

```
package com.ansel.testall.aop;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class AopController {

/**
* 只注入AopService
*/
@Autowired
AopService aopService;

/**
* 测试AOP通知(Advice,也译作 增强)
*
* @return
*/
@RequestMapping(value = "/aop", method = RequestMethod.GET)
public String testAop() {
return "this is a AOP Advice test.";
}

/**
* 测试AOP引入(Introduction)
*
* @return
*/
@RequestMapping(value = "/aop/introdution", method = RequestMethod.GET)
public String testAopIntroduction() {
System.out.println(aopService.myOwnMethod());
//接口类型转换
IntroductionService introductionService = (IntroductionService) aopService;
System.out.println(introductionService.IntroductionMethod());
return "this is a AOP Introduction test.";
}
}

```

4. 启动项目,触发 localhost:8080/aop 请求,控制台输出结果如下:

```
Around--目标方法调用之前执行
2017-07-03 17:33:15.494 INFO 8548 --- [nio-8443-exec-7] tConfig$$EnhancerBySpringCGLIB$$5f4562fb : requset method name is: testAOP
2017-07-03 17:33:15.495 INFO 8548 --- [nio-8443-exec-7] tConfig$$EnhancerBySpringCGLIB$$5f4562fb : request URL is: https://localhost:8443/aop
2017-07-03 17:33:15.495 INFO 8548 --- [nio-8443-exec-7] tConfig$$EnhancerBySpringCGLIB$$5f4562fb : request http method: GET
2017-07-03 17:33:15.495 INFO 8548 --- [nio-8443-exec-7] tConfig$$EnhancerBySpringCGLIB$$5f4562fb : request arguments are: []
Before--通知方法会在目标方法调用之前执行
Around--目标方法返回后调用
After--通知方法会在目标方法返回或抛出异常后调用
AfterReturning--通知方法会在目标方法返回后调用; retVal = this is a AOP test. (@Around can change the return value!) (@AfterReturning can read the return value, but it can't change the value!)
execution(public java.lang.String com.ansel.testall.aop.AOPController.testAOP())
```

页面返回结果如下:
`this is a AOP test. (@Around can change the return value!)`

触发 localhost:8080/aop/introdution 请求,控制台输出结果如下:

![qq 20170704124306](https://user-images.githubusercontent.com/24689696/27815388-6151c8ca-60b6-11e7-86eb-aa5f2772caa5.png)

---
注:

`@Pointcut("execution(* com.ansel.testall.aop..*(..)) and @annotation(org.springframework.web.bind.annotation.RestController)")`

当我使用and操作符连接上面两个切点指示器,没有任何问题(把注解RestController换成RequestMapping也没问题)
然而,当我使用&&操作符连接上面两个切点指示器时,完全没有触发AspectJ,切面没有织入任何连接点(把注解RestController换成RequestMapping就没问题)

```
/**
* OK
*/
@Pointcut("execution(* com.ansel.testall.aop..*(..)) and @annotation(org.springframework.web.bind.annotation.RestController)")

/**
* not OK
*/
@Pointcut("execution(* com.ansel.testall.aop..*(..)) && @annotation(org.springframework.web.bind.annotation.RestController)")

/**
* OK
*/
@Pointcut("execution(* com.ansel.testall.aop..*(..)) and @annotation(org.springframework.web.bind.annotation.RequestMapping)")

/**
* OK
*/
@Pointcut("execution(* com.ansel.testall.aop..*(..)) && @annotation(org.springframework.web.bind.annotation.RequestMapping)")
```

Spring Boot1.5.4 AOP实例的更多相关文章

  1. Spring学习笔记IOC与AOP实例

    Spring框架核心由两部分组成: 第一部分是反向控制(IOC),也叫依赖注入(DI); 控制反转(依赖注入)的主要内容是指:只描述程序中对象的被创建方式但不显示的创建对象.在以XML语言描述的配置文 ...

  2. Java框架spring 学习笔记(十二):aop实例操作

    使用aop需要在网上下载两个jar包: aopalliance.jar aspectjweaver.jar 为idea添加jar包,快捷键ctrl+shift+alt+s,打开添加jar包的对话框,将 ...

  3. Spring Aop实例@Aspect、@Before、@AfterReturning@Around 注解方式配置

    用过spring框架进行开发的人,多多少少会使用过它的AOP功能,都知道有@Before.@Around和@After等advice.最近,为了实现项目中的输出日志和权限控制这两个需求,我也使用到了A ...

  4. Spring.Net AOP实例

    Spring.Net和Log4net.NUnit.NHibernate一样,也是先从Java中流行开来,然后移植到了.NET当中,形成了.NET版的Spring框架.其官方网站为:http://www ...

  5. Spring Aop实例@Aspect、@Before、@AfterReturning@Around 注解方式配置(转)

    用过spring框架进行开发的人,多多少少会使用过它的AOP功能,都知道有@Before.@Around和@After等advice.最近,为了实现项目中的输出日志和权限控制这两个需求,我也使用到了A ...

  6. Spring的IOC和AOP之深剖

    今天,既然讲到了Spring 的IOC和AOP,我们就必须要知道 Spring主要是两件事: 1.开发Bean:2.配置Bean.对于Spring框架来说,它要做的,就是根据配置文件来创建bean实例 ...

  7. Spring(6)—— AOP

    AOP(Aspect-OrientedProgramming)面向切面编程,与OOP完全不同,使用AOP编程系统被分为切面或关注点,而不是OOP中的对象. AOP的引入 在OOP面向对象的使用中,无可 ...

  8. 转-Spring Framework中的AOP之around通知

    Spring Framework中的AOP之around通知 http://blog.csdn.net/xiaoliang_xie/article/details/7049183 标签: spring ...

  9. spring之初识Ioc&Aop

    Spring框架的作用 spring是一个轻量级的企业级框架,提供了ioc容器.Aop实现.dao/orm支持.web集成等功能,目标是使现有的java EE技术更易用,并促进良好的编程习惯. Spr ...

随机推荐

  1. Python爬虫学习之获取网页源码

    偶然的机会,在知乎上看到一个有关爬虫的话题<利用爬虫技术能做到哪些很酷很有趣很有用的事情?>,因为强烈的好奇心和觉得会写爬虫是一件高大上的事情,所以就对爬虫产生了兴趣. 关于网络爬虫的定义 ...

  2. 关于Cookie安全性设置的那些事

    一.标题:关于Cookie安全性设置的那些事 副标:httponly属性和secure属性解析 二.引言 经常有看到XSS跨站脚本攻击窃取cookie案例,修复方案是有httponly.今天写出来倒腾 ...

  3. 在wamp下使用netbeans开启Xdbug

    1.到http://www.xdebug.org 下载与PHP对应的xdebug版本,也可以把phpinfo源码粘贴到http://www.xdebug.org/find-binary.php,提交后 ...

  4. 用scikit-learn学习LDA主题模型

    在LDA模型原理篇我们总结了LDA主题模型的原理,这里我们就从应用的角度来使用scikit-learn来学习LDA主题模型.除了scikit-learn,  还有spark MLlib和gensim库 ...

  5. iOS安全攻防之结构体保护使用

    Objective-C 代码很容易被 hook,因此需要对一些重要的业务逻辑进行保护,可以改用结构体的形式,把函数名隐藏在结构体里,以函数指针成员的形式存储.这样编译后只留了下地址,去掉了名字和参数表 ...

  6. 《实战java高并发程序设计》源码整理及读书笔记

    日常啰嗦 不要被标题吓到,虽然书籍是<实战java高并发程序设计>,但是这篇文章不会讲高并发.线程安全.锁啊这些比较恼人的知识点,甚至都不会谈相关的技术,只是写一写本人的一点读书感受,顺便 ...

  7. VR全景:电商巨头的角逐

    VR全景智慧城市:京东推"京东梦"挑战淘宝Buy+ ,VR购物谁主沉浮? VR全景智慧城市是国内首家商业全景平台,结合先进VR虚拟现实技术,以线下实体为依托,将空间还原到线上,用户 ...

  8. Selenium基础知识

    本人博客文章网址:https://www.peretang.com/basic-knowledge-of-selenium/ 什么是Selenium Selenium是一个自动化测试工具 是一组不同的 ...

  9. 百度导航试用 vs 高德导航

    听说百度导航免费了,下载试用了一下: HUD模式不错,但是需要一个手机支架或挂钩.尤其是HUD景象模式,夜间把手机平放,通过前挡风玻璃反射看.这个功能有点乔布斯的感觉了. 不过路径规划还差一点,和凯立 ...

  10. openjdk8之编译和debug

    系统环境为ubuntu 16.04,uname -a: Linux ddy-Aspire-V5-573G 4.4.0-21-generic #37-Ubuntu SMP Mon Apr 18 18:3 ...