- 在開發環境中,遷移是一個挑戰(比如Dev->QA, QA->Prod)
- 假設有個DB config,在Dev上可能使用的是EmbeddedDatabaseBuilder
@Bean(destroyMethod="shutdown") public DataSource dataSource() { return new EmbeddedDatabaseBuilder() .addScript("classpath:schema.sql") //schema會定義在schema.sql中 .addScript("classpath:test-data.sql")//data使用test-data.sql載入 .build(); }
- production環境可能會比較適合用JNDI從container中get DataSource
@Bean public DataSource dataSource() { JndiObjectFactoryBean jndiObjectFactoryBean = new JndiObjectFactoryBean(); jndiObjectFactoryBean.setJndiName("jdbc/myDS");
jndiObjectFactoryBean.setResourceRef(true);
jndiObjectFactoryBean.setProxyInterface(javax.sql.DataSource.class);
return (DataSource) jndiObjectFactoryBean.getObject(); }
- QA環境可能會使用完全不同的DataSource config
@Bean(destroyMethod="close") public DataSource dataSource() { BasicDataSource dataSource = new BasicDataSource(); dataSource.setUrl("jdbc:h2:tcp://dbserver/~/test"); dataSource.setDriverClassName("org.h2.Driver"); dataSource.setUsername("sa"); dataSource.setPassword("password"); dataSource.setInitialSize(20); dataSource.setMaxActive(30); return dataSource; }
- 問題:可以發現三種環境有三種不同的dataSource(),雖然都會有一個type是javax.sql.DataSource的bin
- 想法:必須有一種方法配置DataSource,使能夠在每種環境都能夠選擇最適合的config
- 如果是在單獨的config file中配置bean,在build時確定要使用哪個config file。這個的方法問題在於要為每個環境rebuild
- 在QA->Prod會不太安心
- 解決:Spring提供解法
- Configuring profile beans
- 優點:能夠在runtime的時候決定要使用的profile,而不是build time
- 要使用profile,要先將所有不同的bean定義到一個或多個profile中,在application deploy到environment的時候,要確認對應的profile已經是active
- 可以使用@Profile指定某個bean屬於哪個profile,如:
- @Profile("dev"),表示在dev profile active的時候才會create;若不是active,則class內的@Bean的會被呼略
@Configuration @Profile("dev") public class DevelopmentProfileConfig { @Bean(destroyMethod="shutdown") public DataSource dataSource() { return new EmbeddedDatabaseBuilder() .setType(EmbeddedDatabaseType.H2) .addScript("classpath:schema.sql") .addScript("classpath:test-data.sql") .build(); } }
@Profile("prod")
@Configuration @Profile("prod") public class ProductionProfileConfig { @Bean public DataSource dataSource() { JndiObjectFactoryBean jndiObjectFactoryBean = new JndiObjectFactoryBean(); jndiObjectFactoryBean.setJndiName("jdbc/myDS"); jndiObjectFactoryBean.setResourceRef(true); jndiObjectFactoryBean.setProxyInterface( javax.sql.DataSource.class); return (DataSource) jndiObjectFactoryBean.getObject(); } }
- 也可以在method level使用@Profile annotation,如此就能夠將@Bean一起放到config中
@Configuration public class DataSourceConfig { @Bean(destroyMethod="shutdown") @Profile("dev") public DataSource embeddedDataSource() { return new EmbeddedDatabaseBuilder() .setType(EmbeddedDatabaseType.H2) .addScript("classpath:schema.sql") .addScript("classpath:test-data.sql") .build(); } @Bean @Profile("prod") public DataSource jndiDataSource() { JndiObjectFactoryBean jndiObjectFactoryBean = new JndiObjectFactoryBean(); jndiObjectFactoryBean.setJndiName("jdbc/myDS");
jndiObjectFactoryBean.setResourceRef(true);
jndiObjectFactoryBean.setProxyInterface(javax.sql.DataSource.class);
return (DataSource) jndiObjectFactoryBean.getObject();
} }
- 注意:可能有其他bean沒有宣告profile,這樣的話這個bean始終都會被創建,與哪個profile active沒有關係
- 在XML中配置profile
- 使用XML配置,設定beans中的profile值
<beans ...(skip xmlns..)
profile="dev">
<jdbc:embedded-database id="dataSource"> <jdbc:script location="classpath:schema.sql" /> <jdbc:script location="classpath:test-data.sql" /> </jdbc:embedded-database>
- 也可以在root <beans>中嵌入<beans> element,而不是為每個environment都建立profile XML document,下例就是將所有profile bean定義放到同一個XML中
<beans profile="dev"> <!-- dev profile的bean--> <jdbc:embedded-database id="dataSource"> <jdbc:script location="classpath:schema.sql" /> <jdbc:script location="classpath:test-data.sql" /> </jdbc:embedded-database> </beans>
<beans profile="qa"> <!-- qa profile的bean--> <bean id="dataSource"
class="org.apache.commons.dbcp.BasicDataSource"
</beans><beans profile="prod"> <!-- prod profile的bean--> <jee:jndi-lookup id="dataSource"jndi-name="jdbc/myDatabase"resource-ref="true"proxy-interface="javax.sql.DataSource" />
</beans> </beans>- 注意上例,ID都是dataSource,但在runtime只會create一個bean,決定權在於active profile是哪個
- Active profile
- 會依賴兩個獨立的attribute
- spring.profiles.active
- spring.profiles.default
- 決定順序
- 有設定spring.profiles.active則會取active的值
- 沒有設定spring.profiles.active,則會找spring.profiles.default的值
- 都沒有設定,則沒有active profile,如此只會create沒有定義在profile中的bean
- 設定屬性的方式
- DispatcherServlet的初始值
- context parameters of a web application
- JNDI entries
- 環境變數
- JVM system properties
- 在integration test上使用@ActiveProfiles annotation
- 可以是:
- spring.profiles.active ()
- spring.profiles.default (設定為dev environment),且在Servlet context設定
- 如:在Web.xml中設定,如此在不同環境時,可視情況設 spring.profiles.active
<context-param> // context default profile <param-name>spring.profiles.default</param-name> <param-value>dev</param-value> </context-param> <servlet> <servlet-name>appServlet</servlet-name> <servlet-class> org.springframework.web.servlet.DispatcherServlet </servlet-class> <init-param> // Servlet default profile <param-name>spring.profiles.default</param-name> <param-value>dev</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet>
- profiles:表示可以時active多個profile,以list列出並用逗號分開
- 使用profile測試
- 通常在測試得時候會希望測試的config和production相同
- 可以使用@ActiveProfiles annotation,可以使用它來指定running的時候要active哪個profile
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes={PersistenceTestConfig.class}) @ActiveProfiles("dev") public class PersistenceTest { ... }
沒有留言:
張貼留言