Properties Management
===================================================================================
.. only:: html
.. contents:: Table of Contents
:depth: 3
:local:
Overview
--------------------------------------------------------------------------------
This section explains how to manage properties.
Value that needs to be managed as properties can be classified into following two categories.
.. tabularcolumns:: |p{0.10\linewidth}|p{0.20\linewidth}|p{0.35\linewidth}|p{0.35\linewidth}|
.. list-table::
:header-rows: 1
:widths: 10 20 35 35
* - Sr. No.
- Classification
- Description
- Example
* - 1.
- Environment dependent setting
- The setting needs to be changed according to the environment on which the application is running.
It depends on non-functional requirements such as system configuration.
- * Database connection information (connection URL, connection user, password, etc)
* Destination of the file storage (directory path etc)
* more ...
* - 2.
- Application settings
- The settings that can be customize the application behavior.
It depends on functional requirements.
- * Password valid days
* Reservation period days
* more ...
.. note::
In this guideline, it is recommended to manage these settings as properties (properties file).
If an application is mechanized such a way that acquires setting from the properties,
there is no need to re-build the application even if there is any changes in these values.
Therefore it is possible to release the tested application on production environment.
.. tip::
Values that are managed as properties can be acquired from JVM system properties (-D option) or OS environment variables.
About access order, refer to ":ref:`PropertiesManagementHowToUse`".
|
Values that are managed as properties can be used at the following two locations.
* Bean definition file
* Java classes managed by DI container
|
.. _PropertiesManagementHowToUse:
How to use
--------------------------------------------------------------------------------
.. _technical-details_label:
About properties file definition
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| Properties file values in Java class and bean definition file can be accessed by defining ```` tag in bean definition file.
| ```` tag reads the group of specified properties files
| and can fetch values for properties files key \ ``xxx``\ specified in \ ``${xxx}``\ format in ``@Value`` annotation or bean definition files.
.. note::
When specified in \ ``${xxx:defaultValue}``\ format and when key \ ``xxx``\ is not set in properties file, \ ``defaultValue``\ is used.
|
See the method below for defining a properties file
**bean definition file**
- applicationContext.xml
- spring-mvc.xml
.. code-block:: xml
.. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}|
.. list-table::
:header-rows: 1
:widths: 10 90
* - Sr. No.
- Description
* - | (1)
- | In location, set the resource location path.
| Multiple paths separated by comma can be specified in location attribute.
| By performing above settings, read properties file under META-INF/spring directory of class path.
| Once these settings are done, just add the properties file under META-INF/spring.
| For details on location value, see \ `Reference `_\ .
.. note::
\ ````\ needs to be defined in both ``applicationContext.xml`` and ``spring-mvc.xml``.
|
Properties are accessed in the following order by default.
#. System properties of active JVM
#. Environment variables
#. Application definition properties
| As per default setting, properties file defined in application is searched and read after all environment related properties (JVM system properties and environment variables) are read.
| Read sequence can be changed by setting local-override attribute of ```` tag to true.
| By performing these settings, the properties defined in application are enabled with higher priority.
**bean definition file**
.. code-block:: xml
.. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}|
.. list-table::
:header-rows: 1
:widths: 10 90
* - Sr. No.
- Description
* - | (1)
- | Access properties in the following order when local-override attribute is set to true.
| 1. Application definition properties
| 2. System properties of active JVM
| 3. Environment variables
|
.. note::
Normally the above settings are sufficient.
When multiple ```` tags are specified, read order can be defined by setting order attribute value.
**bean definition file**
.. code-block:: xml
.. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}|
.. list-table::
:header-rows: 1
:widths: 10 90
:class: longtable
* - Sr. No.
- Description
* - | (1)
- | By setting the order attribute to a value which is less than (2), properties file corresponding to location attribute is read before (2).
| When a key overlapping with the key in properties file read in (2) exists, value fetched in (1) is given preference.
| By setting ignore-unresolvable attribute to true, error which occurs when key exists only in properties file of (2) can be prevented.
* - | (2)
- | By setting the order attribute to value greater than (1), properties file corresponding to location attribute is read after (1).
| When a key overlapping with the key in properties file read in (1) exists, value fetched in (1) is set.
| By setting ignore-unresolvable attribute to true, error which occurs when key exists only in properties file of (1) can be prevented.
|
.. _bean-definition-file_label:
Using properties in bean definition file
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| See the example below of datasource configuration file.
| In the following example, it is assumed that properties file definition ( ```` ) is specified.
| Basically, property value can be set by setting properties file key in bean definition file using ``${}`` placeholder.
**Properties file**
.. code-block:: properties
database.url=jdbc:postgresql://localhost:5432/shopping
database.password=postgres
database.username=postgres
database.driverClassName=org.postgresql.Driver
|
**bean definition file**
.. code-block:: xml
|
.. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}|
.. list-table::
:header-rows: 1
:widths: 10 90
* - Sr. No.
- Description
* - | (1)
- | By setting ``${database.driverClassName}``, the value for read properties file key \ ``database.driverClassName``\ gets substituted.
* - | (2)
- | By setting ``${database.url}``, the value for read properties file key \ ``database.url``\ gets substituted.
* - | (3)
- | By setting ``${database.username}``, the value for read properties file key \ ``database.username``\ gets substituted.
* - | (4)
- | By setting ``${database.password}``, the value for read properties file key \ ``database.password``\ gets substituted.
|
As a result of reading the properties file key, the values are replaced as follows:
.. code-block:: xml
|
Using properties in Java class
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| It is possible to use properties in Java class by specifying ``@Value`` annotation in the field wherein properties values are to be stored.
| To use ``@Value`` annotation, the corresponding object needs to be stored in DI container of Spring.
| In the following example, it is assumed that properties file definition ( ```` ) is specified.
| External reference is possible by adding ``@Value`` annotation to variables and setting properties file key in value using ``${}`` placeholder.
**Properties file**
.. code-block:: properties
item.upload.title=list of update file
item.upload.dir=file:/tmp/upload
item.upload.maxUpdateFileNum=10
**Java class**
.. code-block:: java
@Value("${item.upload.title}") // (1)
private String uploadTitle;
@Value("${item.upload.dir}") // (2)
private Resource uploadDir;
@Value("${item.upload.maxUpdateFileNum}") // (3)
private int maxUpdateFileNum;
// Getters and setters omitted
.. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}|
.. list-table::
:header-rows: 1
:widths: 10 90
* - Sr. No.
- Description
* - | (1)
- | By setting ``${item.upload.title}`` to ``@Value`` annotation value, the value for read properties file key \ ``item.upload.title``\ gets substituted.
| ``uploadTitle`` is substituted by "list of update file" in String class.
* - | (2)
- | By setting ``${item.upload.dir}`` to ``@Value`` annotation value, the value for read properties file key \ ``item.upload.dir``\ gets substituted.
| \ ``org.springframework.core.io.Resource``\ object created with initial value "/tmp/upload" is stored in ``uploadDir``.
* - | (3)
- | By setting ``${item.upload.maxUpdateFileNum}`` to ``@Value`` annotation value, the value for read properties file key \ ``item.upload.maxUpdateFileNum``\ gets substituted.
| ``maxUpdateFileNum`` is substituted by 10.
.. warning::
There could be cases wherein properties values are to be used in static methods of Utility classes etc.; however properties value cannot be fetched using \ ``@Value``\ annotation in classes for which bean definition is not done.
In this case, it is recommended to create Helper class with ``@Component`` annotation and to fetch properties values using \ ``@Value``\ annotation. (This class needs to be included in the component-scan scope.)
Classes in which values from properties file is to be used, should not be made Utility classes.
|
How to extend
--------------------------------------------------------------------------------
Extension of method for fetching properties values is explained below. This can be achieved by
extending ``org.springframework.context.support.PropertySourcesPlaceholderConfigurer`` class.
The example below illustrates a case wherein encrypted properties file is used.
|
Decrypting encrypted values and using them
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| To strengthen security, properties file needs to be encrypted in some cases.
| The example below illustrates decryption of encrypted properties values. (No specific encrypting and decrypting methods are mentioned.)
**bean definition file**
- applicationContext.xml
- spring-mvc.xml
.. code-block:: xml
.. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}|
.. list-table::
:header-rows: 1
:widths: 10 90
* - Sr. No.
- Description
* - | (1)
- | Define the extended PropertySourcesPlaceholderConfigurer instead of ````\. ````\ tag should be deleted.
* - | (2)
- | Set "locations" in name attribute of property tag and specify the path of the properties file to be read, in value attribute.
| The method of specifying path of the properties file to be read is same as :ref:`technical-details_label`.
**Java class**
- Extended PropertySourcesPlaceholderConfigurer
.. code-block:: java
public class EncryptedPropertySourcesPlaceholderConfigurer extends
PropertySourcesPlaceholderConfigurer { // (1)
@Override
protected void doProcessProperties(
ConfigurableListableBeanFactory beanFactoryToProcess,
StringValueResolver valueResolver) { // (2)
super.doProcessProperties(beanFactoryToProcess,
new EncryptedValueResolver(valueResolver)); // (3)
}
}
.. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}|
.. list-table::
:header-rows: 1
:widths: 10 90
* - Sr. No.
- Description
* - | (1)
- | Inherited PropertySourcesPlaceholderConfigurer, should extend ``org.springframework.context.support.PropertySourcesPlaceholderConfigurer`` class.
* - | (2)
- | Override ``doProcessProperties`` method of ``org.springframework.context.support.PropertySourcesPlaceholderConfigurer`` class.
* - | (3)
- | Call ``doProcessProperties`` of parent class; however, use valueResolver( ``EncryptedValueResolver`` ) ``valueResolver`` wherein ``valueResolver`` is implemented independently.
| In ``EncryptedValueResolver`` class, decrypt when encrypted values of properties file are fetched.
|
- EncryptedValueResolver.java
.. code-block:: java
public class EncryptedValueResolver implements
StringValueResolver { // (1)
private final StringValueResolver valueResolver;
EncryptedValueResolver(StringValueResolver stringValueResolver) { // (2)
this.valueResolver = stringValueResolver;
}
@Override
public String resolveStringValue(String strVal) { // (3)
// Values obtained from the property file to the naming
// as seen with the encryption target
String value = valueResolver.resolveStringValue(strVal); // (4)
// Target messages only, implement coding
if (value.startsWith("Encrypted:")) { // (5)
value = value.substring(10); // (6)
// omitted decryption
}
return value;
}
}
.. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}|
.. list-table::
:header-rows: 1
:widths: 10 90
* - Sr. No.
- Description
* - | (1)
- | Inherited ``EncryptedValueResolver`` should implement ``org.springframework.util.StringValueResolver``.
* - | (2)
- | When ``EncryptedValueResolver`` class is created in constructor, set ``StringValueResolver`` inherited from ``EncryptedPropertySourcesPlaceholderConfigurer``.
* - | (3)
- | Override ``resolveStringValue`` method of ``org.springframework.util.StringValueResolver``.
| If the values fetched from properties file are encrypted, these must be decrypted in ``resolveStringValue`` method.
| The process mentioned in steps (5) and (6) is just an example, the process differs depending on type of implementation.
* - | (4)
- | The value is being fetched by specifying key as an argument of ``resolveStringValue`` method of ``StringValueResolver`` set in constructor. This value is defined in properties file.
* - | (5)
- | Check whether values of properties file are encrypted. The method to determine whether the values are encrypted differs depending on type of implementation.
| Here, the value can be considered encrypted if it starts with "Encrypted:".
| If the values are encrypted, decrypt them in step (6) and if they are not encrypted, return them as is.
* - | (6)
- | Encrypted values of properties file are being decrypted. (No specific decryption process is mentioned.)
| Decryption method differs depending on type of implementation.
- Helper to fetch properties
.. code-block:: java
@Value("${encrypted.property.string}") // (1)
private String testString;
@Value("${encrypted.property.int}") // (2)
private int testInt;
@Value("${encrypted.property.integer}") // (3)
private Integer testInteger;
@Value("${encrypted.property.file}") // (4)
private File testFile;
// Getters and setters omitted
.. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}|
.. list-table::
:header-rows: 1
:widths: 10 90
* - Sr. No.
- Description
* - | (1)
- | By setting ``${encrypted.property.string}`` to ``@Value`` annotation value, the value for read properties file key \ ``encrypted.property.string``\ is decrypted and then substituted.
| Value decrypted in String class is substituted in ``testString``.
* - | (2)
- | By setting ``${encrypted.property.int}`` to ``@Value`` annotation value, the value for read properties file key \ ``encrypted.property.int``\ is decrypted and then substituted.
| Value decrypted in integer type is substituted in ``testInt``.
* - | (3)
- | By setting ``${encrypted.property.integer}`` to ``@Value`` annotation value, the value for read properties file key \ ``encrypted.property.integer``\ is decrypted and then substituted.
| Value decrypted in Integer class is substituted in ``testInteger``.
* - | (4)
- | By setting ``${encrypted.property.file}`` to ``@Value`` annotation value, the value for read properties file key \ ``encrypted.property.file``\ is decrypted and then substituted.
| In ``testFile``, File object is stored as initial value which is created using the decrypted value (auto conversion).
**Properties file**
The values encrypted as properties values are prefixed with "Encrypted:" to indicate that they are encrypted.
Although one can view the contents of properties file, but cannot understand them as the values are encrypted.
.. code-block:: properties
encrypted.property.string=Encrypted:ZlpbQRJRWlNAU1FGV0ASRVteXhJQVxJXXFFAS0JGV1Yc
encrypted.property.int=Encrypted:AwI=
encrypted.property.integer=Encrypted:AwICAgI=
encrypted.property.file=Encrypted:YkBdQldARkt/U1xTVVdfV1xGHFpGX14=
.. raw:: latex
\newpage