代码编织梦想

配置profile bean

Spring为环境相关的bean所提供的解决方案其实和构建时候的方案没有太大区别,Spring会根据环境决定该创建那个bean和

不创建那个bean。

Spring的bean profile的功能。要使用profile,首先将所有不同的bean定义到一个或者多个profile之中,在将应用部署到每个环境中,要确保对应的profile处于激活(active)的状态

* Java配置中,使用@Profile注解指定某个bean属于那个profile

首先创建一个bean,用在开发环境和生产环境

@Configuration
@Profile("dev")
public class DevConfiguration {
	@Bean
	public HelloWorld helloWorld(){
		return new HelloWorld("dev environment .....");
	}
}
@Configuration
@Profile("prod")
public class ProductConfiguration {
	public HelloWorld helloWorld(){
		return new HelloWorld("product environment .... ");
	}
}

从Spring3.2开始,profile注解可以用在方法上,上面改为

@Configuration
public class HellloConfiguration {
	@Bean
	@Profile("dev")
	public HelloWorld devhelloWorld(){
		return new HelloWorld("dev environment .....");
	}
	@Bean
	@Profile("prod")
	public HelloWorld prodhelloWorld(){
		return new HelloWorld("product environment .....");
	}
}

只有规定的profile被激活,对应的bean才会被创建,没有指定profile的Bean始终都会创建

* XML中配置profile

* Beans标签使用profile属性表示当前的bean的profile

<?xml version="1.0" encoding="UTF-8"?>  
<beans profile="dev" xmlns="http://www.springframework.org/schema/beans"  
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
   		xmlns:context="http://www.springframework.org/schema/context"
       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 
           ">  
  <bean id="helloWorld" class="com.erong.service.HelloWorld">
  	<property name="message" value="dev bean ....."></property>
  </bean>
</beans>  

需要注意的是xsi:schemaLocation中定义的beans的xsd文件必须是3.1之后的,只有profile被激活并且属性值相同的bean才能创建

* 重复使用元素来指定多个profile

-- profile_dev.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:context="http://www.springframework.org/schema/context"
	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 
           ">
    <context:annotation-config></context:annotation-config>
	<beans profile="dev">
		<bean id="helloWorld" class="com.erong.service.HelloWorld">
			<constructor-arg value="dev hello world bean ...."></constructor-arg>
		</bean>
	</beans>
	<beans profile="business">
		<bean id="helloWorld" class="com.erong.service.HelloWorld">
			<property name="message" value="business bean ....."></property>
		</bean>
	</beans>
	<beans profile="prod">
		<bean id="helloWorld" class="com.erong.service.HelloWorld">
			<property name="message" value="prod bean ....."></property>
		</bean>
	</beans>
</beans>  

所有的bean定义到一个xml文件中,定义了三个bean,但是运行时候只会创建一个bean,取决于处于激活状态的是profile

* 激活profile

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

如果设置了spring.profiles.active属性的话,它的值就会用来确定那个profile是激活的。

如果没有设置,将使用spring.profiles.default的值,两个属性都没有设置将会不激活profile

设置方式:

1. 作为DispatcherServlet的初始化参数

2. 作为Web应用的上下文参数

3. 作为JNDI条目

4. 作为环境变量

5. 作为JVM系统属性

<!-- 为上下文设置默认的profile -->
	<context-param>
		<param-name>spring.profiles.default</param-name>
		<param-value>dev</param-value>
	</context-param>
	<!-- 为servlet设置默认profile -->
	<servlet>
		<servlet-name>myServlet</servlet-name>
		<servlet-class>com.bing.servlet.MyServlet</servlet-class>
		<init-param>
			<param-name>spring.profiles.default</param-name>
			<param-value>dev</param-value>
		</init-param>
	</servlet>
	<servlet-mapping>
		<servlet-name>myServlet</servlet-name>
		<url-pattern>/app</url-pattern>
	</servlet-mapping>

注意到,profile使用的都是复数形式,可以同时激活多个profile,使用逗号隔开

* 使用profile进行测试

当运行集成测试时,如果配置中的bean定义在profile中,那么在运行测试中,需要有一种方式来启用合适的profile

Spring提供了@ActiveProfiles注解,我们可以使用它指定运行测试时要激活那个profile。

测试类:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(value="classpath:profile_dev.xml")
@ActiveProfiles(value={"dev"})
public class CDPlayerTest {
	@Autowired
	private HelloWorld helloWorld;
	@Test
	public void test(){
		System.out.println(
		helloWorld.getMessage());
	}
}

最后应该输出:

Your Message: dev hello world bean ....

测试过程中发现的问题:

1. 创建bean的时候,使用property元素对Bean进行赋值操作,调用的无参的构造器,并且调用的是对应的setter方法进行设值

2. 如果使用constructor-arg元素,必须存在相应参数的构造器方法创建Bean

* 条件化的bean

假设希望一个或多个bean只有在应用的类路径下包含特定的库时才创建。或者希望某个bean在另外某个特定的bean声明之后才会创建。Spring4之后,引入一个全新的注解@Conditional注解,它可以用到带有@Bean注解的方法上。

如果给定的条件计算结果为true,就创建这个bean

1. JavaConfig配置类

@Configuration
public class CDConfig {
	@Bean
	@Conditional(MagicExistCondition.class)
	public CompactDisc sgtPeppers(){
		return new SgtPeppers();
	} 
}

@Conditional将会根据类MagicExistCondition的matches方法返回的结果判断是否创建Bean

-- MagicExistCondition 实现接口 org.springframework.context.annotation.Condition

public class MagicExistCondition implements Condition {
	/**
	 * 检查环境变量是否存在magic属性
	 */
	@Override
	public boolean matches(ConditionContext context, AnnotatedTypeMetadata arg1) {
		Environment env = context.getEnvironment();
		return env.containsProperty("magic");
	}

}

对于matches方法中的ConditionContext接口,提供的方法我们能够检查

public interface ConditionContext {

	/**
	 * 根据返回的BeanDefinitionRegistry,检查bean的定义
	 */
	BeanDefinitionRegistry getRegistry();

	/**
	 * 借助返回的ConfigurableListableBeanFactory,检查bean是否存在
	 */
	ConfigurableListableBeanFactory getBeanFactory();

	/**
	 * 返回的Environment,来确定环境变量是否存在及值是什么
	 */
	Environment getEnvironment();

	/**
	 * 获取加载的资源
	 */
	ResourceLoader getResourceLoader();

	/**
	 * 检查类是否存在
	 */
	ClassLoader getClassLoader();

}

AnnotatedTypeMetadata这个接口,能够检查@Bean注解方法上还存在其他注解

Note:@Profile注解底层使用到了@Conditional注解,并且引用ProCondition作为Condition接口的实现

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
@Documented
@Conditional(ProfileCondition.class)
public @interface Profile {

	/**
	 * The set of profiles for which the annotated component should be registered.
	 */
	String[] value();

}
class ProfileCondition implements Condition {

	@Override
	public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
		if (context.getEnvironment() != null) {
			MultiValueMap<String, Object> attrs = metadata.getAllAnnotationAttributes(Profile.class.getName());
			if (attrs != null) {
				for (Object value : attrs.get("value")) {
					if (context.getEnvironment().acceptsProfiles(((String[]) value))) {
						return true;
					}
				}
				return false;
			}
		}
		return true;
	}

}

从源码看

1. 获取Profile 注解的所有属性的键值对

2. 检查当前环境中生效的Profile和当前Bean的Profile的value的值是否相同,相同,返回true,创建这个bean

@Profile在使用时候也会通过Conditon接口的实现类,判断Bean的profile是否处在激活状态,从而判断是否创建Bean。


* 处理自动装配的歧义性

如果存在多个类实现同一个接口,每个类都创建一个bean,自动注入的时候会选择哪个Bean,Spring无法判断就会抛出异常


解决:

1. 使用@Primary注解或者xml中primary = true ,标识Bean是优先选择的注入的

@Bean
	@Primary
	@Conditional(MagicExistCondition.class)
	public CompactDisc sgtPeppers(){
		return new SgtPeppers();
	} 
<bean id="helloWorld" class="com.erong.service.HelloWorld" primary="true">
			<constructor-arg value="dev hello world bean ...."></constructor-arg>
		</bean>

2. 使用@Qualifier注解限定装配的Bean和@Autowire注解或者@Inject注解搭配使用,值为Bean的ID

@Autowired
@Qualifier("cdplayer")
private CDPlayer cdplayer;

* 创建自定义的限定符

可以为bean设置自己的限定符,而不是依赖于将bean ID 作为限定符

> bean的声明上添加@Qualifier注解,设置Bean自己的限定符号

@Component
@Qualifier("compactDisc")
public class SgtPeppers implements CompactDisc {
@Bean
@Qualifier("compactDisc")
public SgtPeppers getInstance(){
       return new SgtPeppers();
}

这样,创建的Bean的限定符号就为compactDisc,自动注入的时候@Qualifier使用这个限定符注入

note: 

1. @Bean注解放在方法上,如果方法存在形参,会自动扫描匹配的bean自动注入

2. @Bean注解创建的Bean的限定符,可以通过@Qualifier指定

3. @Bean创建的Bean,Bean ID可以同时是指定的限定符,也可以是方法名

* Bean的自定义限定符号相同,需要自定自己的限定符注解

@Target({java.lang.annotation.ElementType.FIELD, 
	java.lang.annotation.ElementType.METHOD, 
	java.lang.annotation.ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface Cold {

}


版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/Ditto_zhou/article/details/80422564

根据环境装配你的bean——spring中profile的应用_正义的键盘的博客-爱代码爱编程

  环境配置类注解的使用场景在于:有时候你的开发环境所使用的bean和测试环境以及生产环境不太一样,一般处理这类问题 可能需要人工处理,你可能会在环境迁移的时候手动去掉其他环境的注入标识,费时且容易出错。   举一个例子:   数据库配置,多个环境的数据库配置肯定不一样,datasource类bean需要手动去切换,如果项目有多数据源 那就更麻烦了。也可能

spring实战笔记——profile详解_ming-world的博客-爱代码爱编程

Profile详解 在项目开发的过程中,我们在不同阶段可能需要不同的配置,而我们不可能花费两个项目去实现这样的功能,但Spring就提供了一个很好的特性,利用profile进行配置可以实现此目的。 配置Prof

spring——使用profile为不同环境创建bean_alemon_y的博客-爱代码爱编程

0.技术所要解决的问题 在开发软件时候,有一个很大的挑战就是将应用从一个环境迁移到另外一个环境。开发阶段中,某些环境相关做法可能并不合适迁移到生产环境中,甚至迁移过去也无法工作。例如数据库配置,加密算法,外部部署~~ p

spring 配置profile bean_三丶竹的博客-爱代码爱编程_profiles.active

@Profile 注解可以根据配置来决定创建哪个bean,用来切换环境 @Configuration @Profile("dev") publi  class  DevelopmentProfileConfig{       @Bean(destroyMethod = "shutdown")      public  DataSource   d

spring中profile属性实现开发、测试、生产环境的切换_zixiangli的博客-爱代码爱编程

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" xm

spring注解之 @profile_weixin_33845881的博客-爱代码爱编程

2019独角兽企业重金招聘Python工程师标准>>> spring中@profile与maven中的profile很相似,通过配置来改变参数。 例如在开发环境与生产环境使用不同的参数,可以配置两套配置文件,通过@profile来激活需要的环境,但维护两套配置文件不如maven中维护一套配置文件,在pom中

(原创)Spring 依赖注入 - 自动装配歧义性的两种解决方式-爱代码爱编程

目录 一、背景 二、解决方法一:使用 @Primary 标识首选 bean 三、解决方法二:使用限定符 @Qualifier (更优,可自定义限定符注解) 一、背景 在进行自动装配中,Spring 发现存在多个符合依赖条件的 bean 时,会产生歧义性,并抛出异常。例如: // 自动装配 @Autowired public void setPe

Spring注解详解之自动注入(@Profile环境配置)-爱代码爱编程

概述 @Profile注解是Spring提供的用来标注当前运行环境的注解,在我们实际工作过程中,会有多个环境,比如:开发环境,测试环境,和生产环境,在不同的环境中,配置会有所不同,比如数据源的配置,在不改动代码的情况下,可以使用@Profile注解来进行切换 源码 @Target({ElementType.TYPE, ElementType

Spring高级装配,Profile的使用,条件化Bean,解决歧义性-爱代码爱编程

随笔,分类于 乱七八糟 下。阅读于《Spring实战 4》笔记 高级装配 环境 与 Profile 让各个 开发环境 之间切换更加方便。使用 Profile。 配置 profile bean 要使用 profile,你首先要将所有不同的 bean 定义整理到一个或多个profile之中,在将应用部署到每个环境时,要确保对应的profil

Spring IOC学习(02)Bean的高级装配-爱代码爱编程

内容概览 环境与profile 条件化的bean 自动装配的歧义性 Bean的作用域 运行时值注入 总结1. 环境与profile 在项目开发的过程中,不可避免的一个问题是项目需要在不同的环境之间运行与切换,比如最经典的例子,通常大部分中小型的项目分为开发(dev),测试(test),生产(prod)三个环境,这三

spring应用手册-IOC(XML配置实现)-(19)-beans标签的profile属性-爱代码爱编程

戴着假发的程序员出品 beans标签的profile属性 spring应用手册(第一部分) profile用于配置spring的多环境配置。 我们可以通过profile配置多个不同环境下的配置属性。 案例: <?xml version="1.0" encoding="UTF-8"?> <beans default

Spring Profile Bean总结-爱代码爱编程

文章目录 profile bean激活profile 如何在不同的环境下,使用不同的bean? profile bean Spring不是在构建时决定创建哪个bean,而是在运行时再确定。这样,同一个包能够适用于所有的环境,没必要重新构建。 Spring 3.1中,引入bean profile功能。 Java配置中,可以使用@Profile

注解装配Bean(六)——@Profile注解区分开发环境-爱代码爱编程

测试人员与开发人员可能使用的不是同一套环境,Spring支持在不同的环境中进行切换的需求。通过@Profile注解实现。 @Profile的使用案例 在注解装配Bean(五)中的案例中进行修改,配置两个数据库连接池,代码修改如下: package com.ssm.spring.annotation.config; import org.spring