1. 程式人生 > >Spring高階裝配術

Spring高階裝配術

1 Spring profile註解的使用

1.1 問題

在開發軟體的時候,有一個很大的挑戰就是將應用程式從一個環境遷移到另外一個環境去。很多時候資料庫配置,加密演算法以及外部系統整合等方面的配置都需要重新修改。這是個很大的問題

1.2 解決方案

Spring 提供了Profile註解,可以把開發環境、測試環境等許多環境統一配置到一起,然後軟體部署的環境調整一下引數即可,例如資料庫配置。
Java顯式配置

import javax.sql.DataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
import org.springframework.jndi.JndiObjectFactoryBean;

@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();
	}
}

XML配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xmlns:jdbc="http://www.springframework.org/schema/jdbc"
	xsi:schemaLocation="http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-4.1.xsd
		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
		http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">

	<beans profile = "dev">
		<jdbc:embedded-database id = "dataSource">
			<jdbc:script location = "classpath:schema.sql"/>
			<jdbc:script location = "classpath:test-data.sql"/>
		</jdbc:embedded-database>
	</beans>
	
	<beans profile = "prod">
		<jee:jndi-lookup id = "dataSource"
						jndi-name = "jdbc/myDatabase"
						resource-ref = "true" 
						proxy-interface = "javax.sql.DataSource" />
	</beans>
</beans>

啟用profile
Spring在確定哪個profile處於啟用狀態時,需要依賴兩個獨立的屬性:spring.profiles.active和spring.profiles.default。有多種方式來設定這兩個屬性,如:

  • 作為DispactcherServlet的初始化引數;
  • 作為Web應用的上下文引數;
  • 作為JNDI條目;
  • 作為環境變數;
  • 作為JVM的系統屬性;
  • 在整合測試類上,使用@ActiveProfiles註解;

這裡使用DispactcherServlet作為示例

<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
    http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>/WEB-INF/spring/root-context.xml</param-value>
	</context-param>
	<context-param>
		<param-name>spring.profiles.default</param-name>
		<param-value>dev</param-value>
	</context-param>
	<listener>
		<listener-class>
			org.springframework.web.context.ContextLoaderListener
		</listener-class>
	</listener>
	<servlet>
		<servlet-name>appServlet</servlet-name>
		<servlet-class>
			org.springframework.web.servlet.DispatcherServlet
		</servlet-class>
		<init-param>
			<param-name>spring.profiles.default</param-name>
			<param-value>dev</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>
	<servlet-mapping>
		<servlet-name>appServlet</servlet-name>
		<url-pattern>/</url-pattern>
	</servlet-mapping>
</web-app>

根據上述配置,實際上預設是dev環境如果,需要切換執行環境的時候可以在程式碼上增加@ActiveProfiles註解
例如:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = PersistenceTestConfig.class)
@ActiveProfiles("dev")
public class PersistenceTest{
	···
}

2 條件化的bean宣告

2.1 應用場景描述

假設希望一個或多個bean只有在特定條件滿足時才建立就需要為bean宣告條件,這樣就可以在滿足特定條件才建立這個bean.

2.2 例子

舉個例子,假設有一個名為MagicBean的類,希望只有設定了magic環境屬性的時候,Spring才會例項化這個類,如果環境沒有這個屬性,MagicBean將被忽略。

程式清單:

  1. MagicBean.java – bean
  2. MagicConfig.java – 顯式配置類
  3. MagicExistsCondition.java – 條件

MagicBean.java

public class MagicBean {
	public void play(){
		System.out.println("測試");
	}
}

MagicConfig.java

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;

public class MagicConfig {
	@Bean
	@Conditional(MagicExistsCondition.class)
	public MagicBean magicBean(){
		return new MagicBean();
	}
}

MagicExistsCondition.java

import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotatedTypeMetadata;

public class MagicExistsCondition implements Condition {
	@Override
	public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
		Environment env = context.getEnvironment();
		return env.containsProperty("magic");
	}
}

編寫好以上程式就可以實現在一定條件下建立bean了