Spring(三)---Spring的高级装配(1)

(一)Spring Profile
背景:在软件开发过程中,最大的挑战是从一个环境迁移到另一个环境中,某些环境相关的做法可能并不适合迁移到生产环境中,甚至迁移过去也无法正常工作.如数据库配置,加密算法以及与外部系统的集成是跨环境部署时会发生变化的几个典型例子.
例:
由于我们平时在开发中,通常会出现在开发的时候使用一个开发数据库,测试的时候使用一个测试的数据库,而实际部署的时候需要一个数据库。以前的做法是将这些信息写在一个配置文件中,当我把代码部署到测试的环境中,将配置文件改成测试环境;当测试完成,项目需要部署到现网了,又要将配置信息改成现网的,真的好烦。。。而使用了Profile之后,我们就可以分别定义3个配置文件,一个用于开发、一个用户测试、一个用户生产,其分别对应于3个Profile。当在实际运行的时候,只需给定一个参数来激活对应的Profile即可,那么容器就会只加载激活后的配置文件,这样就可以大大省去我们修改配置信息而带来的烦恼

(1)什么是profile bean
Spring中的Profile功能其实早在Spring 3.1的版本就已经出来,它可以理解为我们在Spring容器中所定义的Bean的逻辑组名称,只有当这些Profile被激活的时候,才会将Profile中所对应的Bean注册到Spring容器中。举个更具体的例子,我们以前所定义的Bean,当Spring容器一启动的时候,就会一股脑的全部加载这些信息完成对Bean的创建;而使用了Profile之后,它会将Bean的定义进行更细粒度的划分,将这些定义的Bean划分为几个不同的组,当Spring容器加载配置信息的时候,首先查找激活的Profile,然后只会去加载被激活的组中所定义的Bean信息,而不被激活的Profile中所定义的Bean定义信息是不会加载用于创建Bean的。
(2)配置profile bean
首先要将所有不同的bean定义整理到一个或多个profile之中,在将应用部署到每个环境时,要确保对应的profile处于激活(active)的状态.
在Java配置中,可以使用@Profile注解指定某个bean属于哪一个profile.
例:

//@Profile注解应用在了类级别上了,它会告诉Spring这个配置类中的bean只有在dev profile激活时才会创建,若没有激活,会忽略@bean注解的方法
@Configuration
@Profile("dev")
public class DevelopmentProfileConfig(){
  @Bean
  public DataSource dataSource(){
     return new EmbeddedDatabaseBuilder()
     .setType(EmbeddedDatabaseType.H2)
     .addScript("classpath:test.sql")
     .build();
}
}

//从Spring3.2开始,可以在方法级别上使用@profile注解,与@Bean一同使用
//注:尽管每个DataSource Bean都被声明在profile中,并且只有当规定的profile激活时,相应的bean才能被创建,可能会有其他的bean没有声明在一个给定的profile范围内,没有给定的profile始终会被创建.
public class DataSourceConfig(){
   @profile("dev")
   @Bean
  public DataSource dataSource(){
     return new EmbeddedDatabaseBuilder()
     .setType(EmbeddedDatabaseType.H2)
     .addScript("classpath:test.sql")
     .build();
}
  @profile("test")
   @Bean
  public DataSource dataSource(){
     return new TestDatabaseBuilder(); 
}
}

在XML中配置profile

//可以通过<bean元素>的profile属性,在XML中配置profile bean.

这里写图片描述
(3)激活profile
Spring在确定哪个profile处于激活状态时,需要依赖两个独立的属性:spring.profiles.active和spring.profiles.default,如果设置了spring.profiles.active属性的话,那么它的值就会用来确定哪个profile是激活的,如果没有设置spring.profiles.active属性的话,那Spring将查找spring.profiles.default的值.如果spring.profiles.active和spring.profiles.default都没有设置的话,那就没有激活profile.
有多种方式来设置这两个属性:

  • 作为DispatcherServlet的初始化参数;
  • 作为web应用上下文的参数;
  • 作为JNDI条目;
  • 作为环境变量;
  • 作为JVM的系统属性;
  • 在集成测试类上,使用@ActiveProfiles注解设置.
    例:在web应用的web.xml文件中设置默认的profile
    这里写图片描述
    (3)条件化的bean
    Ⅰ背景:假如希望一个或多个bean只有在应用的类路径下包含特定的库时才创建.或者我们希望某个bean只有当另一个bean声明之后才能被创建.
    Ⅱ使用条件化的bean
    在Spring4引入了一个新的@Conditional注解,它可以用到带有@Bean注解的方法上.如果给定的条件计算结果为true,就会创建这个bean,否则的话,这个bean就会被忽略.
//假设有一个名为MagicBean的类,希望设置了magic环境属性的时候,Spring 才会实例化这个类
//条件化创建Bean
@Bean
@Conditional(MagicExistCondition.class)
public MagicBean magicBean(){
  return new MagicBean();
}
//设置给@Conditional的类可以是任意实现了Condition接口的类型
//MagicExistCondition
public class MagicExistCondition implements Condition{
   public boolean matches(ConditionContext context,AnnotatedTypeMetadata metdata){
     Enviroment emv = context.getEnviroment();
     return emv.contaionsProperty("magic");
   }
}

ConditionContext接口
这里写图片描述
这里写图片描述

这里写图片描述
(二)处理自动装配的歧义性
背景:当仅有一个Bean匹配所需的结果时,自动装配才能有效.如果不仅有一个bean能够匹配的话,这种歧义性会阻碍Spring自动装配属性,构造器参数或方法参数.
(1)标记首选的bean
在Spring中可以通过@Primary来表达最喜欢的方案,(即在遇到歧义性的时候首选的bean)

//Dessert的三个实现类中若哪个实现类标注了@Primary,就会被优先注入
//注:若有两个实现类标注了@Primary就会引起歧义性,因为Spring不知道优先注入哪个实现类
@Autowired
public void setDessert(Dessert dessert){
  this.dessert = dessert;
}
//Dessert是一个接口,并且有三个类实现了这个接口
@Primary
@Component
public class Cake implements Dessert{}
@Component
public class Cookies implements Dessert{}
@Component
public class IceCream implements Dessert{}

在Java配置文件标记首选Bean
@Bean
@Primary
public Dessert iceCream(){
  return new IceCream();
}
在XML文件中配置首选bean
<bean id="iceCream"
      class="com.desserteater.IceCream
      primary="true" />

(2)限定自动装配的bean
@Qualifier注解是使用限定符的主要方式,
例:

@Autowired
//@Qualifier注解所设置的参数就是想要注入的bean的ID
//@Component注解声明的类都会创建bean,并且bean的ID为首字母变为小写的类名
@Qualifier("iceCream")
ublic void setDessert(Dessert dessert){
  this.dessert = dessert;
}

//创建自定义的限定符
//可以为bean设置自己的限定符,而不是依赖于将bean ID作为限定符
@Component
//自定义的限定符
@Qualifier("cold")
public class IceCream implements Dessert{...}

使用自定义的限定符注解

创建@Qualifier(“cold”)注解
这里写图片描述
创建@Qualifier(“creamy”)注解
这里写图片描述
这里写图片描述
这里并没有在任何地方指明要将IceCream自动装配到该方法中.相反我们需要使用所需bean的特性来进行指定,即@Cold和@Creamy.因此setDessert()方法依然能够与特定的Dessert实现保持解耦.任意满足这些特征的bean都是可以的.在当前选择Dessert实现时,恰好如此,IceCream是唯一能够与之匹配的bean
这里写图片描述
(三)bean的作用范围
默认情况下, Spring 只为每个在 IOC 容器里声明的 Bean 创建唯一一个实例, 整个 IOC 容器范围内都能共享该实例
这里写图片描述
若要选择其他的作用域,要使用@Scope注解,它可以与@Commponent或@Bean一起使用
例:
这里写图片描述
在Java配置文件中
这里写图片描述
在XML文件中
这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值