日志打印两次(问题)

今天碰到了一个日志被打印两次的问题

Configuration类

/**
 * 配置文件信息
 * @author Administrator
 *
 */
public class Configuration {

private static Logger LOG = Logger.getLogger(Configuration.class);

/**
* 文件路径(备用 当前信息刷新到本地)
*/
public static String filePath = null;
/**
* 键值对
*/
private static Properties prop = null;
/**
* 静态构造函数
*/
static{
if(prop==null){
readConfiguration();
}
}
/**
* 默认构造函数
*
*/
public Configuration(){
if(prop==null){
readConfiguration();
}

}
/**
* prop
* @return
*/
public Properties getProperties(){
return prop;
}
/**
* 获取值
* @param key
* @return
*/
public String getValue(String key){
if(key!=null&&!key.equals("")){
return prop.getProperty(key);
}
return null;
}
/**
* 获取值
* @param key
* @return
*/
public String getValue(String key,String defaultVaule){
if(key!=null&&!key.equals("")){
return prop.getProperty(key,defaultVaule);
}
return null;
}
/**
* 读取配置信息

* @return
*/
private static synchronized void readConfiguration() {
/**
* 读取dataexchange.properties文件
*/
InputStream in = null;
Properties p = null;
try {
URL url = DEUtil.class.getResource(Constants.CONFIG_FILE_NAME);
if(url!=null){
filePath = java.net.URLDecoder.decode(url.getPath(),"utf-8");
LOG.info(filePath);
in = url.openStream();
}else{
in = DEUtil.class.getResourceAsStream(Constants.CONFIG_FILE_NAME);
}
p = new Properties();
if(p!=null){
p.load(in);
}else{
throw new NullPointerException();
}
} catch (FileNotFoundException e2) {
// TODO Auto-generated catch block
e2.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally{
try {
if(in!=null){
in.close();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if (p != null) {
prop = p;
}else{
throw new NullPointerException();
}
}
/**
* 刷新键值对到本地文件
*
*/
public synchronized void porpertiesFlushBack(){
if(prop!=null){
//文件输出流 
OutputStream fos = null;
try {
fos = new FileOutputStream(Configuration.filePath);
//将Properties集合保存到流中
prop.store(fos, "Copyright (c) dlmu 233"); 
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally{
try {
if(fos!=null){
fos.close();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}else{
throw new NullPointerException();
}
}
}


还有一个工具类:DEUtil(贴部分代码)

/**
 * 数据交换工具类
 * 
 * @author Administrator
 * 
 */
public class DEUtil {
/**
* 配置信息
*/
private static Configuration conf = new Configuration();

。。。。。省略部分代码

}

还有一个入口:DataExchangeClient

/**
 * 数据交换客户端
 * @author Administrator
 *
 */
public class Client {

private static Logger LOG = Logger.getLogger(Client .class);
/**
* 配置信息
*/
private Configuration conf = null;
/**
* @param args
* @author Administrator
*/
public static void main(String[] args){
/** 创建客户端实例 */
Client client = new Client ();
client.run();
}
/**
* 初始化函数

*/
private void initial(){
this.conf = new Configuration();

}
/**
* 默认构造函数
*
*/
public Client () {
initial();
}

}


整个执行下来会出现打印两次日志 就是红色的地方执行了两次


整个过程都是单线程


暂时还不知道怎么解释(望有人能指点下 谢谢)



### 日志打印的实现方法与配置教程 #### 一、Spring Boot 中的日志打印 在 Spring Boot 应用程序中,可以通过多种方式实现 SQL 查询日志和接口调用日志打印。以下是两种常见的实现方式: 1. **SQL 查询日志打印** 在 `application.properties` 文件中添加如下配置即可启用 MyBatis 的 SQL 打印功能[^3]: ```properties # 启用 MyBatis SQL 日志 mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl # 如果使用 JPA,则可以设置 Hibernate 的日志级别 spring.jpa.show-sql=true spring.jpa.properties.hibernate.format_sql=true logging.level.org.hibernate.SQL=DEBUG logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE ``` 2. **接口调用日志打印 (AOP 方式)** 使用 AOP 切面技术捕获接口调用并记录参数和返回值。以下是一个简单的切面类示例[^1]: ```java @Aspect @Component public class LoggingAspect { private static final Logger logger = LoggerFactory.getLogger(LoggingAspect.class); @Around("execution(* com.example.controller.*.*(..))") public Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable { long start = System.currentTimeMillis(); try { return joinPoint.proceed(); } finally { long elapsedTime = System.currentTimeMillis() - start; StringBuilder sb = new StringBuilder(); sb.append(joinPoint.getTarget().getClass().getSimpleName()) .append(".") .append(joinPoint.getSignature().getName()); logger.info("{} executed with arguments {} and took {} ms", sb.toString(), Arrays.toString(joinPoint.getArgs()), elapsedTime); } } } ``` #### 二、Django 中的服务端 API 日志记录 对于 Django 框架,通常通过自定义中间件来记录服务端 API 请求和响应数据。下面展示了一个典型的中间件实现[^2]: ```python class APILogMiddleware: def __init__(self, get_response): self.get_response = get_response def __call__(self, request): import json from django.http import JsonResponse method = request.method path = request.path user = getattr(request.user, 'username', 'Anonymous') response = self.get_response(request) status_code = response.status_code content_type = response['Content-Type'] data = {} if 'json' in content_type.lower(): data = json.loads(response.content.decode('utf-8')) message = f"{method} {path} by {user}: Response Code={status_code}, Data={data}" print(message) # 替换为实际日志记录逻辑 return response ``` #### 三、Shiro 请求拦截与日志打印 Apache Shiro 是一种强大的安全框架,在其中也可以轻松实现请求拦截以及日志记录的功能。然而需要注意的是,当尝试读取 HTTP 请求体时可能会遇到异常[^4]。 解决此问题的一种方法是对原始 ServletRequest 进行封装处理,以便多次访问输入流内容: ```java public class MultiReadHttpServletRequest extends HttpServletRequestWrapper { private byte[] requestBody; public MultiReadHttpServletRequest(HttpServletRequest request) throws IOException { super(request); requestBody = IOUtils.toByteArray(request.getInputStream()); } @Override public BufferedReader getReader() throws IOException { return new BufferedReader(new InputStreamReader(getInputStream())); } @Override public ServletInputStream getInputStream() throws IOException { ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(requestBody); return new DelegatingServletInputStream(byteArrayInputStream); } } ``` 随后可以在过滤器链中替换默认的 Request 对象实例。 --- ### 总结 以上分别介绍了基于不同框架下的日志打印解决方案,包括但不限于 Spring Boot 的 AOP 和 MyBatis 配置、Django 自定义中间件以及 Apache Shiro 的请求重写机制。每种方案均提供了详细的代码片段供参考实施。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值