Gerenciamento de Propriedades em Aplicações Spring com @PropertySource e @Value

Introdução

Em projetos Spring, a configuração flexível de propriedades é essencial para adaptar uma aplicação a diferentes ambientes sem a necessidade de recompilação. Este artigo explora como carregar e utilizar valores de arquivos de propriedades externos usando as anotações @PropertySource e @Value. Além disso, abordaremos a interface Environment do Spring para acesso programático às propriedades e faremos uma comparação entre a configuração baseada em anotações e a configuração XML tradicional.

A anotação @PropertySource é utilizada em classes de configuração (marcadas com @Configuration) para especificar a localização de arquivos de propriedades, tornando seus valores acessíveis ao contexto da aplicação através da interface Environment. Já a anotação @Value oferece uma maneira direta de injetar valores de propriedades em campos ou parâmetros de métodos, suportando também a definição de valores padrão.

Vamos construir um exemplo prático para ilustrar essas capacidades.

Tecnologias e Ferramentas

  • Spring Framework 4.0.6.RELEASE
  • Maven 3
  • JDK 1.6+
  • IDE (Eclipse JUNO ou similar)

Estrutura do Projeto

A estrutura do projeto será organizada da seguinte forma:


my-spring-app
├── pom.xml
└── src
    └── main
        ├── java
        │   └── com
        │       └── example
        │           └── spring
        │               ├── AppMain.java
        │               ├── config
        │               │   └── ApplicationPropertiesConfig.java
        │               └── service
        │                   ├── DataProcessorService.java
        │                   └── DataProcessorServiceImpl.java
        └── resources
            ├── app-config.xml
            └── application.properties

Passo 1: Configuração do Maven (pom.xml)

Primeiro, configuraremos as dependências necessárias no arquivo pom.xml do Maven para incluir os módulos core e context do Spring Framework.

<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.example.spring</groupId>
    <artifactId>spring-property-example</artifactId>
    <version>1.0.0-SNAPSHOT</version>
    <packaging>jar</packaging>
 
    <name>Exemplo de Propriedades Spring</name>
 
    <properties>
        <springframework.version>4.0.6.RELEASE</springframework.version>
        <maven.compiler.source>1.6</maven.compiler.source>
        <maven.compiler.target>1.6</maven.compiler.target>
    </properties>
 
    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${springframework.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${springframework.version}</version>
        </dependency>
    </dependencies>
    <build>
        <pluginManagement>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>3.2</version>
                    <configuration>
                        <source>${maven.compiler.source}</source>
                        <target>${maven.compiler.target}</target>
                    </configuration>
                </plugin>
            </plugins>
        </pluginManagement>
    </build>
</project>

Passo 2: Criação da Classe de Configuração Spring

Uma classe de configuração Spring, anotada com @Configuration, serve como uma fonte de definições de beans. Nesta classe, utilizaremos @PropertySource para indicar o arquivo de propriedades a ser carregado e @ComponentScan para que o Spring varra os componentes da aplicação.

package com.example.spring.config;
 
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
 
@Configuration
@ComponentScan(basePackages = "com.example.spring")
@PropertySource(value = { "classpath:application.properties" })
public class ApplicationPropertiesConfig {
 
    /*
     * O bean PropertySourcesPlaceholderConfigurer é necessário para que as anotações @Value("${...}")
     * resolvam os placeholders de propriedades.
     * Se você não estiver usando @Value para injetar propriedades, este bean pode ser omitido.
     */
    @Bean
    public static PropertySourcesPlaceholderConfigurer propertyPlaceholderConfigurer() {
        return new PropertySourcesPlaceholderConfigurer();
    }
}

A anotação @PropertySource(value = { "classpath:application.properties" }) instrui o Spring a carregar o arquivo application.properties do classpath. As propriedades definidas neste arquivo ficarão disponíveis através da interface Environment do Spring.

O PropertySourcesPlaceholderConfigurer é crucial para que o Spring consiga substituir os placeholders ${...} em anotações @Value ou em definições XML por valores reais das propriedades. Sem ele, os placeholders não seriam resolvidos e seriam tratados como strings literais.

Configuração Equivalente via XML

Para aqueles que preferem XML, a configuração acima pode ser expressa da seguinte maneira no arquivo app-config.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-4.0.xsd
    http://www.springframework.org/schema/context   http://www.springframework.org/schema/context/spring-context-4.0.xsd">
 
    <!-- Habilita a varredura de componentes no pacote especificado -->
    <context:component-scan base-package="com.example.spring"/>
 
    <!-- Configura um PropertySourcesPlaceholderConfigurer para resolver placeholders (${...}) -->
    <bean class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer">
        <!-- Define se placeholders não resolvidos devem ser ignorados ou lançar uma exceção -->
        <property name="ignoreUnresolvablePlaceholders" value="true"/>
        <!-- Especifica a localização dos arquivos de propriedades -->
        <property name="locations">
          <list>
            <value>classpath:application.properties</value>
          </list>
        </property>
      </bean>
</beans>

Passo 3: Criação do Arquivo de Propriedades

Vamos criar o arquivo application.properties dentro da pasta src/main/resources com as seguintes propriedades:

db.driver = org.postgresql.Driver
db.url = jdbc:postgresql://localhost:5432/myappdb
db.user = appuser
db.pass = appsecret
app.loglevel = DEBUG
data.input.path = /app/data/input

Passo 4: Criação do Serviço

Definiremos uma interface e uma implementação de serviço para demonstrar como as propriedades são injetadas e acessadas.

Interface DataProcessorService

package com.example.spring.service;
 
public interface DataProcessorService {
    void processConfiguration();
}

Implementação DataProcessorServiceImpl

package com.example.spring.service;
 
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("dataProcessorService")
public class DataProcessorServiceImpl implements DataProcessorService {
 
    // Injeta o valor da propriedade 'data.input.path' ou usa um valor padrão se não encontrada
    @Value("${data.input.path:/tmp/entrada}")
    private String inputDirectory;
 
    // Injeta o valor da propriedade 'data.output.path' ou usa um valor padrão
    @Value("${data.output.path:/tmp/saida}")
    private String outputDirectory;

    // Injeta o valor da propriedade 'app.loglevel' ou usa um valor padrão
    @Value("${app.loglevel:INFO}")
    private String logLevel;
 
    // A interface Environment é injetada automaticamente pelo Spring
    @Autowired
    private Environment appEnvironment;
 
    public void processConfiguration() {
        System.out.println("Acessando propriedade 'db.driver' via Spring Environment: "
                + appEnvironment.getProperty("db.driver"));
        
        System.out.println("URL do Banco de Dados via Environment: "
                + appEnvironment.getProperty("db.url"));
 
        System.out.println("Diretório de Entrada: " + inputDirectory);
        System.out.println("Diretório de Saída: " + outputDirectory);
        System.out.println("Nível de Log da Aplicação: " + logLevel);
    }
}

Nesta implementação, a interface Environment é injetada automaticamente pelo Spring. Como ApplicationPropertiesConfig foi anotada com @PropertySource, o Environment pode acessar todas as propriedades definidas em application.properties. Usamos o método getProperty() para recuperá-las.

As anotações @Value são usadas para injetar diretamente os valores das propriedades nos campos inputDirectory, outputDirectory e logLevel. O formato ${chave:valorPadrao} permite especificar um valor padrão que será usado caso a propriedade chave não seja encontrada no arquivo application.properties.

É fundamental lembrar que o PropertySourcesPlaceholderConfigurer é quem viabiliza a resolução desses placeholders ${...}. Sem ele, o Spring trataria "${data.input.path:/tmp/entrada}" como uma string literal, e não como um placeholder a ser resolvido.

Passo 5: Criação da Clase Principal (Main)

Finalmente, uma clase AppMain para iniciar o contexto Spring e executar o serviço.

package com.example.spring;
 
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.example.spring.config.ApplicationPropertiesConfig;
import com.example.spring.service.DataProcessorService;
 
public class AppMain {
     
    public static void main(String[] args){
        // Inicializa o contexto Spring usando a configuração baseada em anotações
        AbstractApplicationContext context = new AnnotationConfigApplicationContext(ApplicationPropertiesConfig.class);
        
        // Obtém a instância do serviço do contexto Spring
        DataProcessorService service = (DataProcessorService) context.getBean("dataProcessorService");
         
        // Executa o método do serviço para processar as configurações
        service.processConfiguration();
        
        // Fecha o contexto da aplicação para liberar recursos
        context.close();

        System.out.println("\n--- Exemplo com Configuração XML ---");
        // Para usar a configuração XML, descomente a linha abaixo e comente a linha de AnnotationConfigApplicationContext
        // AbstractApplicationContext xmlContext = new ClassPathXmlApplicationContext("app-config.xml");
        // DataProcessorService xmlService = (DataProcessorService) xmlContext.getBean("dataProcessorService");
        // xmlService.processConfiguration();
        // xmlContext.close();
    }
     
}

Execução do Programa

Ao executar a classe AppMain, a saída esperada será:

Acessando propriedade 'db.driver' via Spring Environment: org.postgresql.Driver
URL do Banco de Dados via Environment: jdbc:postgresql://localhost:5432/myappdb
Diretório de Entrada: /app/data/input
Diretório de Saída: /tmp/saida
Nível de Log da Aplicação: DEBUG

Note que a propriedade data.output.path não foi definida em application.properties, portanto, seu valor padrão (/tmp/saida) foi utilizado, conforme especificado na anotação @Value em DataProcessorServiceImpl.

Se você optar por usar a configuração XML, substituindo AnnotationConfigApplicationContext por ClassPathXmlApplicationContext("app-config.xml") e ajustando os nomes dos beens e pacotes conforme o exemplo, você obterá a mesma saída.

Tags: Spring Framework PropertySource Value Annotation Spring Configuration Environment Interface

Publicado em 8-7 06:07