本ページはプロモーションが含まれています

Java入門

Javaのプロパティファイル(properties)の読み込みを実例でわかりやすく解説

トム

・都内自社開発IT企業勤務/javaのバックエンドエンジニア
/java歴10年以上 ・首都圏在住30代
・資格:基本情報技術者/応用情報技術者/Java Silver/Python3エンジニア認定基礎

Java開発を進めていると、「あれ、この設定値どこで変えるんだっけ?」「環境ごとに設定を切り替えたいけど、どうすれば…」と悩んだ経験はありませんか。実は私も、Javaを学び始めたころ、設定ファイルの扱いでよく頭を抱えていました。

特にデータベースの接続情報やAPIキーなど、プログラムの実行環境によって変わる値をコードに直接書き込むのは避けたいものです。

そんな時、Javaで古くから使われているのが「プロパティファイル」です。このファイルを使えば、アプリケーションの設定情報を外部に切り出して管理できるようになります。最初は少しとっつきにくいかもしれませんが、一度理解してしまえば、開発効率が格段に向上する便利な仕組みです。

この記事では、長年Java開発に携わってきた経験から、Javaのプロパティファイルの基本的な読み込み方法から、よくあるつまずきポイント、さらには実務で役立つ応用テクニックまで、初心者の方にも分かりやすく解説します。

プロパティファイルとは何か?

Javaで開発を行う際、設定情報をどのように管理するかは重要です。その手段の一つが「プロパティファイル」の活用です。まずはプロパティファイルがどのようなもので、どんな役割を担っているのかを見ていきます。

プロパティファイルの用途と役割

プロパティファイルは、アプリケーションの設定情報をキーと値のペアで保存するためのテキストファイルです。プログラムのコード内に直接設定値を書き込むのではなく、外部ファイルとして管理することで、以下のようなメリットがあります。

メリット

  1. 設定の変更が容易: プログラムを再コンパイルすることなく、設定値を変更できます。例えば、テスト環境から本番環境へ移行する際に、データベースの接続情報を変更する場合などに便利
  2. 可読性の向上: 設定情報が一箇所にまとまるため、どのような設定がされているのか把握しやすくなる
  3. セキュリティの向上: パスワードなどの機密情報をコードから分離し、プロパティファイルに記述することで、ソースコードのセキュリティを高められます。ただし、プロパティファイル自体のアクセス管理も重要

主な用途としては、データベース接続情報(URL、ユーザー名、パスワード)、外部APIのキー、アプリケーションの動作モード(開発モード、本番モードなど)、ログレベルの設定など、多岐にわたります。

拡張子 .properties の基本構造

プロパティファイルは、拡張子は.properties です。その構造はシンプルです。

ポイント

  • キーと値のペア: キー=値 または キー:値 の形式で記述します。一般的には = がよく使われます。キーにはスペースを含められませんが、値には含めることができる
  • コメント: 行頭に # または ! を付けると、その行はコメントとして扱われる
  • エンコーディング: かつてはISO 8859-1でエンコードされることが多かったですが、最近ではUTF-8で保存し、読み込み時に文字コードを指定する方法が一般的

簡単な例を見てみましょう。

# データベース接続設定
database.url=jdbc:mysql://localhost:3306/mydb
database.username=dbuser
database.password=dbpassword
# アプリケーション設定
application.name=My Awesome App
application.version=1.0.2

キーと値を記述していくだけで、設定情報を簡単に管理できるのがプロパティファイルの特長です。

Javaでプロパティファイルを読み込む基本手順

プロパティファイルの基本を理解したところで、次にJavaからプロパティファイルを読み込む方法を見ていきましょう。Java標準ライブラリの java.util.Properties クラスを使うのが基本的なアプローチです。

Properties クラスの使い方

Propertiesクラスは、プロパティファイルを扱うためにJavaが提供している便利なクラスです。このクラスは Hashtable継承しており、キーと値を文字列として格納できます。

主なメソッドとしては、以下のものがあります。

ポイント

  • load(InputStream inStream): 入力ストリームからプロパティファイルを読み込む
  • getProperty(String key): 指定されたキーに対応する値を取得する
  • getProperty(String key, String defaultValue): 指定されたキーに対応する値を取得するが、キーが存在しない場合はデフォルト値を返す
  • setProperty(String key, String value): 新しいプロパティを設定したり、既存のプロパティを更新する
  • store(OutputStream out, String comments): プロパティリストを指定された出力ストリームに書き出す

ファイルの配置場所に注意(resources ディレクトリ)

Javaプロジェクトでは、プロパティファイルのようなリソースファイルを配置する標準的な場所があります。MavenやGradleといったビルドツールを利用している場合、src/main/resources ディレクトリがそれにあたります。

resources ディレクトリに配置されたファイルは、ビルド時にクラスパスの通った場所(通常は WEB-INF/classes やJARファイルのルートなど)にコピーされます。

例えば、src/main/resources/config.properties というファイルを作成した場合、プログラムからは "config.properties" という名前でアクセスできるようになります。

ファイル読み込みのサンプルコード(InputStream 使用)

それでは、実際に Properties クラスと InputStream を使ってプロパティファイルを読み込むサンプルコードを見ていきましょう。ここでは、src/main/resources ディレクトリに config.properties というファイルが存在することを前提とします。

config.properties:

app.name=MyApplication
app.version=1.0

Javaコード:

import java.io.InputStream;
import java.io.IOException;
import java.util.Properties;
public class PropertyReader {
    public static void main(String[] args) {
        Properties prop = new Properties();
        // クラスローダー経由でリソースファイルを取得する
        try (InputStream input = PropertyReader.class.getClassLoader().getResourceAsStream("config.properties")) {
            if (input == null) {
                System.out.println("申し訳ありません、指定されたファイルが見つかりません。");
                return;
            }
            // プロパティファイルを読み込む
            prop.load(input);
            // プロパティ値を取得して表示
            System.out.println("アプリケーション名: " + prop.getProperty("app.name"));
            System.out.println("バージョン: " + prop.getProperty("app.version"));
            // 存在しないキーを指定した場合 (デフォルト値なし)
            System.out.println("作者: " + prop.getProperty("app.author"));
            // 存在しないキーを指定した場合 (デフォルト値あり)
            System.out.println("作者 (デフォルト値あり): " + prop.getProperty("app.author", "不明"));
        } catch (IOException ex) {
            // IOExceptionが発生した場合の処理
            ex.printStackTrace();
        }
    }
}

このコードは、config.properties ファイルをクラスパスから読み込み、その中に定義されている app.nameapp.version の値を取得して表示します。

よくある読み込み方法

プロパティファイルを読み込む方法はいくつかあり、状況に応じて使い分けることが重要です。ここでは、代表的な読み込みパターンとその特徴について解説します。

クラスパスからの読み込み方法

最も一般的で推奨される方法が、クラスパスからの読み込みです。前のセクションのサンプルコードで示した ClassLoader.getResourceAsStream() を使う方法がこれに該当します。

利点

  • 環境依存性が低い: アプリケーションがJARファイルやWARファイルとしてパッケージングされても、ファイルへのパスが変わらないため、安定して動作する
  • 配置が標準的: src/main/resources に配置するという規約に従うことで、プロジェクト構造が分かりやすくなる

外部ファイルとして読み込む場合(設定の切り替え用途)

アプリケーションの外部にプロパティファイルを配置し、それを読み込む方法もあります。これは特に、アプリケーションを再デプロイせずに設定を頻繁に変更したい場合や、運用担当者が設定ファイルを直接編集するようなシナリオで有効です。

読み込み方法:ファイルシステムのパス(絶対パスまたは実行基盤からの相対パス)を指定して FileInputStream で読み込みます。

利点

  • 柔軟な設定変更: アプリケーションを停止・再起動することなく、設定変更を反映できる場合がある(ファイルの変更を監視し再読み込みする仕組みが必要)
  • 運用との分離: 開発物と設定ファイルを分離して管理できる

考慮事項

  • ファイルパスの管理: 外部ファイルのパスをどのようにアプリケーションに伝えるか(環境変数、起動時引数など)を考慮する必要がある
  • セキュリティ: 外部ファイルのアクセス権限管理が重要になる

例えば、Dockerコンテナでアプリケーションを動かす際に、ホストOS上の設定ファイルをコンテナ内にマウントし、それを読み込むといった使い方が考えられます。コンテナイメージを再ビルドせずに設定を変更できます。

Spring Bootとの連携時の違い

これまで見てきたのは、主にJava SE環境での標準的なプロパティファイルの扱い方でした。しかし、現代のJava開発で広く使われているフレームワークであるSpring Bootを利用する場合、プロパティファイルの扱いはさらに簡単かつ高機能になります。

Spring Bootは「設定より規約」の原則に基づき、多くの設定を自動で行ってくれます。プロパティファイルの読み込みもその一つです。

application.properties / application.yml の役割

Spring Bootプロジェクトでは、src/main/resourcesディレクトリに application.properties または application.yml という名前のファイルを配置しておくと、Spring Bootが起動時に自動的にその内容を読み込み、アプリケーションの設定として利用可能にします。

application.properties

伝統的なキー=値の形式です。

server.port=8081 spring.application.name=my-spring-app

application.yml ( application.yaml)

YAML形式で、より階層的で人間が読みやすい形式で記述できます。

server:
  port: 8081
spring: 
  application:
    name: my-spring-app

どちらの形式を使うかはプロジェクトの好みや規約によりますが、YAMLは複雑な設定を記述する際に可読性が高いという利点があります。両方のファイルが存在する場合、.properties ファイルが .yml ファイルよりも優先されることがあります(プロファイル特有のファイルなど、より具体的なものが優先されます)。

これらのファイルに記述された設定は、特別な読み込み処理をコードに書かなくても、Spring環境内で利用できるようになります。これぞSpring Bootにおけるプロパティファイルの読み込みの簡便さです。

@Value アノテーションによる読み込み方法

Spring Bootでは、application.propertiesapplication.yml に定義された値を、コンポーネント(@Component, @Service, @Controller などでマークされたクラス)のフィールドに直接インジェクション(注入)できます。その際に使うのが @Value アノテーションです。

application.properties:

myapp.title=素晴らしいアプリケーション
myapp.version=2.1

Javaコード:

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
public class AppConfig {
    @Value("${myapp.title}")
    private String title;
    @Value("${myapp.version}")
    private String version;
    // デフォルト値も指定可能
    @Value("${myapp.author:Default Author}")
    private String author;
    public void printConfig() {
        System.out.println("タイトル: " + title);
        System.out.println("バージョン: " + version);
        System.out.println("作者: " + author);
    }
}

${...} のプレースホルダー内にプロパティのキーを指定します。キーが存在しない場合に備えて、コロン : の後にデフォルト値を記述することも可能です。これにより、従来の Properties.getProperty() を呼び出すコードが不要になり、より宣言的に設定値を扱えます。

@ConfigurationProperties を使ったプロパティ管理

多数の設定値をまとめてクラスのフィールドとして扱いたい場合、@Value を一つ一つフィールドに付けるのは冗長になることがあります。そのような場合に便利なのが @ConfigurationProperties アノテーションです。

このアノテーションを使うと、指定したプレフィックスを持つプロパティ群を、POJO(Plain Old Java Object)にまとめてマッピングできます。

application.properties:

myapp.server.host=localhost
myapp.server.port=9000
myapp.client.timeout=5000
myapp.client.retries=3

Javaコード (POJO):

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component; // もしくは @EnableConfigurationProperties と共に利用
// @Component // SpringがスキャンしてBeanとして登録する場合
@ConfigurationProperties(prefix = "myapp") // "myapp" プレフィックスを持つプロパティをマッピング
public class MyAppProperties {
    private Server server = new Server(); // ネストしたプロパティも可能
    private Client client = new Client();
    public static class Server {
        private String host;
        private int port;
        // getters and setters
        public String getHost() { return host; }
        public void setHost(String host) { this.host = host; }
        public int getPort() { return port; }
        public void setPort(int port) { this.port = port; }
    }
    public static class Client {
        private int timeout;
        private int retries;
        // getters and setters
        public int getTimeout() { return timeout; }
        public void setTimeout(int timeout) { this.timeout = timeout; }
        public int getRetries() { return retries; }
        public void setRetries(int retries) { this.retries = retries; }
    }
    // getters and setters for server and client
    public Server getServer() { return server; }
    public void setServer(Server server) { this.server = server; }
    public Client getClient() { return client; }
    public void setClient(Client client) { this.client = client; }
    @Override
    public String toString() {
        return "MyAppProperties{" +
               "serverHost=" + server.getHost() +
               ", serverPort=" + server.getPort() +
               ", clientTimeout=" + client.getTimeout() +
               ", clientRetries=" + client.getRetries() +
               '}';
    }
}

この MyAppProperties クラスをSpringのコンポーネントとして登録するか、メインのコンフィギュレーションクラスで @EnableConfigurationProperties(MyAppProperties.class) を指定することで、Springが自動的にプロパティ値をこのクラスのフィールドにバインドしてくれます。型安全であり、IDEの補完も効きやすくなるため、非常に効率的なプロパティ管理が実現できます。

Spring Bootにおけるこれらの機能は、プロパティファイルの読み込みの作業を大幅に簡略化し、開発者がビジネスロジックに集中できるよう支援してくれます。

まとめとベストプラクティス

Javaアプリケーションにおけるプロパティファイルの扱いは、設定管理の基本であり、アプリケーションの柔軟性や保守性を大きく左右します。ここでは、これまでの内容を踏まえ、より実践的なベストプラクティスをいくつか紹介します。

設定ファイルを使い分ける戦略

一つのプロパティファイルにすべての設定を詰め込むのではなく、設定の性質に応じてファイルを分割することを検討しましょう。

  • application.properties (または application.yml): Spring Bootの場合、基本的なアプリケーション設定、サーバ設定など、汎用的な設定を記述
  • 機能特化型プロパティファイル: 例えば、database.propertiesaws.propertiesexternal-api.properties のように、特定の機能や連携サービスに関する設定を分離します。これにより、関連する設定が一箇所にまとまり、管理がしやすくなります。これらのファイルは、必要に応じてプログラムから明示的に読み込むか、Springであれば @PropertySource アノテーションなどを使って追加の読み込み対象として指定できる
  • ロギング設定ファイル: Logback (logback.xml) や Log4j2 (log4j2.xml) のようなロギングフレームワークの設定は、専用のXMLやプロパティファイルで管理するのが一般的

設定ファイルを適切に分割することで、関心事が分離され、設定の見通しが良くなります。結果として、変更時の影響範囲も特定しやすくなるでしょう。

環境ごとのプロパティ管理の考え方

開発(dev)、ステージング(stg)、本番(prod)など、アプリケーションを実行する環境ごとに設定値が異なるのは一般的です。これらの環境差異を効率的に管理する方法を確立することが重要です。

  • Spring Profiles (Spring Boot): Spring Bootでは、application-{profile}.properties (例: application-dev.properties, application-prod.properties) という命名規則でプロファイル固有の設定ファイルを作成できます。起動時にアクティブなプロファイル(例: spring.profiles.active=dev)を指定することで、対応する設定が自動的に読み込まれる
  • 環境変数: データベースのパスワードやAPIキーなど、特に機密性の高い情報や、実行環境に強く依存する値は、環境変数経由で設定するのが良いプラクティスです。プログラムやプロパティファイル内で環境変数を参照するようにします(例: ${DB_PASSWORD})。
  • 外部設定ファイル: 前述の通り、設定ファイルをJAR/WARの外に配置し、起動時引数や環境変数でそのパスを指定する方法もあります。これにより、デプロイ成果物を変更せずに設定を切り替えられる
  • 設定サーバー (Config Server): Microservicesアーキテクチャなど、多数のサービスが存在する複雑な環境では、Spring Cloud Config Server のような中央集権型の設定サーバーを利用して、各サービスの設定を一元管理する方法も有効

これらの方法を組み合わせることで、安全かつ効率的に環境ごとの設定を管理できます。

Git管理する際のセキュリティ的注意点

プロパティファイル、特にデータベースの認証情報やAPIキーなどの機密情報を含むファイルをGitリポジトリで管理する際には、細心の注意が必要です。

  1. 機密情報はコミットしない:最も基本的な原則は、パスワードやプライベートキーなどの機密情報をリポジトリに直接コミットしないこと
    • .gitignore の活用: 機密情報を含む設定ファイル(例: local.properties, secret.properties)は .gitignore に追加し、リポジトリに含まれないようにします。
    • テンプレートファイルの提供: 代わりに、設定の雛形となるテンプレートファイル(例: config.properties.template)をリポジトリに含め、実際の値は各開発者や運用担当者がローカルで設定するようにします。
  2. 環境変数や外部のシークレット管理システムを利用する:機密情報は、実行環境の環境変数から読み込むか、HashiCorp Vault、AWS Secrets Manager、Google Cloud Secret Manager のような専用のシークレット管理サービスを利用して安全に管理・取得することを強く推奨
  3. 暗号化の検討:どうしても設定ファイルに機密情報を含める必要がある場合は、Jasypt Spring Boot Starter のようなライブラリを使ってプロパティファイル内の値を暗号化し、アプリケーション起動時に復号する仕組みを導入することも一つの手です。ただし、暗号化キーの管理という別の課題が発生する
  4. Pull Request のレビュー:コードレビューの際には、意図せず機密情報がコミットされていないかを確認するプロセスを設けることも重要

これらのセキュリティ対策を講じることで、プロパティファイルの読み込みの利便性を享受しつつ、情報漏洩のリスクを低減できます。

  • この記事を書いた人
  • 最新記事

トム

・都内自社開発IT企業勤務/javaのバックエンドエンジニア
/java歴10年以上 ・首都圏在住30代
・資格:基本情報技術者/応用情報技術者/Java Silver/Python3エンジニア認定基礎

-Java入門