Neste artigo, introduzi os perfis do Spring 3.1, expliquei ambos os casos de negócio para usá-los e demonstrei o uso deles com arquivos de configuração do Spring XML. Parece, no entanto, que boa parte dos desenvolvedores prefere usar a configuração do aplicativo baseado em Java do Spring, e aí o Spring designou um modo de usar os perfis com a sua anotação existente @Configuration.
Vou demonstrar os perfis e a anotação @Configuration usando a classe Person do meu artigo anterior. Esta é uma classe bean simples, cujas propriedades variam dependendo de qual perfil está ativo.
public class Person { private final String firstName; private final String lastName; private final int age; public Person(String firstName, String lastName, int age) { this.firstName = firstName; this.lastName = lastName; this.age = age; } public String getFirstName() { return firstName; } public String getLastName() { return lastName; } public int getAge() { return age; } }
Lembre-se de que os caras do Spring recomendam que os perfis do Spring só devem ser usados quando você precisa carregar diferentes tipos ou conjuntos de classes e que para a definição de propriedades você deve continuar usando o PropertyPlaceholderConfigurer. A razão de eu estar quebrando as regras é que eu quero tentar escrever o código mais simples possível para demonstrar os perfis e a configuração Java.
No coração do uso de perfis do Spring com configuração Java está a nova anotação do Spring @Profile. Ela é usada anexada a um nome de perfil para uma anotação @Configuration. Ela usa um único parâmetro que pode ser utilizado de duas maneiras. Primeiro para anexar um único perfil para uma anotação @Configuration:
@Profile("test1")
e, segundo, para anexar vários perfis:
@Profile({ "test1", "test2" })
Mais uma vez, vou definir dois perfis, “test1” e “test2”, e associar cada um a um arquivo de configuração. Primeiro, o “test1”:
@Configuration @Profile("test1") public class Test1ProfileConfig {@Bean public Person employee() { return new Person("John", "Smith", 55); } }
E depois o “test2”:
@Configuration @Profile("test2") public class Test2ProfileConfig { @Bean public Person employee() { return new Person("Fred", "Williams", 22); } }
Perceba que no código acima eu estou criando um bean Person com uma id efetivo de employee (este é o nome do método) que retorna diferentes valores de propriedade em cada perfil.
Observe também que o @Profile está marcado como:
@Target(value=TYPE)
… o que significa que ele só pode ser colocado ao lado da anotação @Configuration.
Anexando um @Profile a um @Configuration, a próxima coisa a fazer é ativar o seu @Profile selecionado. Isso utiliza exatamente os mesmos princípios e as mesmas técnicas que eu descrevi neste artigo e, novamente, a meu ver, a técnica de ativação mais útil é usar a propriedade de sistema “spring.profiles.active”.
@Test public void testProfileActiveUsingSystemProperties() { System.setProperty("spring.profiles.active", "test1"); ApplicationContext ctx = new ClassPathXmlApplicationContext("profiles-config.xml"); Person person = ctx.getBean("employee", Person.class); String firstName = person.getFirstName(); assertEquals("John", firstName); }
Obviamente, você não vai querer fazer coisas “hard code” como fiz acima e manter as melhores práticas geralmente significa manter as propriedades de configuração do sistema separadas do seu aplicativo. Isso te dá a opção de usar um argumento de linha de comando simples, como:
-Dspring.profiles.active="test1"
… ou adicionando
# Setting a property value spring.profiles.active=test1
a catalina.properties do Tomcat.
Então, isto é tudo: você cria seus perfis do Spring anotando uma an @Configuration com uma @Profile e então ativa o perfil que deseja usar, definindo a propriedade do sistema spring.profiles.active ao nome do seu profile.
Como de costume, os caras do Spring não só limitam você a usar as propriedades do sistema para ativar perfis, você pode fazer coisas programaticamente (nem sei se existe essa palavra, mas era a mais próxima). Por exemplo, o código a seguir cria um AnnotationConfigApplicationContext e depois usa um objeto Environment para ativar o perfil “test1” antes de registrar nossas classes @Configuration.
@Test public void testAnnotationConfigApplicationContextThatWorks() { // Can register a list of config classes AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); ctx.getEnvironment().setActiveProfiles("test1"); ctx.register(Test1ProfileConfig.class, Test2ProfileConfig.class); ctx.refresh(); Person person = ctx.getBean("employee", Person.class); String firstName = person.getFirstName(); assertEquals("John", firstName); }
Tudo isso é lindo e bom, mas cuidado! Você precisa chamar os métodos de AnnotationConfigApplicationContext na ordem certa. Por exemplo, se você registrar suas classes @Configuration antes de especificar o seu perfil, então você vai ter um IllegalStateException.
@Test(expected = IllegalStateException.class) public void testAnnotationConfigApplicationContextThatFails() { // Can register a list of config classes AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext( Test1ProfileConfig.class, Test2ProfileConfig.class); ctx.getEnvironment().setActiveProfiles("test1"); ctx.refresh(); Person person = ctx.getBean("employee", Person.class); String firstName = person.getFirstName(); assertEquals("John", firstName); }
Antes de encerrar o artigo de hoje, o código abaixo demonstra a capacidade de anexar múltiplos @Profile para uma anotação @Configuration.
@Configuration @Profile({ "test1", "test2" }) public class MulitpleProfileConfig { @Bean public Person tourDeFranceWinner() { return new Person("Bradley", "Wiggins", 32); } }
@Test public void testMulipleAssignedProfilesUsingSystemProperties() { System.setProperty("spring.profiles.active", "test1"); ApplicationContext ctx = new ClassPathXmlApplicationContext("profiles-config.xml"); Person person = ctx.getBean("tourDeFranceWinner", Person.class); String firstName = person.getFirstName(); assertEquals("Bradley", firstName); System.setProperty("spring.profiles.active", "test2"); ctx = new ClassPathXmlApplicationContext("profiles-config.xml"); person = ctx.getBean("tourDeFranceWinner", Person.class); firstName = person.getFirstName(); assertEquals("Bradley", firstName); }
No código acima, o vencedor do Tour de France 2012, Bradley Wiggins, aparece tanto no perfil “test1” quanto no “test2”.
***
Texto original disponível em http://www.captaindebug.com/2012/08/using-spring-profiles-and-java.html#.UPdhKif7KSo