一、示例

1、依赖

 <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.2.2</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
</dependency>

2、Controller

 package com.aop.aop.controller;

 import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController; @RestController
@RequestMapping("/aopController")
public class AopController { @RequestMapping(value="/sayHello", method=RequestMethod.GET)
public String sayHello(String name){
return "hello" + name;
} @RequestMapping(value="/sayHello2", method=RequestMethod.GET)
public String sayHello2(String name){
return "hello" + name;
}
}

3、定义切面类

 package com.aop.aop;

 import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
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;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes; import javax.servlet.http.HttpServletRequest;
import java.util.Arrays; @Aspect
@Component
public class WebLogAcpect {
private Logger logger = LoggerFactory.getLogger(WebLogAcpect.class); /**
* 定义切入点,切入点为com.aop.aop.controller下的所有函数
*/
@Pointcut("execution(public * com.aop.aop.controller..*.*(..))")
public void webLog(){} /**
* 前置通知:在连接点之前执行的通知
* @param joinPoint
* @throws Throwable
*/
@Before("webLog()")
public void doBefore(JoinPoint joinPoint) throws Throwable {
// 接收到请求,记录请求内容
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest(); // 记录下请求内容
logger.info("URL : " + request.getRequestURL().toString());
logger.info("HTTP_METHOD : " + request.getMethod());
logger.info("IP : " + request.getRemoteAddr());
logger.info("CLASS_METHOD : " + joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
logger.info("ARGS : " + Arrays.toString(joinPoint.getArgs()));
} @AfterReturning(returning = "ret",pointcut = "webLog()")
public void doAfterReturning(Object ret) throws Throwable {
// 处理完请求,返回内容
logger.info("RESPONSE : " + ret);
}
}

执行

小结:

1) 在完成引入AOP依赖包之后,一般并不需要去做其他配置,在AOP的默认配置属性中,spring.aop.auto属性默认是开启的,也就是说引入AOP依赖后,默认已经增加了@EnableAspectJAutoProxy。

2) 定义切面类需要两个类的注解:@Component注解把切面类加入到IOC容器中;@Aspect注解使之成为切面类。

3) 切面类中:@Pointcut定义切入点;

       @Before在连接点之前执行;

      @After:当某连接点退出时执行的通知(不论是正常返回还是异常退出)。;

@AfterReturning记录返回的对象;@AfterThrowing:在方法抛出异常退出时执行的通知。

    

二、总结

切点标志符号:

AspectJ5的切点表达式由标志符和操作参数组成,如“execution(public * com.aop.aop.controller..*.*(..))“的切点表达式,execution就是标志符号,而圆括号里的“public * com.aop.aop.controller..*.*(..)”就是操作参数。

execution

匹配 join point 的执行, 例如 "execution(* hello(..))" 表示匹配所有目标类中的 hello() 方法. 这个是最基本的 pointcut 标志符.

within

匹配特定包下的所有 join point, 例如 within(com.xys.*) 表示 com.xys 包中的所有连接点, 即包中的所有类的所有方法. 而 within(com.xys.service.*Service) 表示在 com.xys.service 包中所有以 Service 结尾的类的所有的连接点.

this 与 target

this 的作用是匹配一个 bean, 这个 bean(Spring AOP proxy) 是一个给定类型的实例(instance of). 而 target 匹配的是一个目标对象(target object, 即需要织入 advice 的原始的类), 此对象是一个给定类型的实例(instance of).

bean

匹配 bean 名字为指定值的 bean 下的所有方法, 例如:

bean(*Service) // 匹配名字后缀为 Service 的 bean 下的所有方法
bean(myService) // 匹配名字为 myService 的 bean 下的所有方法
args

匹配参数满足要求的的方法.
例如:

@Pointcut("within(com.xys.demo2.*)")
public void pointcut2() {
} @Before(value = "pointcut2() && args(name)")
public void doSomething(String name) {
logger.info("---page: {}---", name);
}
@Service
public class NormalService {
private Logger logger = LoggerFactory.getLogger(getClass()); public void someMethod() {
logger.info("---NormalService: someMethod invoked---");
} public String test(String name) {
logger.info("---NormalService: test invoked---");
return "服务一切正常";
}
}

当 NormalService.test 执行时, 则 advice doSomething 就会执行, test 方法的参数 name 就会传递到 doSomething 中.

常用例子:

// 匹配只有一个参数 name 的方法
@Before(value = "aspectMethod() && args(name)")
public void doSomething(String name) {
} // 匹配第一个参数为 name 的方法
@Before(value = "aspectMethod() && args(name, ..)")
public void doSomething(String name) {
} // 匹配第二个参数为 name 的方法
Before(value = "aspectMethod() && args(*, name, ..)")
public void doSomething(String name) {
}
@annotation

匹配由指定注解所标注的方法, 例如:

@Pointcut("@annotation(com.xys.demo1.AuthChecker)")
public void pointcut() {
}

则匹配由注解 AuthChecker 所标注的方法.

常见的切点表达式

匹配方法签名
// 匹配指定包中的所有的方法
execution(* com.xys.service.*(..)) // 匹配当前包中的指定类的所有方法
execution(* UserService.*(..)) // 匹配指定包中的所有 public 方法
execution(public * com.xys.service.*(..)) // 匹配指定包中的所有 public 方法, 并且返回值是 int 类型的方法
execution(public int com.xys.service.*(..)) // 匹配指定包中的所有 public 方法, 并且第一个参数是 String, 返回值是 int 类型的方法
execution(public int com.xys.service.*(String name, ..))
匹配类型签名
// 匹配指定包中的所有的方法, 但不包括子包
within(com.xys.service.*) // 匹配指定包中的所有的方法, 包括子包
within(com.xys.service..*) // 匹配当前包中的指定类中的方法
within(UserService) // 匹配一个接口的所有实现类中的实现的方法
within(UserDao+)
匹配 Bean 名字
// 匹配以指定名字结尾的 Bean 中的所有方法
bean(*Service)
切点表达式组合
 
// 匹配以 Service 或 ServiceImpl 结尾的 bean
bean(*Service || *ServiceImpl) // 匹配名字以 Service 结尾, 并且在包 com.xys.service 中的 bean
bean(*Service) && within(com.xys.service.*)

三、来源

https://segmentfault.com/a/1190000007469968

https://www.cnblogs.com/lic309/p/4079194.html

https://blog.csdn.net/lmb55/article/details/82470388

最新文章

  1. C++使用vector
  2. 【CVE-2016-10009】OpenSSH &lt; 7.4 - agent Protocol Arbitrary Library Loading
  3. paper122:多尺度与多分辨率的关系
  4. 【第1期】腾讯云的1001种玩法征集,Ipad mini和Kindle 等你拿!(文章评审中)
  5. html5移动web开发笔记(一)Web 存储
  6. phantomjs和angular-seo-server实现angular单页面seo
  7. ASP.NET发布网站遇到的几个问题
  8. jmeter 异步子请求测试随笔
  9. Android判断网络是否已经连接
  10. jquery实现可展开收缩的首页大图广告展示方式 泰山压顶代码 V2.0
  11. find之exec和args
  12. JavaScript 基础二
  13. C# using垃圾回收详解
  14. Cocos2d-x3.0 DrawNode吸取
  15. 九度OJ 1013 开门人和关门人
  16. C# 一个初学者对 依赖注入 IOC 的理解( 含 Unity 的使用)
  17. oAuth2授权协议 &amp; 微信授权登陆和绑定 &amp; 多环境共用一个微信开发平台回调设置
  18. python之路——18
  19. Linux系统安装 OpenSSL两种方法
  20. Android PermissionUtils:运行时权限工具类及申请权限的正确姿势

热门文章

  1. 如何解决错误【selenium.common.exceptions.SessionNotCreatedException】
  2. Kettle使用教程之数据同步
  3. mysql登录的三种方式
  4. 阶段3 2.Spring_06.Spring的新注解_2 spring的新注解-Bean
  5. 对redis的一些理解
  6. zabbix使用脚本监控
  7. oracle导入导出常见问题及解决方案
  8. win10更新导致chrome打开网页速度太慢
  9. GIS学习之栅格数据
  10. 完全分布式部署Hadoop