从读取properties文件说开去,浅谈web容器中类加载器

今天刚好有人让我写个通过读取properties连接数据库的小demo.

汗啊,普通项目中可以使用的文件读取,在web项目中总报空指针异常.

查阅了资料明白,赶紧记录下来,希望遇到此类问题的童鞋能引起重视。

废话不说,直接进入主题!

代码清单1:


?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import java.io.InputStream;
import java.util.Properties;
 
import org.apache.log4j.Logger;
/**
  *
  * 项目名称 PropertiesDemo
  * 包   名 com.linfeng.util
  * 文 件 名 PropertiesUtil.java
  * 开 发 人 Administrator
  * 描述信息 Properties文件读取类
  * 发布日期 2012-10-31上午11:34:59
  * 修改日期
  * 修   改  人       
  * 版本信息 V1.0
  *
  */
public class PropertiesUtil {
?
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
private static Logger log = Logger.getLogger(PropertiesUtil. class );
  private Properties propertie;
  private InputStream inputFile;  
  public PropertiesUtil(String filePath){
  propertie = new Properties();  
        try {  
            inputFile = getClass().getResourceAsStream(filePath);   
            propertie.load(inputFile);  
            inputFile.close();  
        } catch (FileNotFoundException ex) {  
            log.error( "读取属性文件--->失败!- 原因:文件路径错误或者文件不存在" );
            ex.printStackTrace();  
        } catch (IOException ex) {  
            log.error( "装载文件--->失败!" );  
            ex.printStackTrace();  
        }  
  }
  
  /** 
      * 重载函数,得到key的值 
      * @param key 取得其值的键 
      * @return key的值 
      */  
    public String getValue(String key)  
    {  
        if (propertie.containsKey(key)){  
            String value = propertie.getProperty(key); //得到某一属性的值  
            return value;  
        }  
        else   
            return "" ;  
    } //end getValue(...)  
     
    /** 
      * 重载函数,得到key的值 
      * @param fileName properties文件的路径+文件名 
      * @param key 取得其值的键 
      * @return key的值 
      */  
    public String getValue(String fileName, String key)  
    {  
        try {  
            String value = "" ;  
            inputFile = getClass().getResourceAsStream(fileName);  
            propertie.load(inputFile);  
            inputFile.close();  
               
            if (propertie.containsKey(key)){  
                value = propertie.getProperty(key);  
                return value;  
            } else  
                return value;  
        } catch (FileNotFoundException e) {  
            e.printStackTrace();  
            return "" ;  
        } catch (IOException e) {  
            e.printStackTrace();  
            return "" ;  
        } catch (Exception ex) {  
            ex.printStackTrace();  
            return "" ;  
        }  
    } //end getValue(...)  
  /**
  * 根据指定资源路径加载单个资源文件,返回Properties类对象的引用。
  * 若有异常产生,则Properties类对象为空。
  * @param filePath 资源文件的路径的值
  * @return 给定资源文件所对应的Properties类对象的引用
  */
  public static Properties loadPropertiesFile(String filePath){
  Properties properties= new Properties();
  InputStream is = null ;
  try {
  try {
  is= new FileInputStream(filePath);
  properties.load(is);
  } finally {
  if (is!= null ) {
  is.close();
  is= null ;
  }
  }
  } catch (Exception e) {
  properties = null ;
  }
  return properties;
  
  }
 
     }


PropertiesUtil.java 用于进行读取*.properties文件的工具类

通过方法


?
1
loadPropertiesFile(String filePath)
在普通java项目下可以正常读取properties文件,但是在web项目下,无法读取properties文件,报空指针异常。


这里引出类的加载器的概念

每个Class对象都保留着加载自己的类加载器的引用,可以通过Class对象的getClassLoader方法来获得其引用。ClassLoader通过loadClass方法来加载这个类。

按照类加载器,首先应该加载父类,也就是通常所说的父类优先的原则,但是在web容器中加载顺序有所不同。

通过查找资料找到这样的叙述:


对于运行在 Java EE容器中的 Web 应用来说,类加载器的实现方式与一般的 Java 应用有所不同。不同的 Web 容器的实现方式也会有所不同。以 Apache Tomcat 来说,每个 Web 应用都有一个对应的类加载器实例。该类加载器也使用代理模式,所不同的是它是首先尝试去加载某个类,如果找不到再代理给父类加载器。这与一般类加载器的顺序是相反的。这是 Java Servlet 规范中的推荐做法,其目的是使得 Web 应用自己的类的优先级高于 Web 容器提供的类。这种代理模式的一个例外是:Java 核心库的类是不在查找范围之内的。这也是为了保证 Java 核心库的类型安全。

绝大多数情况下,Web 应用的开发人员不需要考虑与类加载器相关的细节。下面给出几条简单的原则:


  • 每个 Web 应用自己的 Java 类文件和使用的库的 jar 包,分别放在 WEB-INF/classes和 WEB-INF/lib目录下面。
  • 多个应用共享的 Java 类文件和 jar 包,分别放在 Web 容器指定的由所有 Web 应用共享的目录下面。
  • 当出现找不到类的错误时,检查当前类的类加载器和当前线程的上下文类加载器是否正确。




于是对于一个普通web项目,properties文件可以放在src目录下,经过编译器编译之后目录变为WEB-INF/classes目录.

路径变化后,只能通过类加载器来获得文件路径,否则无法加载。

代码清单2:


?
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
/**
  *
  * 项目名称 XXXX
  * 包   名 com.xxx.mall.util
  * 文 件 名 DbUtil.java
  * 开 发 人 Administrator
  * 描述信息 数据库帮助类
  * <p>数据库连接方法</p>
  * <p>释放数据库资源方法</p>
  * 发布日期 2012-10-31下午03:26:50
  * 修改日期
  * 修   改  人       
  * 版本信息 V1.0
  *
  */
public class DbUtil {
     //Connection对象
     private  static Connection conn = null ;
     private static final String PROPERTIES_FILE_PATH= "/dbconfig.properties" ;
     /**
      * 获得数据库连接对象方法
      * @return 返回数据库连接对象conn
      */
     public static Connection getConnection(){
         try {
             PropertiesUtil propertiesUtil= new PropertiesUtil(PROPERTIES_FILE_PATH);
             Class.forName(propertiesUtil.getValue( "driver" ));
             conn=DriverManager.getConnection(propertiesUtil.getValue( "url" ), propertiesUtil.getValue( "user" ), propertiesUtil.getValue( "password" ));
         } catch (ClassNotFoundException e) {
             throw new MyDbException( "数据库jar包异常" ,e);
         } catch (SQLException e) {
             throw new MyDbException( "数据库连接字符串异常" ,e);
         }
         catch (Exception e) {
            throw new MyDbException( "数据库连接异常" ,e);
         }
         return conn;
     }
     /**
      * 释放数据库资源方法
      * @param pmst
      * @param rs
      * @param conn
      */
     public static void freeDb(PreparedStatement pmst,ResultSet rs,Connection conn){
         if (pmst!= null ) {
             try {
                 pmst.close();
             } catch (SQLException e) {
                  throw new MyDbException( "数据库关闭PreparedStatement对象异常" ,e);
             }
         }
         if (rs!= null ) {
             try {
                 rs.close();
             } catch (SQLException e) {
                  throw new MyDbException( "数据库关闭ResultSet对象异常" ,e);
             }
         }
         if (conn!= null ) {
             try {
                 conn.close();
             } catch (SQLException e) {
                  throw new MyDbException( "数据库关闭Connection对象异常" ,e);
             }
         }
     }
 
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值