1 应用程序环境的迁移

问题:

开发软件时,有一个很大的挑战,就是将应用程序从一个环境迁移到另一个环境。

例如,开发环境中很多方式的处理并不适合生产环境,迁移后需要修改,这个过程可能会莫名的出现很多bug,一个经常出现在程序员间有意思的问题是:在我那明明没问题啊,为什么到你那就不行了?

举个栗子,数据库配置,在开发环境我们可能使用一个嵌入式的数据源并在启动的时候加载进来,但是在生产环境中这是糟糕的做法,我们希望数据库能直接从JNDI中获取,或者是从连接池中获取。那么问题来了,当从开发环境迁移到生产环境中时,我们应该怎么做?

一个很好想到的办法是:配置多个xml文件,每个xml里面配置一种数据源。然后在构建阶段,确定哪一种数据源编译到可部署的应用中。

但是这样的做法缺点要为每种环境重新构建应用,从开发阶段迁移到QA(质量保证)阶段肯能没什么大问题,但是从QA迁移到生产阶段从新构建可能会出现bug,还QA个毛啊~

解答:

Spring为环境迁移提供的解决方案是profile功能,为bean配置profile注解,然后激活对应的profile。

怎么配置profile?下面有两种方式:

(1)基于Java配置

@Configuration
public class DataSourceConfig { @Bean
@Profile("dev")
public DataSource embeddedDataSource() { // 配置开发环境 嵌入式数据源 } @Bean
@Profile("prod")
public DataSource jndiDataSource() { // 配置生产环境 JNDI数据源 } }

(2)基于xml配置

<?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" xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="
http://www.springframework.org/schema/jee
http://www.springframework.org/schema/jee/spring-jee.xsd
http://www.springframework.org/schema/jdbc
http://www.springframework.org/schema/jdbc/spring-jdbc.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd"> <beans profile="dev">
<jdbc:embedded-database id="dataSource" type="H2">
<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"
lazy-init="true"
jndi-name="jdbc/myDatabase"
resource-ref="true"
proxy-interface="javax.sql.DataSource" />
</beans>
</beans>

怎么激活profile?

Spring在确定哪个profile处于激活状态时,需要依赖两个独立的属性:spring.profiles.active和spring.profiles.default。

如果设置了spring.profiles.active属性的话,那么它的值就会用来确定哪个profile是激活的。但如果没有设置spring.profiles.active,那Spring将会查找spring.profiles.default的值。如果两个属性都没配置,那么被@Profile注解的类都不会被加载。

有多种方式来设置这两个属性:

  • 作为DispatcherServlet的初始化参数;
  • 作为Web应用的上下文参数;
  • 作为JNDI条目;
  • 作为环境变量;
  • 作为JVM的系统属性;
  • 在集成测试类上,使用@ActiveProfiles注解设置。

如何配置这些初始化参数不是本文讨论的内容。但为了把例子解释清楚,这里以web应用上下文参数为例梳理整个流程,配置如下:

这里默认激活配置为dev的profile,所以启动应用时,以Java配置为例,注解@Profile("dev")标记的数据库连接类会被加载到spring容器中,@Profile("prod")标记的类不会被加载。

profile是spring3.1中出现的新功能,只能用于环境迁移的条件装配,但是spring4引入了Conditional功能,我们能灵活的处理条件化装配bean了,而且spring4也使用Conditional重构了profile,也就是说spring4之后,prefile是基于Conditional实现的。

2 条件装配bean

假如你希望一个或多个bean只有在应用的类路径下包含特定的库时才创建。或者我们希望某个bean只有当另外某个特定的bean也声明了之后才会创建。我们还可能要求只有某个特定的环境变量设置之后,才会创建某个bean。这些使用Conditional都能实现。

举个例子:假设有一个名为MagicBean的类,我们希望只有设置了magic环境属性的时候,Spring才会实例化这个类。如果环境中没有这个属性,那么MagicBean将会被忽略。

首先要有一个MagicBean,我们不关注它的功能与实现,只需要知道有这个bean就行。接下来配置:

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

只有满足MagicExistsCondition这个条件时,我们才实例化MagicBean。MagicExistsCondition需要实现Condition接口。Condition接口里面只有matches()方法,当实现类的matches()返回true时,条件才满足。否则条件不满足。MagicExistsCondition实现如下:

public class MagicExistsCondition implements Condition {

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

只有环境变量magic存在,matches才会返回true,条件才满足,MagicBean才会实例化。

参考文章《spring in action》

————完—————

spring的条件装配bean的更多相关文章

  1. Spring总结 1.装配bean

    本随笔内容要点如下: 依赖注入 Spring装配bean的方式 条件化装配 一.依赖注入 我理解的依赖注入是这样的:所谓的依赖,就是对象所依赖的其他对象.Spring提供了一个bean容器,它负责创建 ...

  2. Spring Framework 条件装配 之 @Conditional

    Spring Framework 条件装配 之 @Conditional 前言 了解SpringBoot的小伙伴对Conditional注解一定不会陌生,在SpringBoot项目中,Conditio ...

  3. Spring 之自动化装配 bean 尝试

    [Spring之自动化装配bean尝试] 1.添加dependencies如下所示(不是每一个都用得到 <dependencies> <dependency> <grou ...

  4. spring中自动装配bean

    首先用@Component注解类: package soundsystem: import org.springframework.stereotype.Component; @Component p ...

  5. spring的自动装配Bean与自动检测Bean

    spring可以通过编写XML来配置Bean,也可以通过使用spring的注解来装配Bean. 1.自动装配与自动检测: 自动装配:让spring自动识别如何装配bean的依赖关系,减少对<pr ...

  6. Spring学习笔记—装配Bean

    在Spring中,对象无需自己负责查找或创建与其关联的其他对象.相反,容器负责把需要相互协作的对象引用赋予各个对象.创建应用对象之间协作关系的行为通常称为装配(wiring),这也是依赖注入的本质. ...

  7. Spring系列之装配Bean

    Spring 的三种装配Bean的方式 组件扫描+自动装配(隐式) 通过Java config装配bean(显示) 通过XML装配bean(显示) 一.组件扫描+自动装配(隐式配置) 组件扫描: Sp ...

  8. spring实战三装配bean之Bean的作用域以及初始化和销毁Bean

    1.Bean的作用域 所有的spring bean默认都是单例.当容器分配一个Bean时,不论是通过装配还是调用容器的getBean()方法,它总是返回Bean的同一个实例.有时候需要每次请求时都获得 ...

  9. spring实战一:装配bean之注入Bean属性

    内容参考自spring in action一书. 创建应用对象之间协作关系的行为通常称为装配,这也是依赖注入的本质. 1. 创建spring配置 spring是一个基于容器的框架.如果没有配置spri ...

随机推荐

  1. SGU 261. Discrete Roots

    给定\(p, k, A\),满足\(k, p\)是质数,求 \[x^k \equiv A \mod p\] 不会... upd:3:29 两边取指标,是求 \[k\text{ind}_x\equiv ...

  2. 201. Non Absorbing DFA

    题意好难看懂的说... 有限状态自动机DFA是这么一个有序组<Σ, U, s, T, phi>:Σ代表输入字符集,表示此自动机的工作范围:U代表所有的状态集合:s是初始状态:T是最终状态: ...

  3. AC日记——双栈排序 洛谷 P1155

    双栈排序 思路: 二分图染+模拟: 代码: #include <bits/stdc++.h> using namespace std; #define maxn 1005 #define ...

  4. 【剑指offer】面试题 17. 打印从 1 到最大的 n 位数

    面试题 17. 打印从 1 到最大的 n 位数 题目描述 题目:输入数字 n,按顺序打印出从 1 最大的 n 位十进制数.比如输入 3,则打印出 1.2.3 一直到最大的 3 位数即 999. 解答过 ...

  5. 如何学习Docker

    如何学习Docker 学习Docker,如果没有云计算的基本知识,以及内核的基本知识,那么学习并理解起来会稍吃力.作为容器,Docker容器的优势在哪,不足在哪,最好了解容器的实现是怎样的(简单了解) ...

  6. YII2源码阅读:autoload_real.php 22~23行

    spl_autoload_register(array('ComposerAutoloaderInit32b8eb537f8e12e57c5e7bade69d01f0', 'loadClassLoad ...

  7. POJ 2253 Frogger【最短路变形/最小生成树的最大权/最小瓶颈树/A到B多条路径中的最小的最长边】

    Freddy Frog is sitting on a stone in the middle of a lake. Suddenly he notices Fiona Frog who is sit ...

  8. ZOJ 3211 Dream City

    贪心,$dp$. 假设我们知道要选择哪些物品,那么这些物品应该按什么顺序选择呢? 物品$A(a1,b1)$,物品$B(a2,b3)$. 假设物品$A$在第$x$天被选择,物品$B$在第$y$天被选择. ...

  9. bWAPP练习--injection篇之HTML Injection - Reflected (GET)

    什么是Injection? injection,中文意思就是注入的意思,常见的注入漏洞就是SQL注入啦,是现在应用最广泛,杀伤力很大的漏洞. 什么是HTML injection? 有交互才会产生漏洞, ...

  10. C++-STL-(map用法)

    http://blog.csdn.net/sunshinewave/article/details/8067862