Python php Android centos 程序员 shell Windows wordpress apache google 云计算 linux 微软 编程 Ubuntu 开源 Firefox mysql java nginx

項目重構之數據源配置與優化:log4j 配置數據庫連接池Druid,並實現日誌存儲到數據庫

一、 前言

  泥瓦匠又和大家見面了,最近兩天我在Code Review , 順便代碼小小的Refactoring(重構)下。先了解這個項目吧,這次解決的是數據源配置優化。因為這web項目中配置數據源的地方很多。例如 JDBC要配置數據源,Mybatis要配置數據源,Quartz定時任務要配置數據源,還有Log4j存記錄到數據庫也要配置…

  如題目,興許大家的疑惑看了前面的說明會明白。這次給大家帶來的 數據源配置與優化:log4j 配置數據庫連接池Druid。

  提綱:

二、準備知識
三、正文 開始動手吧
     、配置文件
     、建數據表
     、核心代碼講解
四、結論及下載
二、準備知識

  泥瓦匠也是怕自己說不清楚,又不想把Log4j 和 Durid介紹個遍。那樣會太麻煩。這次主要是項目實戰。所以泥瓦匠也不羅嗦知識準備這塊也就是點到為止。

  Log4j 簡介
  在應用程序中添加日誌記錄總的來說基於三個目的:
    監視代碼中變量的變化情況,周期性的記錄到文件中供其他應用進行統計分析工作;
    跟蹤代碼運行時軌跡,作為日後審計的依據;
    擔當集成開發環境中的調試器的作用,向文件或控制臺打印代碼的調試信息。
  它支持將日誌信息輸入到數據庫,這次我們一mysql為例說明。我們需要Log4j來將調試信息、操作信息等記錄下來,以便後面的審計,這些日誌信息包括用戶ID、用戶姓名、操作類、路徑、方法、操作時間、日誌信息。

  Druid 簡介

  Druid是JAVA語言中最好的數據庫連接池。Druid能夠提供強大的監控和擴展功能。不多多介紹了,阿裏牛人作品必須精品。詳細介紹在:https://github.com/alibaba/druid/wiki/%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98

  泥瓦匠的任務很簡單,目的是為了數據源配置優化,實現數據源配置的唯一性。泥瓦匠也畫了草圖,曾經被人說成畫圖畫出鬼畫符的我告訴大家:沒事,越做越好。如圖,設計簡單草圖就是這樣的。

image

結論:一個項目的配置文件要保持唯一性,就是數據源配置的唯一性。

三、正文 開始動手吧

  開始弄吧,為了寫這個東西。我就也搞了個demo項目。泥瓦匠很辛苦的,哈哈送錢的上面支付寶哦。哈哈,泡了杯水,準備說這個項目了。下面,泥瓦匠先給出這個項目的結構圖,這樣我待會講起來不怎麽累。邏輯性比較強吧。如圖:

image

 

 上面很清楚的寫著我需要完成的功能模塊。最後那個test,是一個測試的servlet類。大家一看就明白。我先從配置文件說起吧。

配置文件 :

  dbConfig.properties 記錄的是最基礎的db配置:url name psd 等,代碼如下:

1

2

3

4

5

6

7

8

database.vendor = mysql

db_url = jdbc:mysql://localhost:3307/test

driverClassName= com.mysql.jdbc.Driver

db_user = root

db_password = 123456

showsql= false

devMode = true

validationQuery=SELECT 1

  log4j.properties則是日誌的配置,但日誌的配置中有一點註意的是如下:

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

  在這裏,我們要註意兩點:

一、設置我們包的下的logger權限,並給予存數據庫的權限。

image

二、db的實現的應用要為你寫的引用類。

1

2

# log db setting

log4j.appender.db=org.nsg.dbsetting.MyJDBCAppender

建數據表 :

然後我們要根據上面配置文件中寫的數據庫和表格我們要對應的建一個名為test的數據庫和一張名為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;

這樣我們就可以開始寫代碼了,泥瓦匠是一個很細節的人。這次博客,我主要是講下代碼中的核心點。因為後面我會把項目提供給你們下載。所以,這裏點到為止。

泥瓦匠說:點到為止,所謂師父領進門,修行在個人啊。

核心代碼講解:

  MyJDBCAppender.java 用於Log4j的數據庫Session管理[連接池用Druid]。這個肯定是我們得核心思想。這裏我就繼承了log4j提供的 org.apache.log4j.jdbc.JDBCAppender;然後只要簡單的重寫了closeConnection和 getConnection方法。如果獲取Druid數據庫源對象異常的話,我還寫了個 取消初始化 的方法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的數據庫Session管理[連接池用Druid]

 * @author 泥沙磚瓦漿木匠

 * @date 2014年12月7日下午1:50:56

 * @version 1.0

 */

public class MyJDBCAppender extends JDBCAppender

{

    /* Druid數據源 */

    private DruidDataSource dataSource;

     

    public MyJDBCAppender()

    {

        super();

    }

     

    @Override

    protected void closeConnection(Connection con)

    {

        try

        {

            /* 如果數據庫連接對象不為空和沒有被關閉的話,關閉數據庫連接 */

            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

    {

        /* 獲取數據庫配置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數據庫源對象產生失敗後,取消初始化 */

            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();

        }

    }

     

}

  值得註意的一點是,泥瓦匠為了方便,所以在其中的地方沒有獲取druid連接池的配置。而是直接寫了下面:

1

2

3

/* 其他配置 自然你也可以自己寫property 然後獲取set */

        result.put("maxActive","30");

        result.put("minIdle","3");

  其實這樣寫是不好了,我們可以寫一個druid.properties然後將連接池的配置放入其中。獲取set,for循環set即可。這邊我就不實現了。很簡單哦,泥瓦匠相信你們。

最後我演示下,示例代碼:放到tomcat7上,然後運行訪問

image

看到控制臺刷出來兩條信息,因為我門設置的是log4j.logger.test=INFO, db。

然後我們去查看數據庫,這邊我用Navicat:

image

 

四、結論及下載

結論:重構很有意思,慢慢來,一點一點來,就行了。細節成就未來。

延伸阅读

    评论