Spring AOP实现日志管理

本文介绍如何使用Spring框架的AOP思想和AspectJ实现Java项目的日志管理功能,包括设计日志表、自定义注解、编写切面和通知,以及在方法上添加注解进行日志记录。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在一些Web管理系统项目中,日志管理功能也常见,管理系统中日志主要是记录一些谁操作了什么东西,系统是否有异常等信息。那么如何在编程中实现呢?在Java面对对象语言中要实现日志管理功能时,是比较麻烦的。在此,引入了Spring框架中的AOP思想,AOP的主要作用是可以横向插入可重复代码(日志管理),在面向对象语言中是无法做到的,它是面向对象的一种延伸。而AspectJ是AOP的一个纯Java框架,而AspectJ实现AOP有两种方式(要添加相应jar包):一种是基于xml实现,另外一种是基于注解实现。实现日志管理是用基于注解来实现的,因为使用注解方式比较灵活。
在实现功能之前,首先要了解AOP相关的一些术语:
Aspect (切面):在实际应用中,切面通常是指封装的用于横向插入系统功能(如事务、日志等)的类。
Joinpoint (连接点):方法的调用。(调用要记录日志的方法)
Pointcut (切入点):通常是指类名、方法名或者方法上的注解(要记录日志的方法名或者方法上的注解)
Advice(通知/增强处理):可以将其理解为切面类中的方法,它是切面的具体实现(日志类实现方法)。
那么,该如何使用AspectJ基于注解来实现日志管理呢?
实现的大致思路是:
    1.设计日志表和日志类,编写日志Dao和Service以及实现
    2.自定义注解,注解中加入几个属性,属性可以标识操作的类型(方法是做什么的)
    3.编写切面,切点表达式使用上面的注解直接定位到使用注解的方法,
    4.编写通知,通过定位到方法,获取上面的注解以及注解的属性,然后从session中直接获取或者从数据库获取当前登录用户的信息,最后根据业务处理一些日志信息之后调用日志Service存储日志。

  1. 设计相关的日志表,编写相关的接口和接口实现类(Dao、Service)
    在这里插入图片描述
  2. 自定义日志注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface LogAnnotation {
	String operateType();//记录日志操作类型
}
  1. 编写切面类,注入service层的对象,配置切入点,该切入点是方法上的注解。日志管理使用的是@Around环绕通知,然后通过ProceedingJoinPoint对象来获取到方法(切入点),再通过该方法获取到方法上的注解,获取到注解里面的属性值(日志操作说明)。获取到用户信息,把相关值设置到Log对象中,然后执行ProceedingJoinPoint对象proceed()方法(连接点),然后包Log对象保存到数据库中。
    注意:如果涉及到事务或者自定义异常类还需要在切面类try…catch…捕获异常中的catch抛出异常,给上一级调用者处理,要不然会把异常处理掉,不能抛出。
@Aspect
@Component//声明一个bean
public class LogAspect {
	@Autowired
	private LogService logService;//日志service
	//切入点
	@Pointcut("@annotation(com.koi.annotation.LogAnnotation)")
	public void myPointcut(){}
	//环绕通知 使用@LogAnnotation注解的方法
	@Around("myPointcut()")
	public Object aroundAdvice(ProceedingJoinPoint  pjp) throws Throwable{
		Signature signature = pjp.getSignature();//获取方法签名
		Method method = ( (MethodSignature)signature ).getMethod();//获取方法
		 //这个方法才是目标对象上有注解的方法
		Method declaredMethod = pjp.getTarget().getClass().getDeclaredMethod(signature.getName(), method.getParameterTypes());
		LogAnnotation annotation = declaredMethod.getAnnotation(LogAnnotation.class);//获取方法上的LogAnnotation注解
		String operateType = annotation.operateType();//获取操作说明
		//获取操作用户信息
		Subject subject = SecurityUtils.getSubject();
		UUser user = (UUser)subject.getPrincipal();
		// 创建一个日志对象(准备记录日志)
		Log log=new Log();
		log.setOperateType(operateType);//操作说明
		log.setOperateor(user.getNickname());//设置操作人
		Object obj=null;
		try {
			obj=pjp.proceed();
			log.setOperateResult("操作成功");//设置操作状态
		} catch (CustomException e) {
			log.setOperateResult("操作失败");//设置操作状态
			throw e;//抛给自定义异常处理器处理
		}finally{
			log.setOperateDate(new Date());//设置当前时间
			logService.addLog(log);
		}
		return obj;
	}
}

在需要记录日志的方法(一般是Service实现类的方法)上添加自定义的日志注解@LogAnnotation

@LogAnnotation(operateType="修改密码")
	@Override
	public ResultInfo updatePassword(UUser user, String oldPassword)
			throws Exception {
		.....
	}

最后,在spring.xml容器中(父容器)添加 <aop:aspectj-autoproxy /> 配置,启动对aspectj的支持。
如果日志操作(自定义日志注解)可以在controller控制层方法中执行,该<aop:aspectj-autoproxy />还要配置在spring-mvc.xml容器(子容器)中。因为spring.xml与spring-mvc.xml是父子容器关系,父容器不可以访问到子容器的对象,而子容器可以访问到父容器的对象,但只是针对对象来说,而<aop:aspectj-autoproxy />该配置不是对象,只是开启对aspectj的支持。如果把该配置单单放在父容器中,控制层(spring-mvc.xml子容器)就对aspectj的不支持了,所以应该在父子容器都配置<aop:aspectj-autoproxy />。

### 使用 Spring AOP 实现日志记录 Spring AOP 是一种强大的工具,能够帮助开发者实现横切关注点的分离。通过使用 AOP 技术,可以轻松地在应用程序中实现日志记录功能,而无需修改核心业务逻辑代码。 #### 启用 AOP 支持 为了在项目中启用 AOP 功能,需要确保配置文件中启用了 AspectJ 自动代理支持。如果是在 Spring Boot 项目中,则可以通过添加 `@EnableAspectJAutoProxy` 注解来完成这一操作[^3]: ```java import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.EnableAspectJAutoProxy; @SpringBootApplication @EnableAspectJAutoProxy public class MyApplication { public static void main(String[] args) { SpringApplication.run(MyApplication.class, args); } } ``` #### 定义切面类 切面类是用来定义通知(Advice)的地方。下面是一个简单的例子,展示了如何创建一个用于日志记录的切面类[^1]: ```java 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.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; @Aspect @Component public class LoggingAspect { private final Logger logger = LoggerFactory.getLogger(this.getClass()); @Before("execution(* com.example.service.*.*(..))") public void logMethodEntry(JoinPoint joinPoint) { String methodName = joinPoint.getSignature().getName(); Object[] arguments = joinPoint.getArgs(); logger.info("Entering method: {} with arguments {}", methodName, arguments); } @AfterReturning(pointcut = "execution(* com.example.service.*.*(..))", returning = "result") public void logMethodExit(Object result) { logger.info("Exiting method with result: {}", result); } } ``` 上述代码片段中的 `LoggingAspect` 类被标记为 `@Aspect` 和 `@Component`,这意味着它会被 Spring 容器识别并自动注册为一个 Bean。该类中有两个主要的通知方法:一个是 `@Before` 方法,另一个是 `@AfterReturning` 方法。这两个方法分别会在目标方法执行前和执行后触发,并打印相应的日志信息[^2]。 #### 日志框架的选择 在这个示例中,选择了 SLF4J 作为日志框架。SLF4J 提供了一个抽象,使得切换底的日志实现变得非常容易。当然,也可以选择其他日志框架,比如 Log4j 或者 Java Util Logging[^4]。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值