加入切面环绕通知实现,日志比较完善的使用方式
加入切面环绕通知实现,日志比较完善的使用方式
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"/>