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.