Ficheros de propiedades en Spring

Última actualización: 02/03/2019

logo spring

 A la hora de utilizar el contenedor de Spring es una buena práctica separar la configuración de los beans, parcial o totalmente realizada en ficheros XML o clases de configuración, y los parámetros de configuración que utilizan esos beans como por ejemplo contraseñas o la ubicación de la base de datos. La ventaja de seguir este criterio es doble:

  • Los parámetros de configuración son fácilmente localizables y no están diseminados en los ficheros XML de Spring o, peor todavía, definidos en el código.
  • La configuración es fácilmente modificable por cualquier persona, como por ejemplo un administrador de sistemas, aunque no tenga conocimientos de Spring.

Lo habitual es definir los parámetros de configuración en ficheros de propiedades estándar de Java (.properties). Spring permite utilizar cómodamente este tipo de ficheros tal y como vamos a ver.

Proyecto para pruebas

Para las pruebas se usará un proyecto Maven consistente en un bean que se definirá en Spring y en el que se quiere utilizar un valor definido en un fichero .properties. Asimismo, se usará una clase Main.

En el pom.xml sólo se incluirá como dependencia spring-core en la versión 4.3.22. Cualquier incompatibilidad entre la versión de Spring y el código utilizado en este artículo se indicará expresamente.

<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0    	http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.danielme.blog.spring.properties</groupId>
    <artifactId>pruebaSpring-properties</artifactId>
    <version>1.0</version>
    <name>pruebaSpring-properties</name>

    <description>Ejemplo de utilización en Spring ioC de ficheros .properties.</description>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.build.mainClass>com.danielme.blog.spring.properties.Main</project.build.mainClass>
        <java.version>1.6</java.version>
        <spring.version>4.3.22.RELEASE</spring.version>
        <maven.jar.plugin.version>3.1.1</maven.jar.plugin.version>
        <maven.compiler.plugin.version>3.8.0</maven.compiler.plugin.version>
        <maven.exec.plugin.version>1.6.0</maven.exec.plugin.version>

    </properties>

    <developers>
        <developer>
            <id>dmedina</id>
            <name>Daniel Medina</name>
            <email>danielme_com@yahoo.com</email>
            <url>http://danielme.com</url>
            <roles>
                <role>developer</role>
            </roles>
        </developer>
    </developers>

    <licenses>
        <license>
            <name>El presente proyecto Maven es el código de ejemplo utilizado en el tutorial "Ficheros .properties en Spring IoC", 
			publicado con licencia Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0  Unported en la web 	
      "http://danielme.com"</name>
        </license>
    </licenses>

    <build>
        <pluginManagement>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-jar-plugin</artifactId>
                    <version>${maven.jar.plugin.version}</version>
                    <configuration>
                        <archive>
                            <manifest>
                                <addClasspath>true</addClasspath>
                                <mainClass>${project.build.mainClass}</mainClass>
                            </manifest>
                        </archive>
                    </configuration>
                </plugin>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>${maven.compiler.plugin.version}</version>
                    <configuration>
                        <source>${java.version}</source>
                        <target>${java.version}</target>
                        <encoding>${project.build.sourceEncoding}</encoding>
                    </configuration>
                </plugin>
                <plugin>
                    <groupId>org.codehaus.mojo</groupId>
                    <artifactId>exec-maven-plugin</artifactId>
                    <version>${maven.exec.plugin.version}</version>
                    <executions>
                        <execution>
                            <goals>
                                <goal>java</goal>
                            </goals>
                        </execution>
                    </executions>
                    <configuration>
                        <mainClass>${project.build.mainClass}</mainClass>
                    </configuration>
                </plugin>
            </plugins>
        </pluginManagement>
    </build>

    <dependencies>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>

    </dependencies>

</project>

El bean en el que se realizará la inyección:

package com.danielme.blog.spring.properties;

public class BeanSpring {

    private Integer cantidad;

    private String usuario;

    public Integer getCantidad() {
        return cantidad;
    }

    public String getUsuario() {
        return usuario;
    }

}

y su definición en el springContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd">

	<bean id="beanSpring" class="com.danielme.blog.spring.properties.BeanSpring" />

</beans>

En la clase Main, se inicia el contexto de Spring y se recupera el bean

package com.danielme.blog.spring.properties;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * Ficheros .properties en Spring
 * 
 * @author danielme.com
 * 
 */
public class Main {

    public static void main(String[] args) {
        // Se inicia programáticamente el contenedor de Spring y se obtiene el bean
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext(
                "/springContext.xml");
        BeanSpring beanSpring = (BeanSpring) applicationContext.getBean("beanSpring");

        System.out.println(
                "cantidad: " + beanSpring.getCantidad() + ", usuario: " + beanSpring.getUsuario());
    }

}

Y por último, el fichero que justifica la redacción de este artículo (config.properties):

valor.usuario = usuario
valor.cantidad = 10

Método «tradicional» en XML

En primer lugar hay que «importar» el fichero .properties, y se puede hacer dos formas distintas

  1. Definiendo directamente un PropertyPlaceholderConfigurer que contendrá todos los .properties que queramos utilizar.
    <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    	<property name="location">
    		<value>classpath:config.properties</value>
    	</property>
    </bean>	
    
  2. Más fácil todavía con context:property-placeholder (OJO: sólo disponible a partir de Spring 2.5)
    <context:property-placeholder location="classpath:config.properties" />
    

    Para importar más de un fichero, simplemente se separan con comas. También se pueden importar todos.

    <context:property-placeholder location="classpath:*.properties" />
    

Nota: se pueden importar .properties desde cualquier ubicación utilizando un location como «file:///C:\\configuraciones\\config.properties». Esta posibilidad puede ser interesante para facilitar la modificación de las propiedades en cualquier momento (los cambios no se aplicarán hasta que la aplicación se reinicie).

Ahora ya estamos en condiciones de inyectar los valores de los parámetros definidos en el config.properties

	<bean id="beanSpring" class="com.danielme.blog.spring.properties.BeanSpring">
		<property name="cantidad" value="${valor.cantidad}" />
		<property name="usuario" value="${valor.usuario}" />
	</bean>

Y listo. Ejecutamos nuestro Main (si no usamos un IDE se puede hacer desde la línea de comandos con «mvn clean package exec:java») para comprobar que la inyección se ha realizado correctamente, y que incluso el número se ha inyectado en un Integer. No obstante, deberemos tener cuidado con estas conversiones ya que son susceptibles de provocar un hermoso java.lang.NumberFormatException.

¿Qué pasaría si inyectamos una propiedad que no existe? Si eliminamos valor.usuario del properties obtendremos este error

Caused by: java.lang.IllegalArgumentException: Could not resolve placeholder 'valor.usuario' in value "${valor.usuario}"
	at org.springframework.util.PropertyPlaceholderHelper.parseStringValue(PropertyPlaceholderHelper.java:174)
	at org.springframework.util.PropertyPlaceholderHelper.replacePlaceholders(PropertyPlaceholderHelper.java:126)

Para permitir que una propiedad a inyectar no tenga que existir usaremos el atributo ignore-unresolvable.

<context:property-placeholder location="classpath:config.properties" ignore-unresolvable="true/>

Con anotaciones

Si usamos Spring 3.1 se pueden inyectar los valores de los parámetros de los .properties utilizando la anotación @Value. En nuestro ejemplo, primero tendríamos que habilitar el «autowiring» mediante anotaciones en el springContext.xml y eliminar la inyección en beanSpring de las propiedades cantidad y usuario. Pero vamos a ir un paso más allá y realizar la definición del propio bean con anotaciones. Así pues, el fichero quedaría así:

	<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd">

<!-- ruta en la que se buscarán los beans anotados -->
<context:component-scan base-package="com.danielme" />	

<context:property-placeholder location="classpath:config.properties" />
	
</beans>

Ahora tendremos que anotar el bean con @Service para que los instancie el contenedor y hacer la inyección con @Value. Esta inyección se va a hacer directamente en los atributos por lo que se puede prescindir de los setters si se crearon sólo para poder inyectar las dependencias.

package com.danielme.blog.spring.properties;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

@Service
public class BeanSpring {

    @Value("${valor.cantidad}")
    private Integer cantidad;

    @Value("${valor.usuario}")
    private String usuario;

    public Integer getCantidad() {
        return cantidad;
    }

    public String getUsuario() {
        return usuario;
    }

}

Como vemos, gracias a Spring 3.1 podemos seguir reduciendo los XML en favor del uso de anotaciones siguiendo la tendencia impulsada por JEE y que poco a poco se va imponiendo en el mundo Spring.

En el caso de que estemos usando una versión anterior a Spring 3.1, se puede realizar también la inyección mediante autowired definiendo los valores de los properties como beans de Spring de la siguiente forma:

<bean id="cantidad" class="java.lang.Integer">
  <constructor-arg value="${valor.cantidad}"/>
</bean>

<bean id="usuario" class="java.lang.String">
  <constructor-arg value="${valor.usuario}"/>
</bean>

Es una solución menos elegante y limpia que la anterior pero nos permite seguir definiendo y configurando los beans con anotaciones en versiones muy antiguas de Spring.

Configuración programática

Este tutorial fue publicado originalmente en 2012 y desde hace varios años el uso de Spring mediante ficheros XML ha sido abandonado en favor de configuraciones programáticas en clases (Java Config) algo que resultaba muy novedoso cuando fue escrito el tutorial. En nuestro ejemplo, el fichero springContext.xml puede ser reemplazado por la siguiente clase.

package com.danielme.blog.spring.properties;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;

@Configuration
@PropertySource("classpath:config.properties")
@ComponentScan("com.danielme.blog.spring.properties")
public class SpringConfiguration {

}

Las anotaciones @PropertySource y @ComponentScan equivalen a los tags context:component-scan y context:property-placeholder respectivamente. Para arrancar Spring con esta clase usaremos la siguiente instrucción.

ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfiguration.class);

Al cargar los ficheros con la anotación @PropertySource, además de utilizar @Value es posible acceder a todas las propiedades a través de la clase Environment.

package com.danielme.blog.spring.properties;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Service;

@Service
public class BeanSpring {

    @Autowired
    Environment enviroment;

    @Value("${valor.cantidad}")
    private Integer cantidad;

    @Value("${valor.usuario}")
    private String usuario;

    public Integer getCantidad() {
        return cantidad;
    }

    public String getUsuario() {
        return enviroment.getProperty("valor.usuario");
        // return usuario;
    }

}

Código de ejemplo

El proyecto completo se encuentra en Github. Para más información sobre cómo utilizar GitHub, consultar este artículo.

Otros tutoriales relacionados con Spring

Testing en Spring Boot con JUnit 4\5. Mockito, MockMvc, REST Assured, bases de datos embebidas

Introducción a Spring Boot: Aplicación Web con servicios REST y Spring Data JPA

Spring JDBC Template: simplificando el uso de SQL

Persistencia en BD con Spring Data JPA

Persistencia en BD con Spring: Integrando JPA, c3p0, Hibernate y EHCache

Testing Spring con JUnit 4

2 comentarios sobre “Ficheros de propiedades en Spring

  1. Tengo el siguiente problema:

    Fichero Spring.xml:

    Conexion.java:

    @Service
    public class Conexion {

    @Value(«${mysql.url}»)
    private String url;

    @Value(«${mysql.user}»)
    private String user;

    @Value(«${mysql.password}»)
    private String password;

    @Value(«${mysql.driver}»)
    private String driver;

    public String getUrl() {
    return url;
    }
    public String getUser() {
    return user;
    }
    public String getPassword() {
    return password;
    }
    public String getDriver() {
    return driver;
    }
    }

    Como realizado la llamada por ejemplo al metodo getUrl() desde otra clase Java??

    1. Por que no utilizas un «datasource» lo defines en el archivo XML srpingContext, posteriormente realizas la inyeccion para que utilices en tus clases DAO, donde vayas a utilizar una conexcion, de esa manera Spring administra tus conexiones.

Replica a Gerardo Torreblanca Luna Cancelar la respuesta

Este sitio utiliza Akismet para reducir el spam. Conoce cómo se procesan los datos de tus comentarios.