作者:泥沙磚瓦漿木匠
網(wǎng)站:
http://blog.csdn.net/jeffli1993個(gè)人簽名:打算起手不凡寫出鴻篇巨作的人,往往堅(jiān)持不了完成第一章節(jié)。
交流QQ群:【編程之美 365234583】
http://qm.qq.com/cgi-bin/qm/qr?k=FhFAoaWwjP29_AonqzL0rpdQAjjqlHQQ如果我的幫到了你,是否樂意捐助一下或請(qǐng)一杯啤酒也好呢?有你支持,干的更好~
點(diǎn)這參與眾籌 我的支付寶:13958686678
一、 前言
泥瓦匠又和大家見面了,最近兩天我在Code Review ,順便代碼小小的Refactoring(重構(gòu))下。先了解這個(gè)項(xiàng)目吧,這次解決的是數(shù)據(jù)源配置優(yōu)化。因?yàn)檫@web項(xiàng)目中配置數(shù)據(jù)源的地方很多。例如JDBC要配置數(shù)據(jù)源,Mybatis要配置數(shù)據(jù)源,Quartz定時(shí)任務(wù)要配置數(shù)據(jù)源,還有Log4j存記錄到數(shù)據(jù)庫(kù)也要配置…
如題目,興許大家的疑惑看了前面的說(shuō)明會(huì)明白。這次給大家?guī)?lái)的 數(shù)據(jù)源配置與優(yōu)化:log4j 配置數(shù)據(jù)庫(kù)連接池Druid。
提綱:
二、準(zhǔn)備知識(shí)
三、正文 開始動(dòng)手吧
、配置文件
、建數(shù)據(jù)表
、核心代碼講解
四、結(jié)論及下載
二、準(zhǔn)備知識(shí)
泥瓦匠也是怕自己說(shuō)不清楚,又不想把Log4j 和 Durid介紹個(gè)遍。那樣會(huì)太麻煩。這次主要是項(xiàng)目實(shí)戰(zhàn)。所以泥瓦匠也不羅嗦知識(shí)準(zhǔn)備這塊也就是點(diǎn)到為止。
Log4j 簡(jiǎn)介
在應(yīng)用程序中添加日志記錄總的來(lái)說(shuō)基于三個(gè)目的:
監(jiān)視代碼中變量的變化情況,周期性的記錄到文件中供其他應(yīng)用進(jìn)行統(tǒng)計(jì)分析工作;
跟蹤代碼運(yùn)行時(shí)軌跡,作為日后審計(jì)的依據(jù);
擔(dān)當(dāng)集成開發(fā)環(huán)境中的調(diào)試器的作用,向文件或控制臺(tái)打印代碼的調(diào)試信息。
它支持將日志信息輸入到數(shù)據(jù)庫(kù),這次我們一Mysql為例說(shuō)明。我們需要Log4j來(lái)將調(diào)試信息、操作信息等記錄下來(lái),以便后面的審計(jì),這些日志信息包括用戶ID、用戶姓名、操作類、路徑、方法、操作時(shí)間、日志信息。
Druid 簡(jiǎn)介
Druid是Java語(yǔ)言中最好的數(shù)據(jù)庫(kù)連接池。Druid能夠提供強(qiáng)大的監(jiān)控和擴(kuò)展功能。不多多介紹了,阿里牛人作品必須精品。詳細(xì)介紹在:
https://github.com/alibaba/druid/wiki/%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98泥瓦匠的任務(wù)很簡(jiǎn)單,目的是為了數(shù)據(jù)源配置優(yōu)化,實(shí)現(xiàn)數(shù)據(jù)源配置的唯一性。泥瓦匠也畫了草圖,曾經(jīng)被人說(shuō)成畫圖畫出鬼畫符的我告訴大家:沒事,越做越好。如圖,設(shè)計(jì)簡(jiǎn)單草圖就是這樣的。
結(jié)論:一個(gè)項(xiàng)目的配置文件要保持唯一性,就是數(shù)據(jù)源配置的唯一性。
三、正文 開始動(dòng)手吧
開始弄吧,為了寫這個(gè)東西。我就也搞了個(gè)demo項(xiàng)目。泥瓦匠很辛苦的,哈哈送錢的上面支付寶哦。哈哈,泡了杯水,準(zhǔn)備說(shuō)這個(gè)項(xiàng)目了。下面,泥瓦匠先給出這個(gè)項(xiàng)目的結(jié)構(gòu)圖,這樣我待會(huì)講起來(lái)不怎么累。邏輯性比較強(qiáng)吧。如圖:
上面很清楚的寫著我需要完成的功能模塊。最后那個(gè)test,是一個(gè)測(cè)試的servlet類。大家一看就明白。我先從配置文件說(shuō)起吧。
配置文件 :
dbConfig.properties 記錄的是最基礎(chǔ)的db配置:url name psd 等,代碼如下:
1
2
3
4
5
6
7
8
database.vendor = mysql
db_url = jdbc:
driverClassName= com.mysql.jdbc.Driver
db_user = root
db_password = 123456
showsql= false
devMode = true
validationQuery=SELECT 1
log4j.properties則是日志的配置,但日志的配置中有一點(diǎn)注意的是如下:
1
2
3
4
5
6
7
8
9
10
log4j.rootLogger=debug,appender1
log4j.appender.appender1=org.apache.log4j.ConsoleAppender
log4j.appender.appender1.layout=org.apache.log4j.TTCCLayout
log4j.logger.test=INFO, db
# log db setting
log4j.appender.db=org.nsg.dbsetting.MyJDBCAppender
log4j.appender.db.BufferSize=1
log4j.appender.db.sql=insert into operate_log(handclass,method,createtime,loglevel,logmsg) values ('%C','%M','%d{yyyy-MM-dd HH\:mm\:ss}','%p','%m')
log4j.appender.db.layout=org.apache.log4j.PatternLayout
在這里,我們要注意兩點(diǎn):
一、設(shè)置我們包的下的logger權(quán)限,并給予存數(shù)據(jù)庫(kù)的權(quán)限。
二、db的實(shí)現(xiàn)的應(yīng)用要為你寫的引用類。
1
2
# log db setting
log4j.appender.db=org.nsg.dbsetting.MyJDBCAppender
建數(shù)據(jù)表 :
然后我們要根據(jù)上面配置文件中寫的數(shù)據(jù)庫(kù)和表格我們要對(duì)應(yīng)的建一個(gè)名為test的數(shù)據(jù)庫(kù)和一張名為operate_log的表。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
/*
Navicat MySQL Data Transfer
Source Server : Mysql
Source Server Version : 50617
Source Host : localhost:3307
Source Database : test
Target Server Type : MYSQL
Target Server Version : 50617
File Encoding : 65001
Date: 2014-12-08 18:46:21
*/
SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for operate_log
-- ----------------------------
DROP TABLE IF EXISTS `operate_log`;
CREATE TABLE `operate_log` (
`log_id` int(11) NOT NULL AUTO_INCREMENT,
`handclass` varchar(100) DEFAULT NULL,
`method` varchar(100) DEFAULT NULL,
`createtime` varchar(100) DEFAULT NULL,
`loglevel` varchar(20) DEFAULT NULL,
`logmsg` text,
PRIMARY KEY (`log_id`)
) ENGINE=InnoDB AUTO_INCREMENT=23 DEFAULT CHARSET=utf8;
這樣我們就可以開始寫代碼了,泥瓦匠是一個(gè)很細(xì)節(jié)的人。這次博客,我主要是講下代碼中的核心點(diǎn)。因?yàn)楹竺嫖視?huì)把項(xiàng)目提供給你們下載。所以,這里點(diǎn)到為止。
泥瓦匠說(shuō):點(diǎn)到為止,所謂師父領(lǐng)進(jìn)門,修行在個(gè)人啊。
核心代碼講解:
MyJDBCAppender.java 用于Log4j的數(shù)據(jù)庫(kù)Session管理[連接池用Druid]。這個(gè)肯定是我們得核心思想。這里我就繼承了log4j提供的org.apache.log4j.jdbc.JDBCAppender;然后只要簡(jiǎn)單的重寫了closeConnection和getConnection方法。如果獲取Druid數(shù)據(jù)庫(kù)源對(duì)象異常的話,我還寫了個(gè) 取消初始化 的方法uninitialize。代碼這邊也貼出下,方便大家觀看:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
package org.nsg.dbsetting;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;
import org.apache.log4j.jdbc.JDBCAppender;
import org.apache.log4j.spi.ErrorCode;
import org.nsg.constant.PropertiesConst;
import org.nsg.exception.JdbcException;
import org.nsg.util.MyProperties;
import org.nsg.util.PropertiesUtil;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.DruidDataSourceFactory;
/**
* @Description MyJDBCAppender.java
* 用于Log4j的數(shù)據(jù)庫(kù)Session管理[連接池用Druid]
* @author 泥沙磚瓦漿木匠
* @date 2014年12月7日下午1:50:56
* @version 1.0
*/
public class MyJDBCAppender extends JDBCAppender
{
/* Druid數(shù)據(jù)源 */
private DruidDataSource dataSource;
public MyJDBCAppender()
{
super();
}
@Override
protected void closeConnection(Connection con)
{
try
{
/* 如果數(shù)據(jù)庫(kù)連接對(duì)象不為空和沒有被關(guān)閉的話,關(guān)閉數(shù)據(jù)庫(kù)連接 */
if ( con != null && !con.isClosed())
con.close();
}
catch (SQLException e)
{
errorHandler.error("Error closing MyJDBCAppender.closeConnection() 's connection",e,ErrorCode.GENERIC_FAILURE);
}
}
@Override
protected Connection getConnection() throws SQLException
{
/* 獲取數(shù)據(jù)庫(kù)配置property */
MyProperties properties = PropertiesUtil.loadPropertyFile(PropertiesConst.DB_CONFIG);
String className = String.valueOf(properties.getProperty("driverClassName",""));
String connUrl = String.valueOf(properties.getProperty("db_url",""));
String uname = String.valueOf(properties.getProperty("db_user",""));
String psw = String.valueOf(properties.getProperty("db_password",""));
System.out.println(className);
System.out.println(connUrl);
System.out.println(uname);
System.out.println(psw);
Properties result = new Properties();
result.put("driverClassName",className);
result.put("url",connUrl);
result.put("username",uname);
result.put("password",psw);
/* 其他配置 自然你也可以自己寫property 然后獲取set */
result.put("maxActive","30");
result.put("minIdle","3");
try
{
dataSource = (DruidDataSource) DruidDataSourceFactory.createDataSource(result);
}
catch (Exception e)
{
/* Druid數(shù)據(jù)庫(kù)源對(duì)象產(chǎn)生失敗后,取消初始化 */
try {uninitialize();} catch(Exception e2) {}
throw new JdbcException(e);
}
return dataSource.getConnection();
}
/* 取消初始化 */
public void uninitialize()
{
try
{
if (dataSource != null)
dataSource.close();
}
catch (Exception e)
{
throw new JdbcException(String.format("MyJDBCAppender uninitialize fail (%s)",e));
}
finally
{
super.close();
}
}
}
值得注意的一點(diǎn)是,泥瓦匠為了方便,所以在其中的地方?jīng)]有獲取druid連接池的配置。而是直接寫了下面:
1
2
3
/* 其他配置 自然你也可以自己寫property 然后獲取set */
result.put("maxActive","30");
result.put("minIdle","3");
其實(shí)這樣寫是不好了,我們可以寫一個(gè)druid.properties然后將連接池的配置放入其中。獲取set,for循環(huán)set即可。這邊我就不實(shí)現(xiàn)了。很簡(jiǎn)單哦,泥瓦匠相信你們。
最后我演示下,示例代碼:放到tomcat7上,然后運(yùn)行訪問
看到控制臺(tái)刷出來(lái)兩條信息,因?yàn)槲议T設(shè)置的是log4j.logger.test=INFO, db。
然后我們?nèi)ゲ榭磾?shù)據(jù)庫(kù),這邊我用Navicat:
四、結(jié)論及下載
結(jié)論:重構(gòu)很有意思,慢慢來(lái),一點(diǎn)一點(diǎn)來(lái),就行了。細(xì)節(jié)成就未來(lái)。
下載鏈接:
http://pan.baidu.com/s/1hqKN0Le如以上文章或鏈接對(duì)你有幫助的話,別忘了在文章按鈕或到頁(yè)面右下角點(diǎn)擊 “贊一個(gè)” 按鈕哦。你也可以點(diǎn)擊頁(yè)面右邊“分享”懸浮按鈕哦,讓更多的人閱讀這篇文章