高级装配 —— Spring profile
来源:互联网 发布:linux oracle 是否安装 编辑:程序博客网 时间:2024/06/07 11:54
Q:什么是 profile?
A:可以理解为我们在Spring容器中所定义的Bean的逻辑组名称。只有当这些 Profile 被激活的时候,才会将 Profile 中所对应的 Bean 注册到 Spring 容器中。
Q:为什么要使用 profile bean?
A: 因为在不同的环境中某个 bean 会有所不同。我们就必须得有一种方法来配置 bean,使其在每种环境下都会选择最为合适的配置。
其中一种方法:在单独的配置类(或 XML 文件)中配置每个 bean,然后在构建阶段(可能会使用 Maven 的 profiles)确定要将哪一个配置编译到可部署的应用中。然而,这种方法的问题在于要为每种环境重新构建应用。比如:发开阶段 -> QA 阶段时,需要重新构建。QA 阶段 -> 开发阶段,需要重新构建。
而 Spring 所提供的解决方案(profile bean):不需要重新构建。他不是在构建阶段做出决策,而是等到运行时再来确定要将哪一个配置编译到可部署的应用中。这样的好处就是:同一个部署单元(可能会是 WAR 文件)能够适用于所有的环境,没有必要进行重新构建。
如:在开发中,通常会出现在开发的时候使用一个开发数据库,测试的时候使用一个测试的数据库,而实际部署的时候需要一个数据库。环境的更改,每次都需要修改配置文件。但是使用 profile 就不需要了。
在 Spring 3.1 中,Spring 引入了 bean profile 的功能。
Q:怎么使用 profile?
A:首先要将所有不同的 bean 定义整理到一个或多个 profile 之中,再将应用部署到每个环境时,要确保对应的 profile 处于激活的状态。
Q:怎么配置 profile bean?
在 JavaConfig 中配置 profile
方式一:单个创建
package com.myapp;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 javax.activation.DataSource;/** * 在 Java 配置中,可以使用 @Profile 注解指定某个 bean 属于哪一个 profile。 * 在配置类中,嵌入式数据库的 DataSource 可能会配置成如下所示。 * * 注意:@Profile 注解应用在类级别上,它会告诉 Spring 这个配置类中的 bean 只有在 dev profile 激活时才会创建。 * 如果 dev profile 没有激活的话,那么带有 @Bean 注解的方法都会被忽略掉。 */@Configuration@Profile("dev")public class DevelopmentProfileConfig { @Bean public DataSource dataSource(){ return (DataSource) new EmbeddedDatabaseBuilder() .setType(EmbeddedDatabaseType.H2) .addScript("classpath:schema.sql") .addScript("classpath:test-data.sql") .build(); }}
可能还需要一个适用于生产环境的配置:
package com.myapp;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.context.annotation.Profile;import org.springframework.jndi.JndiObjectFactoryBean;import javax.activation.DataSource;/** * 只有 prod profile 激活时,才会创建对应的 bean。 */@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(); }}
在 Spring 3.1 中,只能在类级别上使用 @Profile 注解。不过,从 Spring 3.2 开始,你也可以在方法级别上使用 @Profile 注解,与 @Bean 注解一同使用。这样的话,就能将这两个 bean 的声明放到同一个配置类之中。
方式二:放在同一个配置类之中
package com.myapp;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;import javax.activation.DataSource;/** * @Profile 注解基于激活的 profile 实现 bean 的装配 * * 注意:尽管每个 DataSource bean 都被声明在一个 profile 中,并且只有当规定的 profile 激活时, * 相应的 bean 才会被创建,但是可能会有其他的 bean 并没有声明在一个给定的 profile 范围内。 * 没有指定 profile 的 bean 始终都会被创建,与激活哪个 profile 没有关系。 */@Configurationpublic class DataSourceConfig { @Bean @Profile("dev") //为 dev profile 装配的 bean public DataSource embeddedDataSource(){ return (DataSource) new EmbeddedDatabaseBuilder() .setType(EmbeddedDatabaseType.H2) .addScript("classpath:schema.sql") .addScript("classpath:test-data.sql") .build(); } @Bean @Profile("prod") //为 prod profile 装配的 bean 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 中配置 profile
方式一:单个配置文件
<?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:jdbc="http://www.springframework.org/schema/jdbc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd" profile="dev"> <!-- 通过<beans>元素的 profile 属性,在 XML 配置中配置 profile bean --> <!-- 定义了适用于开发阶段的嵌入式数据库 DataSource bean, 也可以将 profile 设置成 prod,创建适用于生产环境的从 JNDI 获取的 DataSource bean --> <jdbc:embedded-database id="dataSource"> <jdbc:script location="classpath:schema.sql"/> <jdbc:script location="classpath:test-data.sql"/> </jdbc:embedded-database></beans>
方式二:重复使用元素来指定多个 profile
<?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:jdbc="http://www.springframework.org/schema/jdbc" xmlns:jee="http://www.springframework.org/schema/jee" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd"> <!-- 这里的两个 bean ,类型都是 javax.sql.DataSource,并且ID 都是 dataSource 但是运行时,只会创建一个 bean,这取决于处于激活状态的是哪个 profile --> <!-- dev profile 的 bean --> <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> <!-- prod profile 的 bean --> <beans profile="prod"> <jee:jndi-lookup jndi-name="jdbc/myDatabase" id="dataSource" resource-ref="true" proxy-interface="javax.sql.DataSource"/> </beans></beans>
Q:怎么激活 profile?
Spring 在确定哪个 profile 处于激活状态时,需要依赖两个独立的属性:spring.profile.active 和 spring.profile.default。Spring 会先查找 active 再找 default,如果两个均没有设置的话,那就没有激活的 profile,因此只会创建哪些没有定义的在 profile 中的 bean。
Q:有哪些方式是来设置这两个属性呢?
A:
- 作为 DispatcherServlet 的初始化参数;
- 作为 Web 应用的上下文参数;
- 作为 JNDI 条目;
- 作为环境变量;
- 作为 JVM 的系统属性;
- 在集成测试上,使用 @ActiveProfiles 注解设置。
在 Web 应用中,设置 spring.profiles.default 的 web.xml 文件如下所示
这里采用的方法:使用 DispatcherServlet 的初始化参数将 spring.profiles.default 设置为开发环境的 profile,我会在 Servlet 上下文中进行设置(为了兼顾到 ContextLoaderListener)。
<?xml version="1.0" encoding="UTF-8"?><web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1"> <context-param> <param-name>contextConfigLocation</param-name> <!-- bean 配置所在的 xml --> <param-value>classpath:datesource.xml</param-value> </context-param> <!-- 为上下文设置默认的 profile:为了兼顾到 ContextLoaderListener --> <context-param> <param-name>spring.profiles.default</param-name> <param-value>dev</param-value> </context-param> <!-- 需要导入 spring-web --> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!-- 需要导入 spring-webmvc --> <servlet> <servlet-name>appServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <!-- 为 servlet 设置默认的 profile --> <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>
然后,当应用程序部署到 QA、生产或其他环境之中时,负责部署的人根据情况使用系统属性、环境变量或 JNDI 设置 spring.profiles.active 即可。当设置了 active 以后,default 的值就无所谓了。
Q:怎么同时激活多个 profile?
A:通过列出多个 profile 名称,并以逗号分隔来实现。
当运行继承测试时,通常会希望采用与生产环境(或者是生产环境的部分子集)相同的配置进行测试。
如果配置中的 bean 定义在了 profile 中,那么在运行测试时,就需要一种方式来启用合适的 profile。
Q:如何使用 profile 进行测试?
Spring 提供了@ActiveProfiles 注解,我们可以使用它来指定运行测试时需要激活哪个 profile。在集成测试时,通常想要激活的是开发环境的 profile。
/** * 使用 @ActiveProfiles 激活 dev profile * <p> * SpringJUnit4ClassRunner 需要导入 spring-test 包 */@RunWith(SpringJUnit4ClassRunner.class)// 设置配置文件@ContextConfiguration("classpath:datesource.xml")//@ContextConfiguration(classes = {PersistenceTestConfig.class})@ActiveProfiles("dev")public class PersistenceTest {}
在条件化创建 bean 方面,Spring 的 profile 机制是一种很棒的方法,这里的条件要基于哪个 profile 处于激活状态来判断。
Spring 4.0 中提供了一种更为通用的机制来实现条件化的 bean 定义,在这种机制中,条件完全由你来确定。那就是 @Conditional 注解定义条件化的 bean
上一篇:自动装配、JavaConfig、XML 三种方案之间,怎么导入和混合配置?
下一篇:高级装配 —— 条件化的 bean
- 高级装配 —— Spring profile
- 【Spring学习笔记】基于profile的高级装配
- Spring实战笔记——Bean的高级装配
- spring in action笔记(四)——高级装配
- Spring装配Bean——高级装配之与环境相关的bean
- Spring Bean 高级装配
- spring(3)高级装配
- 【Spring 核心】高级装配
- Spring 高级装配
- Spring 高级装配
- 【Spring】高级装配
- 【Spring】高级装配
- Spring高级装配
- Spring之高级装配
- 根据环境装配你的bean——Spring中profile的应用
- spring 第三章节 高级装配
- Spring入门之高级装配
- 读书笔记-spring高级装配bean
- 虚拟机类加载机制
- 利用插件制作安卓动画
- Zepto.js
- java中static{}语句块详解
- 数据库选型参考资料
- 高级装配 —— Spring profile
- 陈纪修老师《数学分析》 第09章:数项级数 笔记
- TCP三次握手和四次挥手
- Java关键字及作用解释
- Excel 技巧百例:字符串截取函数的经典组合示例
- 用 Android studio 查看源码细节
- 初学数据结构--读《数据结构》(人民邮电出版社)笔记
- Java动态代理
- 设计模式之建造者模式