框架中配置文件加载的原理

1. 框架中加载配置文件的方式的概述

  1. 方式1: 通过Properties + IO

  2. 方式2: 通过ServletContext + IO

  3. 方式3: 通过类加载器

    • 类名.class.getClassLoader().getResourceAsStream("");

    • 类名.class.getResourceAsStream("");

2. 通过IO流结合Properties加载配置文件

2.1 Properties类概述

  • class Properties extends Hashtable<Object,Object>
    Properties 类本质就是一个Map集合, 但是她在Map集合的基础上进行了功能扩展, 那就是该集合可以和IO流结合使用, 能通过IO将键值对存入硬盘的文件中, 也能通过IO从硬盘文件中将键值对加载进来.
    该集合没有泛型.

  • Properties类的特点:
    Properties可以保存在流中或从流中加载.
    每个键及其对应的值都是一个字符串.
    是Hashtable的子类,说明是一个Map集合.

  • Properties类的构造: 常用她的无参构造. public Properties();

  • Properties类的常用成员方法:

    • Object setProperty(String key,String value):该集合的添加功能

      • 添加功能源码解析

        class Hashtable<K, V> {
            public V put(K key, V value) {
        		// ...
            }
        }
        
        class Properties extends Hashtable {
            public V setProperty(String key, String value) {
                return put(key, value);
            }
        }
        

        可见, setProperty(x,y)其实是调用了父类的put(x,y)方法,并且限定了能传入实参的类型。

    • String getProperty(String key):根据键获取值

    • Set<String> stringPropertyNames():获取键的集合

    • void load(Reader reader/InputStream inStream):把文件中的数据读取到Properties集合中

      • 注意, 文件中的数据必须是键值对形式, 例如:

        # config.properties
        className=java.util.ArrayList 
        key02=value02 
        key03=value03 
        
    • void store(Writer writer,String comments): 把Properties集合中的数据储存到文件中

      • 注意: 第二个参数是对属性列表的描述,不想描述就写null.

2.2 Properties作为Map集合使用

    public static void main(String[] args) {
        Properties properties = new Properties();
        properties.put("张三", 20);
        properties.put("李四", 21);
        properties.put("王五", 22);
        
        Set<Object> keySet = properties.keySet();
        for (Object key : keySet) {
            Object value = properties.get(key);
            System.out.println(key + "\t" + value);
        }
    }

2.3 Properties的特殊功能

    public static void main(String[] args) {
        Properties properties = new Properties();
        properties.setProperty("张三", "男");
        properties.setProperty("李四", "女");
        properties.setProperty("王五", "未知");

        Set<String> keySet = properties.stringPropertyNames();
        for (String key : keySet) {
            String value = properties.getProperty(key);
            System.out.println(key + "\t" + value);
        }
    }

2.4 Properties和IO结合使用

  • Properties和IO结合使用, 主要用来读写文件. 一般用来读取配置文件.
package cn.king.demo01;

import java.io.FileInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Properties;
import java.util.Set;
/**
 * Properties 类等效于一个 hashMap,里面装的元素是键值对,
 * 但是他的 hashMap 的基础上扩展了功能:
 * 能将键值对存入硬盘的文件中,并可以从硬盘文件中将键值对加载进来.
 */
public class Demo01 {
    public static void main(String[] args) throws Exception {
        // 加载 config.properties 文件
        InputStream in = new FileInputStream("config.properties");
        Properties properties = new Properties();
        // 将输入流中的文件装载进Properties集合中
        properties.load(in);
        in.close();

        // 获取 config.properties 文件中键为"className"的值
        // className = java.util.ArrayList
        String className = properties.getProperty("className");

        // 使用反射创建对象
        ArrayList list = (ArrayList) Class.forName(className).newInstance();

        // 遍历Properties集合.
        Set<String> keySet = properties.stringPropertyNames();
        for (String key : keySet) {
            String value = properties.getProperty(key);
            System.out.println(value);
        }
    }
}
package cn.king.demo01;

import java.io.*;
import java.util.Properties;
import java.util.Set;

/**
 * 需求:
 * 已知文件user.txt中的数据是键值对形式,但是不知道内容,
 * 请写一个程序判断是否有“lisi”这样的键存在,如果有就改变其值为100
 * <p>
 * 分析:
 * a、把文件中的数据加载到集合中
 * b、遍历集合,获得每一个键
 * c、判断键key是否有“lisi”,如果有就改变其值value为“100”
 * d、把集合中的数据重新存储到文件中
 */
public class Demo03 {
    public static void main(String[] args) throws IOException {
        //把文件中的数据加载到集合
        Properties prop = new Properties();
        Reader reader = new FileReader("user.txt");
        prop.load(reader);
        reader.close();

        //遍历集合,得到每一个键
        Set<String> set = prop.stringPropertyNames();
        for (String key : set) {
            //判断是否有“lisi”,有就改值
            if ("lisi".equals(key)) {
                prop.setProperty(key, "100");
                break;
            }
        }
        //集合中的数据重新存入文件
        Writer writer = new FileWriter("user.txt");
        prop.store(writer, null);
        writer.close();
    }
}

3. 通过ServletContext对象的获取项目中的任意文件的绝对路径

  • 项目结构
    在这里插入图片描述
package cn.king.web.servlet;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet(name = "AServlet", urlPatterns = {"/AServlet"})
public class AServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request,
                          HttpServletResponse response) throws ServletException, IOException {

        /*
         * 获取ServletContext对象.
         *
         * 该对象的一个功能是能获取本项目中任意文件的真实路径,
         * 真实路径就是发布到服务器上后的绝对路径.
         */
        ServletContext application = this.getServletContext();

        // "/"代表web文件夹下. 下面代表获取web文件夹下的a.txt文件的真实路径
        String realPath1 = application.getRealPath("/a.txt");
        System.out.println("a.txt的绝对路径是: " + realPath1);

        // 下面代表获取web文件夹下的WEB-INF文件夹下的b.txt文件的真实路径
        String realPath2 = application.getRealPath("/WEB-INF/b.txt");
        System.out.println("b.txt的绝对路径是: " + realPath2);

        // 下面代表获取src下的c.txt文件的真实路径
        String realPath3 = application.getRealPath("/WEB-INF/classes/c.txt");
        System.out.println("c.txt文件的绝对路径是: " + realPath3);
        /*
         * src目录下也叫classPath下, 也叫类路径下.
         * web项目发布后, src下的所有.java文件将被编译后放到web/WEB-INF/classes目录下,
         * web目录(Eclipse中叫WebContent目录)将更名成当前项目名并发布到tomcat的webapps
         * 目录下.
         */
    }

    protected void doGet(HttpServletRequest request,
                         HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }
}
  • 获取了文件的绝对路径, 就能通过IO流读写该文件了.

4. 通过类加载器来管理资源和配置文件

  • 也就是通过类加载器来读写项目中的文件. 实际上也使用了IO流.
  • java中的类加载器连.class文件都能加载, 那么加载其他类型的文本文件简直就是小菜一碟;
  • 类加载器加载文件的方法:
    • InputStream inputStream =
      this.getClass().getClassLoader().getResourceAsStream("欲加载的文件的路径");
      只能加载类路径下(classpath下)的文件, 文件路径前不能加"/".
    • InputStream inputStream = this.getClass().getResourceAsStream("欲加载的文件的路径");
      只能加载类路径下(classpath下)的文件, 文件路径前能加"/", 加"/“和不加”/"的意义不同.
  • 注意
    如果使用 new FileInputStream(" 欲加载的文件的路径");的方式,既能获取 InputStream 又能获取 OutputStream , 因此可以对配置文件进行读写; 能读写任意位置的文件;
    如果使用 getResourceAsStream(" 欲加载的文件的路径");的方式,那么只能获取 InputStream, 因此只能对配置文件进行读操作; 只能读取类路径下(classpath下)的文件;
package cn.king.demo01;

import java.io.InputStream;

public class Demo01 {
    public void fun1() {
        // 注意下面两行代码
        InputStream inputStream01 = this.getClass().getClassLoader().getResourceAsStream("");
        InputStream inputStream02 = this.getClass().getResourceAsStream("");
        /*
         * 你每天都要喝可乐, 每次喝可乐都找我, 我要去商店买来给你喝,
         * 久而久之, 觉得不方便,
         * 干脆我自己也卖可乐, 你要喝我直接拿给你, 不需要再往商店跑了.
         * 上述的话可以形容上面的两句代码.
         */
    }

    public void fun2() {
        // 从classpath路径下寻找config.properties并加载
        InputStream in01 =
                Demo01.class.getResourceAsStream("/config.properties");

        // 从Demo01类所在包中寻找config.properties并加载
        InputStream in02 =
                Demo01.class.getResourceAsStream("config.properties");

        // 从Demo01类所在包下的resource目录中寻找config.properties并加载
        InputStream in03 =
                Demo01.class.getResourceAsStream("resource/config.properties");

        /*
         * 可见,用Demo01.class.getResourceAsStream("欲加载的文件的路径");时,
         * 只能从类路径下加载资源. 
         * 文件路径前既可以加"/"也可以不加"/", 加和不加的意义不同. 
         */
    }

    public void fun3() {
        // 代表从类路径下寻找 config.properties 并加载.
        InputStream in01 =
                Demo01.class.getClassLoader().getResourceAsStream("config.properties");

        // 代表从类路径下的 resource 目录下寻找 config.properties 并加载
        InputStream in02 =
                Demo01.class.getClassLoader().getResourceAsStream("resource/config.properties");

        /*
         * Demo01.class.getClassLoader().getResourceAsStream("欲加载的文件的路径");
         * 只能从类路径下加载资源.   
         * 文件路径前不能加"/". 
         */
    }
}
package cn.king.demo01;

import java.io.IOException;
import java.io.InputStream;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

/**
 * 将db.properties封装进properties中
 */
public class PropertiesDemo {
    
    public static void main(String[] args) throws IOException {
        InputStream resourceAsStream =
                PropertiesDemo.class.getClassLoader().getResourceAsStream("db.properties");
        Properties properties = new Properties();
        properties.load(resourceAsStream);

        Set<Map.Entry<Object, Object>> entrySet = properties.entrySet();
        for (Map.Entry entry : entrySet) {
            System.out.println(entry.getKey() + "\t" + entry.getValue());
        }
    }
    
}
# db.properties
driverDriver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/db_name?characterEncoding=UTF-8
username=root
password=root

5. 注意

  • 只要是读写文件就必须使用IO.
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值