Spring 3.1 新機能 - Bean Definition Profiles と Environment XML版
3.1からProfileという仕組みを使ってBeanの定義を簡単に切り替えられました。RailsとかGrailsだとかSeasar2とかにも似たのがありますね。それです。
やり方はXMLで定義する方法と、Javaのクラスに対してアノテーションを設定する方法がありますが、まずはXMLの方から見ていきます。
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.1.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd"> <context:property-placeholder location="classpath*:META-INF/spring/*.properties" /> <context:component-scan base-package="org.yamkazu.spring31" /> <bean class="org.springframework.orm.jpa.JpaTransactionManager" id="transactionManager"> <property name="entityManagerFactory" ref="entityManagerFactory" /> </bean> <tx:annotation-driven transaction-manager="transactionManager" /> <bean class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" id="entityManagerFactory"> <property name="persistenceUnitName" value="persistenceUnit" /> <property name="dataSource" ref="dataSource" /> </bean> <beans profile="production"> <bean class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" id="dataSource"> <property name="driverClassName" value="${database.driverClassName}" /> <property name="url" value="${database.url}" /> <property name="username" value="${database.username}" /> <property name="password" value="${database.password}" /> <property name="testOnBorrow" value="true" /> <property name="testOnReturn" value="true" /> <property name="testWhileIdle" value="true" /> <property name="timeBetweenEvictionRunsMillis" value="1800000" /> <property name="numTestsPerEvictionRun" value="3" /> <property name="minEvictableIdleTimeMillis" value="1800000" /> </bean> </beans> <beans profile="dev"> <jdbc:embedded-database id="dataSource" type="H2" /> </beans> </beans>
profileはbeansの属性として定義します。ここではproductionとdevという二つのProfileを定義して実行時のProfile情報を元にdataSourceが切り替わるようにしています。beansは上の様にbeansの中に入れ子にしてもいいですし(ネストで書けるようになったのは3.1からです)、従来通りファイル自体に切り離して、rootエレメントとして定義しても問題ありません。
あとは実行時にこのProfileを指定して実行するだけです。この実行時のProfileを指定するのがEnvironmentというしくみです。テストから見てみます。
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = "classpath:/META-INF/spring/*.xml") @ActiveProfiles({ "dev" }) public class AccountRepositoryTest { @Inject AccountRepository accountRepository; @Test public void 一件登録して取得する() { Account account = new Account(); account.setName("aaa"); accountRepository.persist(account); Account find = accountRepository.find(account.getId()); assertThat(find.getName(), is(equalTo("aaa"))); } }
従来のSpringのJUnitでテストをする設定に加えて@ActiveProfilesというアノテーションを指定してProfile情報を定義します。分かりやすいようにわざと配列形式で指定しましたが、有効にしたいProfileは複数定義することが可能です。実はProfileの定義も複数指定できます。例えば
<beans profile="dev1,dev2"> <jdbc:embedded-database id="dataSource" type="H2" /> </beans>
のような形です。
次はプログラム内でEnvironmentを指定する方法を見ていきます。
public class AccountRepositoryXmlTest { @Test public void 一件登録して取得する() { GenericXmlApplicationContext ctx = new GenericXmlApplicationContext(); ctx.getEnvironment().setActiveProfiles("dev"); ctx.load("classpath:/META-INF/spring/*.xml"); ctx.refresh(); AccountRepository accountRepository = ctx.getBean(AccountRepository.class); Account account = new Account(); account.setName("aaa"); accountRepository.persist(account); Account find = accountRepository.find(account.getId()); assertThat(find.getName(), is(equalTo("aaa"))); } }
contextのgetEnvironment().setActiveProfiles("xx")を呼び出して設定します。
実行時のシステムプロパティーに設定する方法もあります。
public class AccountRepositoryXmlTest { @Test public void 一件登録して取得する() { GenericXmlApplicationContext ctx = new GenericXmlApplicationContext(); ctx.load("classpath:/META-INF/spring/*.xml"); ctx.refresh(); AccountRepository accountRepository = ctx.getBean(AccountRepository.class); Account account = new Account(); account.setName("aaa"); accountRepository.persist(account); Account find = accountRepository.find(account.getId()); assertThat(find.getName(), is(equalTo("aaa"))); } }
上記のコードを
-Dspring.profiles.active="dev"
というspring.profiles.activeに有効にしたいprofileを指定することが出来ます。
ちなみにWebアプリケーションの場合はweb.xmlからEnvironmentを指定できます。
<servlet> <servlet-name>dispatcher</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>spring.profiles.active</param-name> <param-value>production</param-value> </init-param> </servlet>