Spring AOP

2019-08-27 wjy329 SpringBoot 21

AOP:面向切面编程。AOP可以实现关注点分离,即:不同的问题交给不同的部分去解决。
AOP名词:
1.Aspect:通用功能的代码实现
2.Target:被织入Aspect的对象
3.Join Point:可以作为切入点的机会,所有方法都可以作为切入点
4.Pointcut:Aspect实际被应用在的Join Point,支持正则
5.Advice:类里的方法以及这个方法如何织入到目标方法的方式
6.Weaving:Aop的实现过程

AOP的三种织入方式:
1.编译时织入:需要特殊的Java编译器,如AspectJ
2.类加载时织入:需要特殊的Java编译器,如AspectJ和AspectWerkz
3.运行时织入:Spring采用的方式,通过动态代理的方式,实现简单

AOP的实现:JdkProxy和Cglib

下面通过一个实例来理解AOP:
1.pom.xml
主要是引入AOP的starter
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.7.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.wjy329</groupId>
<artifactId>aop-test</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>aop-test</name>
<description>Demo project for Spring Boot</description>

<properties>
<java.version>1.8</java.version>
</properties>

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
<version>2.1.0.RELEASE</version>
</dependency>

</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>

</project>

2.TestController.java

package com.wjy329.aoptest.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

/**
* @description:
* @author: wjy329
* @create: 2019-08-27 14:17
**/

@Controller
public class TestController {

@RequestMapping(value = "/test",method = RequestMethod.GET)
@ResponseBody
public String test(){
String test = "Test AOP";
System.out.println(test);
return test;
}

}
3.RequestLogAspect.java
package com.wjy329.aoptest.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;


/**
* @description: 请求日志切面
* @author: wjy329
* @create: 2019-08-27 14:21
**/


@Aspect
@Component
public class RequestLogAspect {
private static final Logger logger = LoggerFactory.getLogger(RequestLogAspect.class);

@Pointcut("execution(public * com.wjy329.aoptest.controller..*.*(..))")
public void webLog(){
}

@Before("webLog()")
public void deBefore(JoinPoint joinPoint){
// 接收到请求,记录请求内容
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
HttpServletRequest request = attributes.getRequest();
// 记录请求内容
logger.info("请求的URL:"+request.getRequestURL().toString());
logger.info("请求的IP地址:"+request.getRemoteAddr());
}

@AfterReturning(returning = "ret",pointcut = "webLog()")
public void doAfterReturning(Object ret){
// 处理完的请求,返回内容
logger.info("RESPONSE:"+ret);
}

}



这个例子是常见的打印日志,在一堆方法中,我们可能需要打印每一个方法的日志,如果在每个方法中都写日志会非常的繁琐,AOP就能解决这个问题,让你的业务代码专注于业务,日志代码负责日志打印的实现。例子中主要实现在:RequestLogAspect.java中,通过@Pointcut注解中的参数,表明切入点是哪个方法,例子中的参数代表controller下的所有方法;@Before代表在织入前的动作,@AfterReturning代表织入后的动作。
本文作者:wjy329
版权声明:本博客除特殊说明外均属本人原创。如需转载请署名作者及文章出处。
评论