泥瓦匠又和大家見面了,最近兩天我在code review ,
順便代碼小小的refactoring(重構)下。先了解這個項目吧,這次解決的是資料源配置優化。因為這web項目中配置資料源的地方很多。例如
jdbc要配置資料源,mybatis要配置資料源,quartz定時任務要配置資料源,還有log4j存記錄到資料庫也要配置…
如題目,興許大家的疑惑看了前面的說明會明白。這次給大家帶來的 資料源配置與優化:log4j 配置資料庫連接配接池druid。
提綱:
二、準備知識
三、正文 開始動手吧
、配置檔案
、建資料表
、核心代碼講解
四、結論及下載下傳
泥瓦匠也是怕自己說不清楚,又不想把log4j 和 durid介紹個遍。那樣會太麻煩。這次主要是項目實戰。是以泥瓦匠也不羅嗦知識準備這塊也就是點到為止。
log4j 簡介
在應用程式中添加日志記錄總的來說基于三個目的:
監視代碼中變量的變化情況,周期性的記錄到檔案中供其他應用進行統計分析工作;
跟蹤代碼運作時軌迹,作為日後審計的依據;
擔當內建開發環境中的調試器的作用,向檔案或控制台列印代碼的調試資訊。
它支援将日志資訊輸入到資料庫,這次我們一mysql為例說明。我們需要log4j來将調試資訊、操作資訊等記錄下來,以便後面的審計,這些日志資訊包括使用者id、使用者姓名、操作類、路徑、方法、操作時間、日志資訊。
druid 簡介
泥瓦匠的任務很簡單,目的是為了資料源配置優化,實作資料源配置的唯一性。泥瓦匠也畫了草圖,曾經被人說成畫圖畫出鬼畫符的我告訴大家:沒事,越做越好。如圖,設計簡單草圖就是這樣的。

結論:一個項目的配置檔案要保持唯一性,就是資料源配置的唯一性。
開始弄吧,為了寫這個東西。我就也搞了個demo項目。泥瓦匠很辛苦的,哈哈送錢的上面支付寶哦。哈哈,泡了杯水,準備說這個項目了。下面,泥瓦匠先給出這個項目的結構圖,這樣我待會講起來不怎麼累。邏輯性比較強吧。如圖:
上面很清楚的寫着我需要完成的功能子產品。最後那個test,是一個測試的servlet類。大家一看就明白。我先從配置檔案說起吧。
配置檔案 :
dbconfig.properties 記錄的是最基礎的db配置:url name psd 等,代碼如下:
1
2
3
4
5
6
7
8
<code>database.vendor = mysql</code>
<code>driverclassname= com.mysql.jdbc.driver</code>
<code>db_user = root</code>
<code>db_password = 123456</code>
<code>showsql= false</code>
<code>devmode = true</code>
<code>validationquery=select 1</code>
log4j.properties則是日志的配置,但日志的配置中有一點注意的是如下:
9
10
<code>log4j.rootlogger=debug,appender1</code>
<code>log4j.appender.appender1=org.apache.log4j.consoleappender</code>
<code>log4j.appender.appender1.layout=org.apache.log4j.ttcclayout</code>
<code>log4j.logger.test=info, db</code>
<code># log db setting</code>
<code>log4j.appender.db=org.nsg.dbsetting.myjdbcappender</code>
<code>log4j.appender.db.buffersize=1</code>
<code>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')</code>
<code>log4j.appender.db.layout=org.apache.log4j.patternlayout</code>
在這裡,我們要注意兩點:
一、設定我們包的下的logger權限,并給予存資料庫的權限。
二、db的實作的應用要為你寫的引用類。
建資料表 :
然後我們要根據上面配置檔案中寫的資料庫和表格我們要對應的建一個名為test的資料庫和一張名為operate_log的表。
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<code>/*</code>
<code>navicat mysql data transfer</code>
<code>source server : mysql</code>
<code>source server version : 50617</code>
<code>source host : localhost:3307</code>
<code>source database : test</code>
<code>target server type : mysql</code>
<code>target server version : 50617</code>
<code>file encoding : 65001</code>
<code>date: 2014-12-08 18:46:21</code>
<code>*/</code>
<code>set foreign_key_checks=0;</code>
<code>-- ----------------------------</code>
<code>-- table structure for operate_log</code>
<code>drop table if exists `operate_log`;</code>
<code>create table `operate_log` (</code>
<code> </code><code>`log_id` int(11) not null auto_increment,</code>
<code> </code><code>`handclass` varchar(100) default null,</code>
<code> </code><code>`method` varchar(100) default null,</code>
<code> </code><code>`createtime` varchar(100) default null,</code>
<code> </code><code>`loglevel` varchar(20) default null,</code>
<code> </code><code>`logmsg` text,</code>
<code> </code><code>primary key (`log_id`)</code>
<code>) engine=innodb auto_increment=23 default charset=utf8;</code>
這樣我們就可以開始寫代碼了,泥瓦匠是一個很細節的人。這次部落格,我主要是講下代碼中的核心點。因為後面我會把項目提供給你們下載下傳。是以,這裡點到為止。
泥瓦匠說:點到為止,所謂師父領進門,修行在個人啊。
核心代碼講解:
myjdbcappender.java
用于log4j的資料庫session管理[連接配接池用druid]。這個肯定是我們得核心思想。這裡我就繼承了log4j提供的
org.apache.log4j.jdbc.jdbcappender;然後隻要簡單的重寫了closeconnection和
getconnection方法。如果擷取druid資料庫源對象異常的話,我還寫了個 取消初始化
的方法uninitialize。代碼這邊也貼出下,友善大家觀看:
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
<code>package org.nsg.dbsetting;</code>
<code>import java.sql.connection;</code>
<code>import java.sql.sqlexception;</code>
<code>import java.util.properties;</code>
<code>import org.apache.log4j.jdbc.jdbcappender;</code>
<code>import org.apache.log4j.spi.errorcode;</code>
<code>import org.nsg.constant.propertiesconst;</code>
<code>import org.nsg.exception.jdbcexception;</code>
<code>import org.nsg.util.myproperties;</code>
<code>import org.nsg.util.propertiesutil;</code>
<code>import com.alibaba.druid.pool.druiddatasource;</code>
<code>import com.alibaba.druid.pool.druiddatasourcefactory;</code>
<code>/**</code>
<code> </code><code>* @description myjdbcappender.java</code>
<code> </code><code>* 用于log4j的資料庫session管理[連接配接池用druid]</code>
<code> </code><code>* @author 泥沙磚瓦漿木匠</code>
<code> </code><code>* @date 2014年12月7日下午1:50:56</code>
<code> </code><code>* @version 1.0</code>
<code> </code><code>*/</code>
<code>public class myjdbcappender extends jdbcappender</code>
<code>{</code>
<code> </code><code>/* druid資料源 */</code>
<code> </code><code>private druiddatasource datasource;</code>
<code> </code>
<code> </code><code>public myjdbcappender()</code>
<code> </code><code>{</code>
<code> </code><code>super();</code>
<code> </code><code>}</code>
<code> </code><code>@override</code>
<code> </code><code>protected void closeconnection(connection con)</code>
<code> </code><code>try</code>
<code> </code><code>{</code>
<code> </code><code>/* 如果資料庫連接配接對象不為空和沒有被關閉的話,關閉資料庫連接配接 */</code>
<code> </code><code>if ( con != null && !con.isclosed())</code>
<code> </code><code>con.close();</code>
<code> </code>
<code> </code><code>}</code>
<code> </code><code>catch (sqlexception e)</code>
<code> </code><code>errorhandler.error("error closing myjdbcappender.closeconnection() 's connection",e,errorcode.generic_failure);</code>
<code> </code><code>protected connection getconnection() throws sqlexception</code>
<code> </code><code>/* 擷取資料庫配置property */</code>
<code> </code><code>myproperties properties = propertiesutil.loadpropertyfile(propertiesconst.db_config);</code>
<code> </code><code>string classname = string.valueof(properties.getproperty("driverclassname",""));</code>
<code> </code><code>string connurl = string.valueof(properties.getproperty("db_url",""));</code>
<code> </code><code>string uname = string.valueof(properties.getproperty("db_user",""));</code>
<code> </code><code>string psw = string.valueof(properties.getproperty("db_password",""));</code>
<code> </code><code>system.out.println(classname);</code>
<code> </code><code>system.out.println(connurl);</code>
<code> </code><code>system.out.println(uname);</code>
<code> </code><code>system.out.println(psw);</code>
<code> </code>
<code> </code><code>properties result = new properties();</code>
<code> </code><code>result.put("driverclassname",classname);</code>
<code> </code><code>result.put("url",connurl);</code>
<code> </code><code>result.put("username",uname);</code>
<code> </code><code>result.put("password",psw);</code>
<code> </code><code>/* 其他配置 自然你也可以自己寫property 然後擷取set */</code>
<code> </code><code>result.put("maxactive","30");</code>
<code> </code><code>result.put("minidle","3");</code>
<code> </code><code>datasource = (druiddatasource) druiddatasourcefactory.createdatasource(result);</code>
<code> </code><code>catch (exception e)</code>
<code> </code><code>/* druid資料庫源對象産生失敗後,取消初始化 */</code>
<code> </code><code>try {uninitialize();} catch(exception e2) {}</code>
<code> </code><code>throw new jdbcexception(e);</code>
<code> </code><code>return datasource.getconnection();</code>
<code> </code><code>/* 取消初始化 */</code>
<code> </code><code>public void uninitialize()</code>
<code> </code><code>if (datasource != null)</code>
<code> </code><code>datasource.close();</code>
<code> </code><code>throw new jdbcexception(string.format("myjdbcappender uninitialize fail (%s)",e));</code>
<code> </code><code>finally</code>
<code> </code><code>super.close();</code>
<code>}</code>
值得注意的一點是,泥瓦匠為了友善,是以在其中的地方沒有擷取druid連接配接池的配置。而是直接寫了下面:
<code>/* 其他配置 自然你也可以自己寫property 然後擷取set */</code>
其實這樣寫是不好了,我們可以寫一個druid.properties然後将連接配接池的配置放入其中。擷取set,for循環set即可。這邊我就不實作了。很簡單哦,泥瓦匠相信你們。
最後我示範下,示例代碼:放到tomcat7上,然後運作通路
看到控制台刷出來兩條資訊,因為我門設定的是log4j.logger.test=info, db。
然後我們去檢視資料庫,這邊我用navicat:
結論:重構很有意思,慢慢來,一點一點來,就行了。細節成就未來。