spring-data-aop
用途主要是记录日志和做切面增强
项目demo: https://github.com/woyaochengweidaniu/spring
项目启动直接访问接口即可在控制台看到效果--------------------
依赖
<?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 http://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.6.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.lcm</groupId>
<artifactId>aop</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>aop</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</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-aop -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
<version>2.1.6.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/cn.hutool/hutool-all -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>4.5.11</version>
</dependency>
<!-- 解析 UserAgent 信息 -->
<dependency>
<groupId>eu.bitwalker</groupId>
<artifactId>UserAgentUtils</artifactId>
<version>1.21</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.8</version>
<scope>provided</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.1.6.RELEASE</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
切点可以用注解 也可以用表达式
1创建注解
package com.lcm.aop.annon;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 创建注解
* RetentionPolicy.RUNTIME 生命周期 运行时
*ElementType.METHOD 标记在什么地方 方法上
*
* @author lcm
* @date created in 2019 7 11
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface OpLog {
String operation() default "";
String target() default "";
}
创建切面
package com.lcm.aop.aspectj;
import com.lcm.aop.annon.OpLog;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
/**
* <p>进行注解式切面编程</p>
* @author lcm
* @date created in 2019 7 11
*
*/
@Slf4j
@Aspect
@Component
public class OpreationLog {
/**
*<p>只需要在方法上添加注解即可</p>
*/
@Pointcut("@annotation(com.lcm.aop.annon.OpLog)")
public void operation(){}
/**
* <p>带有log的注解并且切入点是operation 返回的是Object</p>
* @param joinPoint
* @param opLog
* @param o
*/
@AfterReturning(value = "operation()&&@annotation(opLog)",returning = "o")
public void AfterReturning(JoinPoint joinPoint, OpLog opLog, Object o){
log.info("操作类型:{}",opLog.operation());
log.info("操作目标:{}",opLog.target());
log.info("返回对象:{}",o);
Object[] args = joinPoint.getArgs();
for (Object object:args) {
log.info("参数:{}",object);
}
}
}
创建service
package com.lcm.aop.service;
import com.lcm.aop.annon.OpLog;
import org.springframework.stereotype.Service;
/**
* @author lcm
*/
@Service
public class TestSerivce {
@OpLog(operation = "删除",target = "订单")
public Object delete(String id){
System.out.println(id);
return "success";
}
}
创建controller
package com.lcm.aop.api;
import com.lcm.aop.service.TestSerivce;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author lcm
*/
@RestController
public class ApiController {
@Autowired
private TestSerivce serivce;
/**
* 测试方法
*
* @param id 测试参数
*/
@GetMapping("/test2")
public Object test2(String id) {
Object delete = serivce.delete(id);
return delete;
}
}
2使用表达式进行切点切入
package com.lcm.aop.aspectj;
import cn.hutool.json.JSONUtil;
import eu.bitwalker.useragentutils.UserAgent;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
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.Map;
import java.util.Objects;
/**
* @author lcm
* <P>记录切面日志</P>
* @date created in 2019 7 11
* @author lcm
* @deprecated 切面不仅可以做日志 还可以做方法增强
*
*/
@Aspect
@Component
@Slf4j
public class AopLog {
private static final String START_TIME = "request-start";
/**
* 切入点
*/
@Pointcut("execution(public * com.lcm.aop.controller.*Controller.*(..))")
public void log() {
}
/**
* 前置操作
*
* @param point 切入点
*/
@Before("log()")
public void beforeLog(JoinPoint point) {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = Objects.requireNonNull(attributes).getRequest();
log.info("【请求 URL】:{}", request.getRequestURL());
log.info("【请求 IP】:{}", request.getRemoteAddr());
log.info("【请求类名】:{},【请求方法名】:{}", point.getSignature().getDeclaringTypeName(), point.getSignature().getName());
Map<String, String[]> parameterMap = request.getParameterMap();
log.info("【请求参数】:{},", JSONUtil.toJsonStr(parameterMap));
Long start = System.currentTimeMillis();
request.setAttribute(START_TIME, start);
}
/**
* 环绕操作
*
* @param point 切入点
* @return 原方法返回值
* @throws Throwable 异常信息
*/
@Around("log()")
public Object aroundLog(ProceedingJoinPoint point) throws Throwable {
Object result = point.proceed();
log.info("【返回值】:{}", JSONUtil.toJsonStr(result));
return result;
}
/**
* 后置操作
*/
@AfterReturning("log()")
public void afterReturning() {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = Objects.requireNonNull(attributes).getRequest();
Long start = (Long) request.getAttribute(START_TIME);
Long end = System.currentTimeMillis();
log.info("【请求耗时】:{}毫秒", end - start);
String header = request.getHeader("User-Agent");
UserAgent userAgent = UserAgent.parseUserAgentString(header);
log.info("【浏览器类型】:{},【操作系统】:{},【原始User-Agent】:{}", userAgent.getBrowser().toString(), userAgent.getOperatingSystem().toString(), header);
}
}
创建controller
package com.lcm.aop.controller;
import cn.hutool.core.lang.Dict;
import cn.hutool.core.util.StrUtil;
import com.lcm.aop.service.TestSerivce;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* <p>
* 测试 Controller
* </p>
*
* @package: com.xkcoding.log.aop.controller
* @description: 测试 Controller
* @author: yangkai.shen
* @date: Created in 2018/10/1 10:10 PM
* @copyright: Copyright (c) 2018
* @version: V1.0
* @modified: yangkai.shen
*/
@RestController
public class TestController {
@Autowired
private TestSerivce serivce;
/**
* 测试方法
*
* @param who 测试参数
* @return {@link Dict}
*/
@GetMapping("/test1")
public Dict test1(String who) {
return Dict.create().set("who", StrUtil.isBlank(who) ? "me" : who);
}
}
启动项目然后访问端口 如果端口号指定了,就按照指定的端口号访问
浏览器输入:http://localhost:8081/test1
浏览器输入:http://localhost:8081/test2