1、目的
写项目的时候经常会通过日志来排查原因,一种是通过log4j将日志收集出来,然后使用elk进行数据的分类与统计,这种是针对大量的请求日志进行记录。另一种就是通过自定义注解的方式写入数据库,这种是针对特定接口来处理,将重要的操作信息记录到数据库中。这篇博客就是说的第二种方式。
2、思路
首先,应该使用自定义注解来标记哪些接口需要记录操作日志。
然后, 使用切面来统一拦截参数和返回的结果,并将信息返回到数据库。
3、实现过程
?1、Log 自定义注解
package com.example.demo.common.annotation;
import com.example.demo.enums.BusinessType;
import com.example.demo.enums.OperatorType;
import java.lang.annotation.*;
/**
* @author zhangyang
* @version 1.0
* @Date 2022/5/14 13:54
* @Description 自定义注解
*/
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Log {
/**
* 模块
* @return
*/
String title() default "";
/**
* 功能
* @return
*/
BusinessType businessType() default BusinessType.INSERT;
/**
* 操作人类别
* @return
*/
OperatorType operatorType() default OperatorType.OTHER;
/**
* 是否保存请求的参数
* @return
*/
boolean isSaveRequestData() default true;
}
2、 进行跨域配置
package com.example.demo.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* @ClassName SysConfig
* @Description 跨域配置类
* @Author zhangyang
* @Date 2022/3/2 17:41
* @Version 1.0
*/
@Configuration
public class CorsConfiguration implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
//本应用的所有方法都会去处理跨域请求
registry.addMapping("/**")
.allowCredentials(true)
//允许远端访问的域名
.allowedOrigins("*")
//允许请求的方法("POST", "GET", "PUT", "OPTIONS", "DELETE")
.allowedMethods("*")
//允许请求头
.allowedHeaders("*")
.maxAge(3600);
}
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry){
registry.addResourceHandler("/uploads/**")
.addResourceLocations("classpath:/static/");
}
}
3、定义用于测试的controller
package com.example.demo.controller;
import com.example.demo.common.annotation.Log;
import com.example.demo.entity.User;
import com.example.demo.enums.BusinessType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.List;
/**
* @author zhangyang
* @version 1.0
* @Date 2022/5/14 13:53
* @Description 用于测试的Controller
*/
@RequestMapping("/user")
@RestController
public class UserController {
@GetMapping("/selectAll")
@Log(title = "用户查询",businessType = BusinessType.SELECT)
public List<User> selectAllUser() {
return new ArrayList<>();
}
}
4、定义切面实现请求拦截
package com.example.demo.aspectj;
import com.alibaba.fastjson.JSON;
import com.example.demo.common.annotation.Log;
import com.example.demo.entity.SysLog;
import com.example.demo.enums.BusinessStatus;
import com.example.demo.service.ISysLogService;
import com.example.demo.util.IpUtils;
import com.example.demo.util.SpringUtils;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.servlet.HandlerMapping;
import java.lang.reflect.Method;
import java.util.Map;
/**
* @author zhangyang
* @version 1.0
* @Date 2022/5/14 14:09
* @Description 操作日志切面
*/
@Aspect
@Component
public class LogAspect {
private static final Logger log = LoggerFactory.getLogger(LogAspect.class);
//配置织入点
@Pointcut("@annotation(com.example.demo.common.annotation.Log)")
public void logPointCut() {
}
/**
* 处理完请求后执行
*
* @param joinPoint 切点
* @param jsonResult 返回的信息
*/
@AfterReturning(pointcut = "logPointCut()", returning = "jsonResult")
public void doAfterRetuning(JoinPoint joinPoint, Object jsonResult) {
handleLog(joinPoint, null, jsonResult);
}
/**
* 拦截异常操作
*
* @param joinPoint 切点
* @param ex 异常
*/
@AfterThrowing(value = "logPointCut()", throwing = "ex")
public void doAfterThrowing(JoinPoint joinPoint, Exception ex) {
handleLog(joinPoint, ex, null);
}
/**
* 处理完请求之后执行
*
* @param joinPoint 切点
* @param e 异常信息
* @param jsonResult 返回结果
*/
protected void handleLog(final JoinPoint joinPoint, final Exception e, Object jsonResult) {
Log controllerLog = getAnnotationLog(joinPoint);
if (controllerLog == null) {
return;
}
SysLog sysLog = new SysLog();
sysLog.setStatus(BusinessStatus.SUCCESS.ordinal());
// 请求的地址
RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
ServletRequestAttributes requestAttributes = (ServletRequestAttributes) attributes;
String ip = IpUtils.getIpAddr(requestAttributes.getRequest());
sysLog.setOperIp(ip);
// 返回参数
sysLog.setOperUrl(requestAttributes.getRequest().getRequestURI());
sysLog.setOperName("zhangyang");
if (e != null) {
sysLog.setStatus(BusinessStatus.FAIL.ordinal());
sysLog.setErrorMsg(StringUtils.substring(e.getMessage(), 0, 2000));
}
// 设置方法名称
String className = joinPoint.getTarget().getClass().getName();
String methodName = joinPoint.getSignature().getName();
sysLog.setMethod(className + "." + methodName + "()");
sysLog.setOperLocation(sysLog.getOperIp());
// 设置请求方式
sysLog.setRequestMethod(requestAttributes.getRequest().getMethod());
getControllerMethodDescription(joinPoint, controllerLog, sysLog);
// 保存到数据库
SpringUtils.getBean(ISysLogService.class).insertLog(sysLog);
}
/**
* 获取注解中对方法的描述信息,用于controller层注解
*
* @param joinPoint 切点
* @param log 日志
* @param sysLog 数据库操作日志对象
*/
public void getControllerMethodDescription(JoinPoint joinPoint, Log log, SysLog sysLog) {
// 设置action动作
sysLog.setBusinessType(log.businessType().ordinal());
// 设置标题
sysLog.setTitle(log.title());
// 设置操作人的类别
sysLog.setOperatorType(log.operatorType().ordinal());
// 是否需要保存request 参数和 值
if (log.isSaveRequestData()) {
setRequestValue(joinPoint, sysLog);
}
}
/**
* 获取的请求参数,放到log中
* @param joinPoint 切点
* @param sysLog 操作日志
*/
private void setRequestValue(JoinPoint joinPoint,SysLog sysLog) {
String requestMethod = sysLog.getRequestMethod();
if(HttpMethod.PUT.name().equals(requestMethod) || HttpMethod.POST.name().equals(requestMethod)) {
String params = argsArrayString(joinPoint.getArgs());
sysLog.setOperParam(StringUtils.substring(params,0,2000));
} else {
// 请求的地址
RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
ServletRequestAttributes requestAttributes = (ServletRequestAttributes) attributes;
Map<?,?> paramsMap = (Map<?,?>) requestAttributes.getRequest().getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE);
sysLog.setOperParam(StringUtils.substring(paramsMap.toString(),0,2000));
}
}
/**
* 参数转化成Json字符串
* @param paramsArray 参数对象
* @return
*/
private String argsArrayString(Object[] paramsArray) {
String param = "";
if(paramsArray != null && paramsArray.length > 0) {
for(int i=0; i<paramsArray.length; i++) {
if(StringUtils.isNotEmpty(paramsArray[i].toString())) {
Object object = JSON.toJSON(paramsArray[i]);
param += object.toString() + "";
}
}
}
return param;
}
/**
* 是否存在注解,如果存在就获取
*
* @param joinPoint 切点
* @return 注解对象
*/
private Log getAnnotationLog(JoinPoint joinPoint) {
Signature signature = joinPoint.getSignature();
MethodSignature methodSignature = (MethodSignature) signature;
Method method = methodSignature.getMethod();
if (method != null) {
return method.getAnnotation(Log.class);
}
return null;
}
}
5、相关实体类
? ? ? ? 1、操作日志实体类SysLog
package com.example.demo.entity;
import lombok.Data;
/**
* @author zhangyang
* @version 1.0
* @Date 2022/5/14 15:28
* @Description
*/
@Data
public class SysLog {
/**
* 主键
*/
private Long id;
/**
* 操作模块
*/
private String title;
/**
* 业务类型(0 其他 1 新增 2 修改 3删除)
*/
private Integer businessType;
/**
* 请求方法
*/
private String method;
/**
* 请求方式
*/
private String requestMethod;
/**
* 操作类别 (0 其他 1 后台用户 2 手机端用户)
*/
private Integer operatorType;
/**
* 操作人员
*/
private String operName;
/**
* 部门名称
*/
private String deptName;
/**
* 请求URl
*/
private String operUrl;
/**
* 操作地址
*/
private String operIp;
/**
* 操作地点
*/
private String operLocation;
/**
* 请求参数
*/
private String operParam;
/**
* 返回参数
*/
private String jsonResult;
/**
* 状态
*/
private Integer status;
/**
* 异常信息
*/
private String errorMsg;
}
? ? ? ? 2、User
package com.example.demo.entity;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;
/**
* @author zhangyang
* @version 1.0
* @Date 2022/5/14 14:03
* @Description
*/
@Data
public class User {
/**
* 主键
*/
@TableId
Integer id;
/**
* 用户姓名
*/
String name;
/**
* 用户地址
*/
String address;
}
6、枚举类
package com.example.demo.enums;
/**
* @author lenovo
* @version 1.0
* @Date 2022/5/14 15:43
* @Description 操作状态
*/
public enum BusinessStatus {
/**
* 成功
*/
SUCCESS,
/**
* 失败
*/
FAIL,
}
package com.example.demo.enums;
/**
* @author lenovo
* @version 1.0
* @Date 2022/5/14 13:56
* @Description
*/
public enum BusinessType {
/**
* 新增
*/
INSERT,
/**
* 修改
*/
UPDATE,
/**
* 删除
*/
DELETE,
/**
* 清空
*/
CLEAN,
/**
* 查询
*/
SELECT,
}
package com.example.demo.enums;
/**
* @author lenovo
* @version 1.0
* @Date 2022/5/14 13:59
* @Description
*/
public enum OperatorType {
/**
* 其他
*/
OTHER,
/**
* 后台用户
*/
MANAGE,
/**
* 手机端用户
*/
MOBILE
}
?7、Mapper
package com.example.demo.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.demo.entity.SysLog;
import org.apache.ibatis.annotations.Mapper;
/**
* @author zhangyang
* @version 1.0
* @Date 2022/5/14 16:40
* @Description
*/
@Mapper
public interface SysLogMapper extends BaseMapper<SysLog> {
}
8、service以及Impl
package com.example.demo.service;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.demo.entity.SysLog;
import com.example.demo.vo.SysLogBasePageVo;
/**
* @author lenovo
* @version 1.0
* @Date 2022/5/14 16:38
* @Description 日志服务层
*/
public interface ISysLogService {
/**
* 新增数据库日志记录
* @param sysLog
*/
void insertLog(SysLog sysLog);
/**
* 分页查询对象
* @param sysLogBasePageVo 分页查询对象
* @return Page
*/
Page<SysLog> selectSysLogPage(SysLogBasePageVo sysLogBasePageVo);
}
package com.example.demo.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.demo.entity.SysLog;
import com.example.demo.mapper.SysLogMapper;
import com.example.demo.service.ISysLogService;
import com.example.demo.vo.SysLogBasePageVo;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
/**
* @author lenovo
* @version 1.0
* @Date 2022/5/14 16:39
* @Description
*/
@Service
public class SysLogServiceImpl implements ISysLogService {
@Resource
private SysLogMapper sysLogMapper;
@Override
public void insertLog(SysLog sysLog) {
sysLogMapper.insert(sysLog);
}
@Override
public Page<SysLog> selectSysLogPage(SysLogBasePageVo sysLogBasePageVo) {
QueryWrapper<SysLog> sysLogQueryWrapper = new QueryWrapper<>();
if(StringUtils.isNotEmpty(sysLogBasePageVo.getSearchKey())) {
sysLogQueryWrapper.eq("title",sysLogBasePageVo.getSearchKey());
}
return sysLogMapper.selectPage(new Page<>(sysLogBasePageVo.getCurrentPage(),sysLogBasePageVo.getPageSize()),sysLogQueryWrapper);
}
}
9、Util工具类
package com.example.demo.util;
import javax.servlet.http.HttpServletRequest;
/**
* 获取IP地址
*/
public class IpUtils
{
public static String getIpAddr(HttpServletRequest request)
{
if (request == null)
{
return "unknown";
}
String ip = request.getHeader("x-forwarded-for");
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
{
ip = request.getHeader("Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
{
ip = request.getHeader("X-Forwarded-For");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
{
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
{
ip = request.getHeader("X-Real-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
{
ip = request.getRemoteAddr();
}
return "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : "";
}
}
package com.example.demo.util;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
/**
* @author lenovo
* @version 1.0
* @Date 2022/5/14 16:31
* @Description
*/
@Component
public class SpringUtils implements BeanFactoryPostProcessor, ApplicationContextAware {
/**
* Spring 应用上下文
*/
private static ConfigurableListableBeanFactory beanFactory;
private static ApplicationContext applicationContext;
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
SpringUtils.beanFactory = configurableListableBeanFactory;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
SpringUtils.applicationContext = applicationContext;
}
/**
* 获取对象
*
* @param name 名称
* @param <T> 定义的泛型类型
* @return
*/
public static <T> T getBean(String name) {
return (T) beanFactory.getBean(name);
}
/**
* 根据类获取到bean对象
* @param clz 类对象
* @param <T> 定义泛型类型
* @return
*/
public static <T> T getBean(Class<T> clz) {
T result = (T) beanFactory.getBean(clz);
return result;
}
}
10、vo 对象
package com.example.demo.vo;
import lombok.Data;
/**
* @author zhangyang
* @version 1.0
* @Date 2022/5/14 17:09
* @Description 基础分页查询vo对象
*/
@Data
public class BasePageVo {
/**
* 页面大小
*/
Integer pageSize;
/**
* 页码
*/
Integer currentPage;
/**
* 总页数
*/
Integer pages;
}
package com.example.demo.vo;
import lombok.Data;
/**
* @author zhangyang
* @version 1.0
* @Date 2022/5/14 17:08
* @Description
*/
@Data
public class SysLogBasePageVo extends BasePageVo {
/**
* 查询关键字
*/
String searchKey;
}
11、application.yml工具类
# 应用名称
spring.application.name=demo
# 应用服务 WEB 访问端口
server.port=8080
# 数据库驱动:
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
# 数据源名称
spring.datasource.name=defaultDataSource
# 数据库连接地址
spring.datasource.url=jdbc:mysql://localhost:3306/springboot?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
# 数据库用户名&密码:
spring.datasource.username=root
spring.datasource.password=root
SysLog 表结构
User 表结构
?
?
4、代码分析
? ?首先,定义了一个自定义注解Log,其目标范围为Method,只有在运行的时候才会保留,同时可以被javadoc工具类文档化。其代码中定义了 属性类型为String的属性名称为title ,
属性类型为BusinessType 属性名称为busniessType 默认值为INSERT , 属性类型为OperatorType 属性名称operatorTpye 默认值为 OperatorType.OTHER, 属性类型为boolean
?属性方法为isSaveRequestData? 默认值为true。
?然后controller 使用了这个注解
?@GetMapping("/selectAll")
?@Log(title = "用户查询",busninessType = BusinessType.SELECT)
最后,定义了LogAspect 切面类,
/**
* 配置了织入点,即要拦截使用了Log注解的方法
*/
@Pointcut("@annotation(com.example.demo.common.annnotaion.Log)")
public void logPointCut() {
}
? 拦截方法处理完后的请求
/**
*
* 处理完请求后执行
* @param joinPoint 切点
* @param jsonResult 返回的信息
*/
@AfterReturning(poincut = "logPointCut()", returning="jsonResult")
public void doAfterReturning(JoinPoint joinPoint, Object jsonResult) {
handleLog(joinPoint, null, jsonResult);
}
拦截方法被抛出异常的请求?
/*
*
* @param joinPoint 切点
* @param e 异常信息
* @param jsonResult 返回结果
*/
public void doAfterThrowing(JoinPoint joinPoint,Exception ex) {
handleLog(joinPoint,ex,null);
}
?封装方法并保存到数据库中
/**
* 处理完请求之后执行
*
* @param joinPoint 切点
* @param e 异常信息
* @param jsonResult 返回结果
*/
protected void handleLog(final JoinPoint joinPoint, final Exception e, Object jsonResult) {
Log controllerLog = getAnnotationLog(joinPoint);
if (controllerLog == null) {
return;
}
SysLog sysLog = new SysLog();
sysLog.setStatus(BusinessStatus.SUCCESS.ordinal());
// 请求的地址
RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
ServletRequestAttributes requestAttributes = (ServletRequestAttributes) attributes;
String ip = IpUtils.getIpAddr(requestAttributes.getRequest());
sysLog.setOperIp(ip);
// 返回参数
sysLog.setOperUrl(requestAttributes.getRequest().getRequestURI());
sysLog.setOperName("zhangyang");
if (e != null) {
sysLog.setStatus(BusinessStatus.FAIL.ordinal());
sysLog.setErrorMsg(StringUtils.substring(e.getMessage(), 0, 2000));
}
// 设置方法名称
String className = joinPoint.getTarget().getClass().getName();
String methodName = joinPoint.getSignature().getName();
sysLog.setMethod(className + "." + methodName + "()");
sysLog.setOperLocation(sysLog.getOperIp());
// 设置请求方式
sysLog.setRequestMethod(requestAttributes.getRequest().getMethod());
getControllerMethodDescription(joinPoint, controllerLog, sysLog);
// 保存到数据库
SpringUtils.getBean(ISysLogService.class).insertLog(sysLog);
}
/**
* 获取注解中对方法的描述信息,用于controller层注解
*
* @param joinPoint 切点
* @param log 日志
* @param sysLog 数据库操作日志对象
*/
public void getControllerMethodDescription(JoinPoint joinPoint, Log log, SysLog sysLog) {
// 设置action动作
sysLog.setBusinessType(log.businessType().ordinal());
// 设置标题
sysLog.setTitle(log.title());
// 设置操作人的类别
sysLog.setOperatorType(log.operatorType().ordinal());
// 是否需要保存request 参数和 值
if (log.isSaveRequestData()) {
setRequestValue(joinPoint, sysLog);
}
}
读取请求中的参数并放到log中?
/**
* 获取的请求参数,放到log中
* @param joinPoint 切点
* @param sysLog 操作日志
*/
private void setRequestValue(JoinPoint joinPoint,SysLog sysLog) {
String requestMethod = sysLog.getRequestMethod();
if(HttpMethod.PUT.name().equals(requestMethod) || HttpMethod.POST.name().equals(requestMethod)) {
String params = argsArrayString(joinPoint.getArgs());
sysLog.setOperParam(StringUtils.substring(params,0,2000));
} else {
// 请求的地址
RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
ServletRequestAttributes requestAttributes = (ServletRequestAttributes) attributes;
Map<?,?> paramsMap = (Map<?,?>) requestAttributes.getRequest().getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE);
sysLog.setOperParam(StringUtils.substring(paramsMap.toString(),0,2000));
}
}
将参数转化为json?
/**
* 参数转化成Json字符串
* @param paramsArray 参数对象
* @return
*/
private String argsArrayString(Object[] paramsArray) {
String param = "";
if(paramsArray != null && paramsArray.length > 0) {
for(int i=0; i<paramsArray.length; i++) {
if(StringUtils.isNotEmpty(paramsArray[i].toString())) {
Object object = JSON.toJSON(paramsArray[i]);
param += object.toString() + "";
}
}
}
return param;
}
/**
* 是否存在注解,如果存在就获取
*
* @param joinPoint 切点
* @return 注解对象
*/
private Log getAnnotationLog(JoinPoint joinPoint) {
Signature signature = joinPoint.getSignature();
MethodSignature methodSignature = (MethodSignature) signature;
Method method = methodSignature.getMethod();
if (method != null) {
return method.getAnnotation(Log.class);
}
return null;
}
5、实现结果
? 运行起项目,地址栏访问?http://localhost:8080/user/selectAll
? 这时候就会发现数据库表sys_log 就会新增一条记录
6、总结
? 记录请求日志功能主要是用切面知识,
?切面主要支持5种类型的通知注解:
? ? ? ? @Before 前置通知,在方法执行之前执行
? ? ? ? ?@After 后置通知,在方法执行之后执行
? ? ? ? @AfterRunning 返回通知,在方法返回结果之后执行
? ? ? ? @AfterThrowing 异常通知,在方法抛出异常之后
? ? ? ? ?@Around: 环绕通知
也就是,需要在核心业务前执行该辅助业务、在核心业务执行之后执行该辅助业务、在报错时候执行该辅助业务、在方法执行之前之后异常时执行该辅助业务
?@PointCut(value ="execution(* com.cn.spring.aspectj.NotVeryUsefulAspectService.*(...))")
其中表达式标签
?execution 用于匹配方法执行的连接点
args(): 用于匹配当前执行的方法传入的参数为指定类型的执行方法
this(): 用于匹配当前AOP代理对象类型的执行方法,注意是AOP代理对象类型的配置,这样就可能包括引入接口也类型匹配;
target(): 用于匹配当前目标对象类型的执行方法,注意是目标对象的类型匹配,这样就不包括引入接口也类型匹配;
within(): 用于匹配指定类型内的方法执行;
@args(): 用于匹配当前执行的参数
如 this(com.test.spring.aop.pointcutexp.Intf) 实现Intf 接口的所有类,如果Intf不是接口,限定Intf单个类
@target(org.springframework.transaction.annotation.Transactional) 带有@Transactional 标注的所有类的任意方法
@args(org.springframework.transation.annotation.Transational) 参数带有@Transational 标注的方法
args(String) 参数为String 类型的方法,
args(java,io.serializable,...)? 任何一个以接受“传入参数类型为java.io.serializable”开头,且其后可跟任意个任意类型的参数的方法执行,args 指定的参数类型是在运行时动态匹配的
第二个就是使用手动获取Spring的bean对象
package com.example.demo.util;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
/**
* @author lenovo
* @version 1.0
* @Date 2022/5/14 16:31
* @Description
*/
@Component
public class SpringUtils implements BeanFactoryPostProcessor, ApplicationContextAware {
/**
* Spring 应用上下文
*/
private static ConfigurableListableBeanFactory beanFactory;
private static ApplicationContext applicationContext;
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
SpringUtils.beanFactory = configurableListableBeanFactory;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
SpringUtils.applicationContext = applicationContext;
}
/**
* 获取对象
*
* @param name 名称
* @param <T> 定义的泛型类型
* @return
*/
public static <T> T getBean(String name) {
return (T) beanFactory.getBean(name);
}
/**
* 根据类获取到bean对象
* @param clz 类对象
* @param <T> 定义泛型类型
* @return
*/
public static <T> T getBean(Class<T> clz) {
T result = (T) beanFactory.getBean(clz);
return result;
}
}
|