杰瑞科技汇

Java Web如何读取配置文件?

下面我将详细介绍几种最主流和推荐的方法,从传统的 Servlet API 到现代的 Spring/Spring Boot 框架。

Java Web如何读取配置文件?-图1
(图片来源网络,侵删)

传统 Servlet 方式 (不依赖框架)

在 Java Web 应用的早期,我们主要使用 Servlet API 来读取配置文件,Servlet 规范定义了两个主要的配置文件位置:

  • web.xml: 部署描述符,可以配置初始化参数。
  • /WEB-INF/classes 目录: 存放应用的资源文件,如 .properties.xml 文件,这个目录下的文件会被 ClassLoader 自动加载。

读取 web.xml 中的初始化参数

这种方式通常用于配置整个 Web 应用的全局参数。

  1. web.xml 中配置参数

    <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
             version="4.0">
        <!-- 定义上下文初始化参数 -->
        <context-param>
            <param-name>systemConfigPath</param-name>
            <param-value>/WEB-INF/config/system.properties</param-value>
        </context-param>
        <!-- 定义 Servlet 初始化参数 -->
        <servlet>
            <servlet-name>MyServlet</servlet-name>
            <servlet-class>com.example.MyServlet</servlet-class>
            <init-param>
                <param-name>dbUser</param-name>
                <param-value>admin</param-value>
            </init-param>
        </servlet>
    </web-app>
  2. 在 Java 代码中读取

    Java Web如何读取配置文件?-图2
    (图片来源网络,侵删)
    • 在 Servlet 中读取 init-param:

      import javax.servlet.*;
      import javax.servlet.http.*;
      import java.io.IOException;
      public class MyServlet extends HttpServlet {
          @Override
          public void init() throws ServletException {
              // 只能读取当前 Servlet 的 init-param
              String dbUser = getInitParameter("dbUser");
              System.out.println("Servlet init-param dbUser: " + dbUser);
          }
          @Override
          protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
              // ...
          }
      }
    • 在任何地方读取 context-param:

      import javax.servlet.ServletContext;
      // 在 Servlet 中获取
      ServletContext context = getServletContext();
      String configPath = context.getInitParameter("systemConfigPath");
      System.out.println("Context-param systemConfigPath: " + configPath);
      // 也可以通过 JNDI 在其他类中获取 ServletContext
      // context = (ServletContext) new InitialContext().lookup("java:comp/env");

读取 src/main/resources 下的属性文件

这是最传统的方式,通过 ClassLoader 来读取。

假设你的项目结构如下:

Java Web如何读取配置文件?-图3
(图片来源网络,侵删)
src/
└── main/
    ├── java/
    │   └── com/
    │       └── example/
    │           └── MyServlet.java
    └── resources/
        └── database.properties

database.properties

db.url=jdbc:mysql://localhost:3306/mydb
db.username=root
db.password=secret

MyServlet 中读取:

import javax.servlet.*;
import javax.servlet.http.*;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
public class MyServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 1. 获取 ClassLoader
        ClassLoader classLoader = getClass().getClassLoader();
        // 2. 通过 ClassLoader 获取输入流
        // 注意:路径是相对于 resources 目录的,不要以 "/" 开头
        InputStream inputStream = classLoader.getResourceAsStream("database.properties");
        if (inputStream != null) {
            Properties props = new Properties();
            props.load(inputStream);
            String url = props.getProperty("db.url");
            String username = props.getProperty("db.username");
            String password = props.getProperty("db.password");
            System.out.println("DB URL: " + url);
            System.out.println("DB User: " + username);
            inputStream.close();
        } else {
            System.err.println("Sorry, unable to find database.properties");
        }
    }
}

Spring Framework 方式

Spring 框架提供了更强大、更灵活的方式来管理配置。

使用 @PropertySource@Value (推荐)

这是 Spring 中读取外部属性文件最常用和最优雅的方式。

  1. 创建属性文件src/main/resources 下创建 app.properties:

    app.name=My Spring Application
    app.version=1.0.0
  2. 配置类 创建一个配置类,并使用 @PropertySource 来指定属性文件的位置。

    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.PropertySource;
    @Configuration
    @PropertySource("classpath:app.properties") // classpath: 表示从 resources 目录加载
    public class AppConfig {
        @Value("${app.name}")
        private String appName;
        @Value("${app.version}")
        private String appVersion;
        // 可以提供一个 getter 方法来在其他地方使用
        public String getAppName() {
            return appName;
        }
        public String getAppVersion() {
            return appVersion;
        }
        // 打印出来测试
        public void print() {
            System.out.println("App Name from @PropertySource: " + appName);
            System.out.println("App Version from @PropertySource: " + appVersion);
        }
    }
  3. 在应用中使用

    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    @RestController
    public class MyController {
        @Autowired
        private AppConfig appConfig;
        @GetMapping("/config")
        public String getConfig() {
            appConfig.print(); // 调用方法打印
            return "App Name: " + appConfig.getAppName() + ", Version: " + appConfig.getAppVersion();
        }
    }

使用 Environment 对象

Environment 是 Spring 的核心接口,可以统一访问所有属性源,包括系统属性、环境变量、以及通过 @PropertySource 加载的文件。

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class EnvironmentController {
    @Autowired
    private Environment env;
    @GetMapping("/env-config")
    public String getEnvConfig() {
        // 通过 getProperty 方法获取属性,可以设置默认值
        String appName = env.getProperty("app.name", "Default App Name");
        String dbUrl = env.getProperty("db.url"); // 如果没有该属性,返回 null
        System.out.println("App Name from Environment: " + appName);
        System.out.println("DB URL from Environment: " + dbUrl);
        return "App Name: " + appName;
    }
}

Spring Boot 方式 (现代标准)

Spring Boot 极大地简化了配置管理,它遵循“约定优于配置”的原则。

默认的 application.propertiesapplication.yml

Spring Boot 会自动在 src/main/resources 目录下寻找 application.propertiesapplication.yml 文件,并将其作为主配置文件。

src/main/resources/application.properties:

# 服务器端口
server.port=8081
# 自定义应用属性
myapp.name=My Boot App
myapp.feature.enabled=true

在任意 Spring Bean(如 @Service, @RestController)中,可以直接使用 @Value 注入:

import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class BootConfigController {
    @Value("${myapp.name}")
    private String appName;
    @Value("${myapp.feature.enabled}")
    private boolean featureEnabled;
    @GetMapping("/boot-config")
    public String getBootConfig() {
        return "App Name: " + appName + ", Feature Enabled: " + featureEnabled;
    }
}

使用 @ConfigurationProperties (类型安全的配置)

这是 Spring Boot 中最推荐的方式,用于管理一组相关的配置,它能将配置文件中的属性绑定到一个 Java 对象,类型安全且代码清晰。

  1. 创建属性文件 src/main/resources/application.properties:

    # 数据库配置
    datasource.url=jdbc:mysql://localhost:3306/mydb
    datasource.username=root
    datasource.password=secret
    datasource.pool-size=10
  2. 创建配置属性类 使用 @ConfigurationProperties 注解来绑定前缀。

    import org.springframework.boot.context.properties.ConfigurationProperties;
    import org.springframework.context.annotation.Configuration;
    @Configuration
    @ConfigurationProperties(prefix = "datasource") // 绑定以 "datasource" 开头的属性
    public class DataSourceProperties {
        private String url;
        private String username;
        private String password;
        private int poolSize;
        // 必须提供标准的 getter 和 setter 方法
        public String getUrl() { return url; }
        public void setUrl(String url) { this.url = url; }
        public String getUsername() { return username; }
        public void setUsername(String username) { this.username = username; }
        public String getPassword() { return password; }
        public void setPassword(String password) { this.password = password; }
        public int getPoolSize() { return poolSize; }
        public void setPoolSize(int poolSize) { this.poolSize = poolSize; }
        @Override
        public String toString() {
            return "DataSourceProperties{" +
                   "url='" + url + '\'' +
                   ", username='" + username + '\'' +
                   ", password='" + password + '\'' +
                   ", poolSize=" + poolSize +
                   '}';
        }
    }
  3. 在应用中使用 Spring Boot 会自动创建并注册这个 Bean,你只需要 @Autowired 即可。

    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    @RestController
    public class BootPropertiesController {
        @Autowired
        private DataSourceProperties dataSourceProperties;
        @GetMapping("/datasource-config")
        public String getDatasourceConfig() {
            return dataSourceProperties.toString();
        }
    }

多环境配置

Spring Boot 支持不同环境的配置文件,非常实用。

  • application.properties: 通用配置
  • application-dev.properties: 开发环境配置
  • application-prod.properties: 生产环境配置

application.properties 中通过 spring.profiles.active 来激活指定环境的配置:

# 激活开发环境配置
spring.profiles.active=dev

然后在 application-dev.properties 中可以覆盖通用配置:

# 开发环境使用不同的端口和数据库
server.port=8080
datasource.url=jdbc:mysql://dev-db:3306/mydb_dev

总结与对比

方法 适用场景 优点 缺点
Servlet API 无框架的纯 Java Web 项目 标准规范,所有 Servlet 容器都支持 代码冗余,功能单一,灵活性差
Spring @PropertySource Spring/Spring Boot 项目 灵活,可加载任意路径的文件,与 Spring 生态集成好 需要手动管理 Properties 对象,不如 @ConfigurationProperties 类型安全
Spring Environment Spring/Spring Boot 项目 统一访问所有属性源,功能强大 需要手动转换类型,不够直观
Spring Boot @Value Spring Boot 项目 简单,直接注入单个值到字段 适合少量、零散的配置,不适合管理一组相关配置
Spring Boot @ConfigurationProperties Spring Boot 项目 (强烈推荐) 类型安全,代码清晰,适合管理一组相关配置 需要编写一个 POJO 类

最终建议:

  • 如果你还在使用传统的 Servlet/JSP 项目:使用 Servlet API 读取 web.xml 参数和 ClassLoader 读取 resources 下的文件。
  • 如果你在使用 Spring/Spring MVC 项目:优先使用 @PropertySource + @Value@ConfigurationProperties
  • 如果你在使用 Spring Boot 项目毫不犹豫地使用 @ConfigurationProperties 来管理结构化配置,并用 application-{profile}.properties 来区分环境,对于少量、独立的配置,@Value 也是一个不错的选择。
分享:
扫描分享到社交APP
上一篇
下一篇