加入切面环绕通知实现,日志比较完善的使用方式
1,配置好相应的日志框架,在需要的地方手动打日志(消费端,服务端都如此配置)
1、添加依赖包logback使用需要和slf4j一起使用,所以总共需要添加依赖的包有slf4j-api
logback使用需要和slf4j一起使用,所以总共需要添加依赖的包有slf4j-api.jar,logback-core.jar,logback-classic.jar,logback-access.jar这个暂时用不到所以不添加依赖了,maven配置
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<logback.version>1.1.7</logback.version>
<slf4j.version>1.7.21</slf4j.version>
</properties>
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>${logback.version}</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>${logback.version}</version>
</dependency>
</dependencies>
2、logback.xml配置
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false">
<!--定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径-->
<property name="LOG_HOME" value="/home" />
<!-- 控制台输出 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
</encoder>
</appender>
<!-- 按照每天生成日志文件 -->
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!--日志文件输出的文件名-->
<FileNamePattern>${LOG_HOME}/TestWeb.log.%d{yyyy-MM-dd}.log</FileNamePattern>
<!--日志文件保留天数-->
<MaxHistory>30</MaxHistory>
</rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
</encoder>
<!--日志文件最大的大小-->
<triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
<MaxFileSize>10MB</MaxFileSize>
</triggeringPolicy>
</appender>
<!-- 日志输出级别 -->
<root level="INFO">
<appender-ref ref="STDOUT" />
</root>
</configuration>
3、java代码
/**
* Hello world!
*/
public class App {
private final static Logger logger = LoggerFactory.getLogger(App.class);
public static void main(String[] args) {
logger.info("logback 成功了");
logger.error("logback 成功了");
logger.debug("logback 成功了");
}
}
参考:
https://www.cnblogs.com/warking/p/5710303.html
2,在1的基础上,配置切面---》利用切面,环绕通知,自动拦截,
一般用来打印请求,参数,返回结果(不是拦截器)
这种可以弥补1中设点不够的问题,让临时调试不需要不断点
这个LogAopAspect就是切面,在这里将通知植入定义好的切点
@Component将类纳入spring,@Aspect注解定义切面,需要定义xml启动注解的扫描
@Pointcut定义切点(程序正常方法)
@Around 定义通知,这里通知植入切点(通知修饰的方法)
消费端:
package com.houbank.incoming.web.interceptor;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.alibaba.druid.support.spring.mvc.StatHandlerInterceptor;
import com.alibaba.fastjson.JSON;
/**
*
* <p>自定义日志拦截类</p>
* @author houzhanshan
* @version $Id: LogAopAspect.java, v 0.1 2017年6月5日 上午10:08:19 Exp $
*/
@Component
@Aspect
public class LogAopAspect {
public static final String REQUESTIP = "requestIp";
public static final String REQUESTPORT = "requestPort";
public static final String REQUESTURI = "requestUri";
public static final String REQUESTTYPE = "requestType";
public static final String REQUEST_PARAM = "param";
@Pointcut("execution(* com.houbank.incoming.web.controller..*(..)) and @within(org.springframework.web.bind.annotation.Controller)")
private void anyAcesssAndResponseMethdod() {
}
@Autowired
private HttpServletRequest request;
@Around("anyAcesssAndResponseMethdod()")
public Object notifyLog(ProceedingJoinPoint joinPoint) throws Throwable {
Object returnObj = null;
if (joinPoint.getArgs().length > 0) {
Map<String, Object> paramMap = new HashMap<>();
paramMap.put(REQUESTIP, request.getServerName());
paramMap.put(REQUESTPORT, String.valueOf(request.getServerPort()));
paramMap.put(REQUESTURI, request.getRequestURI());
paramMap.put(REQUESTTYPE, request.getMethod());
paramMap.put(REQUEST_PARAM, JSON.toJSONString(request.getParameterMap()));
LogUtils.accessLog.info("请求request" + JSON.toJSONString(paramMap));
returnObj = joinPoint.proceed();//植入的切点
if (returnObj != null) {
LogUtils.accessLog.info("返回response" + JSON.toJSONString(returnObj));
}
return returnObj;
} else {
Map<String, Object> paramMap = new HashMap<>();
paramMap.put(REQUESTIP, request.getServerName());
paramMap.put(REQUESTPORT, String.valueOf(request.getServerPort()));
paramMap.put(REQUESTURI, request.getRequestURI());
paramMap.put(REQUESTTYPE, request.getMethod());
LogUtils.accessLog.info("返回request" + JSON.toJSONString(paramMap));
returnObj = joinPoint.proceed();
if (returnObj != null) {
LogUtils.accessLog.info("返回response" + JSON.toJSONString(returnObj));
}
}
return returnObj;
}
static class AccessLog {
private static Logger logger;
public static Logger getLogger(String name) {
logger = LoggerFactory.getLogger(name);
return logger;
}
}
}
xml
配置切面注解扫描:
<?xml version="1.0" encoding="UTF-8"?>
<!--
代理配置
-->
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 拦截器 --><!-- 启动对@AspectJ注解的支持 -->
<aop:aspectj-autoproxy/>
</beans>
服务端:
@Component纳入spring管理,@Aspect定义切面,xml需配置切面的扫描
@Pointcut定义切点
@Before 前置通知,@AfterReturning后置通知
package com.houbank.incoming.service.log;
import java.lang.reflect.Method;
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.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import lombok.extern.slf4j.Slf4j;
@Aspect
@Component
@Slf4j
public class LogAspect {
@Pointcut("execution(* com.houbank.incoming.service.impl.*.*(..))")
public void methodPointcut() {}
@Before("methodPointcut()")
public void before(JoinPoint joinPoint) {
Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
//查询不记录日志
if(method.getName().startsWith("select") || method.getName().startsWith("get") || method.getName().startsWith("query")) {
return;
}
StringBuilder sb = new StringBuilder();
sb.append(method.getDeclaringClass().getSimpleName()).append(".").append(method.getName()).append(" req:");
for(int i = 0; i < joinPoint.getArgs().length; i++) {
sb.append(joinPoint.getArgs()[i]);
}
log.info(sb.toString());
}
@AfterReturning(returning="rvt", pointcut="methodPointcut()")
public void after(JoinPoint joinPoint, Object rvt) {
Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
//查询不记录日志
if(method.getName().startsWith("select") || method.getName().startsWith("get") || method.getName().startsWith("query")) {
return;
}
log.info(method.getDeclaringClass().getSimpleName() + "."+ method.getName() + " resp:" + rvt);
}
}
xml配置:
<!-- 启动对@AspectJ注解的支持 -->
<aop:aspectj-autoproxy proxy-target-class="true"/>
相关推荐
本项目"使用切面的方式记录日志springMvc + hibernate"正是结合了Spring MVC的Web层处理、Spring AOP的日志管理和Hibernate的持久化操作,让我们一起深入探讨这些关键知识点。 首先,**Spring MVC**是Spring框架的...
本文将深入探讨“基于切面的日志记录SSMdemo”,这是一个结合了Spring、SpringMVC和MyBatis框架,并利用AOP(面向切面编程)实现日志功能的简单学习案例。 首先,我们来了解SSM框架。SSM是Spring、SpringMVC和...
本项目“Spring MVC Mybatis Plus 实现AOP 切面日志系统”旨在提供一个基础的日志记录框架,能够自动追踪和记录应用程序的关键操作,同时支持数据持久化到数据库中,方便后期分析和问题排查。下面将详细介绍这些技术...
Spring AOP提供了三种实现方式:代理模式、AspectJ切面和注解驱动的切面。 1. **代理模式** Spring AOP的基础是动态代理,它可以创建目标对象的代理对象来实现切面功能。有两种代理方式:JDK动态代理和CGLIB代理。...
对于所有需要进行日志记录的方法的采用对该方法所在的类进行动态代理的方式处理。在代理方法中的在原有方法的前后新增日志记录,动态代理采用装饰器模式实现通常称为AOP,AOP方面的内容请参阅: ...
但如果需要实现自定义的切面或中间件服务,理解AOP的概念和Spring的实现方式至关重要。 总而言之,Java切面和通知是Spring框架中的重要组成部分,它们提供了对系统级服务的声明式处理,简化了代码并提升了代码的可...
本篇文章将深入探讨Java和Kotlin中的注解使用及切面实现方式。 ### Java 注解 Java注解是一种元数据,它提供了在源代码中添加信息的方式,这些信息可以在编译时或运行时被解析。Java标准库中提供了多种内置注解,...
面向切面编程(AOP,Aspect Oriented Programming)是一种编程范式,主要目的是将系统中的关注点分离,比如日志记录、事务管理等通用功能,从核心业务逻辑中解耦出来。在Java领域,Spring框架提供了强大的AOP支持,...
在IT行业中,Spring AOP(Aspect Oriented Programming,面向切面编程)是Spring框架的核心特性之一,它使得我们能够以一种声明式的方式处理系统中的横切关注点,如日志记录、事务管理、性能监控等。这个“spring-...
在Spring框架中,AOP(面向切面编程)是一种强大的工具,它允许我们在不修改源代码的情况下,对程序进行横向关注点的插入,比如日志记录、事务管理、权限检查等。在这里,我们重点关注如何利用Spring AOP实现分层...
本篇将详细探讨如何使用切入点匹配方法实现Spring AOP的环绕通知。 首先,理解AOP的核心概念: 1. 切面(Aspect):切面是关注点的模块化,它封装了横切关注点,如日志、事务等。 2. 连接点(Join Point):程序...
- **通知(Advice)**:是切面在特定连接点(Join Point)执行的代码,可以是前置通知(Before)、后置通知(After)、返回通知(After Returning)、异常通知(After Throwing)和环绕通知(Around)。 - **连接...
1.只需要在controller层增加自定义@RequestLog注解就可以实现了。 @RequestLog功能参数如下: 功能一:是否记录请求参数 功能二:是否记录请求日志 功能三:是否记录返回值 功能四:是否以debug形式记录 功能五:日志类型 ...
假设我们要实现一个简单的日志记录功能,可以使用环绕通知记录方法的执行时间: ```java @Aspect public class LoggingAspect { @Around("execution(* com.example.service.*.*(..))") public Object ...
Spring框架是实现AOP的一个流行工具,它提供了两种主要的AOP实现方式:基于代理的AOP(Proxy-based AOP)和基于注解的AOP(Annotation-based AOP)。 1. **基于代理的AOP** 这种方式是Spring最早提供的AOP支持,它...
总的来说,JDK动态代理机制提供了一种轻量级的面向切面编程实现方式,它无需额外的框架支持,仅依赖Java标准库,适用于简单的AOP场景。然而,对于更复杂的切面需求,如类级别的代理或静态方法的拦截,可能需要借助...
在Spring框架中,AOP(面向切面编程)是一种强大的设计模式,它允许开发者定义“切面”,这些切面可以封装代码中横切关注点,如日志、事务管理、性能监控等。环绕通知是Spring AOP的一个重要概念,它是对方法调用...
本节将详细介绍如何使用Spring AOP实现流程日志跟踪,主要关注于如何通过AOP拦截特定的类和方法来进行日志记录。 ##### 3.1 配置Spring AOP 在Spring配置文件中定义切面和切入点表达式是非常关键的一步。一般来说...
在上述例子中,`MyInvocationHandler`实现了`invoke`方法,它在调用目标方法前后分别添加了日志记录的切面逻辑。`Main`类创建了一个`Service`接口的代理对象,并通过这个代理对象调用了`execute`方法,实现了AOP的...