博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Spring in Action --- 第三章 高级装配
阅读量:5280 次
发布时间:2019-06-14

本文共 4816 字,大约阅读时间需要 16 分钟。

Spring profile

使用Spring profile 可以设定在不同的环境中启用不同的bean.由于环境的不同,数据库配置,加密算法以及与外部系统的集成可能会有不同的表现,特别是数据库,一般开发环境,QA环境,预发布环境,生产环境会分开

Spring并不是在构建的时候做出这样的决策的,而是等到运行时再来确定

在java中

使用@Porfile注解指定某个bean属于哪一个profile,

@Profile("dev")

表示profile环境是dev.

只有相应的profile激活的时候,才会创建对应的bean,但是,没有指定profile的bean始终都会被创建,与激活哪个profile没有关系

在XML中

创建不同的XML文件设置不同的profile,也可以在根<bean>元素中嵌套定义<beans>元素,而不是为每一个环境创建一个profile XML文件.

激活 profile

Spring在确定哪个profile处于激活状态时,需要依赖两个独立的属性:spring.profiles.activespring.profiles.default,如果设置了 spring.profiles.active 属性,那么它的值就会用来确定哪个profile是激活的,但是如果没有设置,那 Spring会查找spring.profiles.defalut的值.如果两者均为设置,那么就没有激活的profile,Spring只会创建哪些没有定义在profile中的bean.

设置属性的方式
  • 作为 DispatcherServlet 的初始化参数
  • 作为 Web 应用的上下文参数
  • 作为 JNDI 条目
  • 作为环境变量
  • 作为JVM的系统属性

示例:

在web.xml中为上下文设置默认的profile

spring.profiles.default
dev

在web.xml中为Servlet设置默认的profile

appServlet
prg.springframework.web.servlet.DispatcherServlet
spring.profiles.default
dev

使用profile进行测试

Spring提供了@ActiveProfiles注解指定运行测试时要激活哪个profile.

条件化的 bean

Spring4以后,引入了@Conditional,可以用到带有@Bean注解的方法上,用于计算给定的条件如果为true,就会创建这个bean,否则的话这个bean会被忽略

例如有一个Test的类,我们希望只有设置了 test 环境属性的时候,Spring才会实例化这个类,如果没有,就会被忽略.下面的配置展示了注解的使用方式

@Bean@Conditional(TestExistsCondition.class)public Test test() {    return new Test();}

@Condition中给定了一个Class,指明创建该bean的条件,设置给它的类可以是任意实现了Condition接口的类型.下面展现了TestExistsCondition类的实现

public class TestExistsCondition() {    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {    Environment env = context.getEnvironment();    return env.containsProperty("test");    }}

其中的两个参数 ConditionContext, AnnotatedTypeMetadata 都是接口,具体请看P77

处理自动装配的歧义性

在使用自动装配时,如果一个接口有多个实现类并且都被定义为bean,当Spring试图装配的时候就会无法做出选择从而抛出 NoUniqueBeanDefinitionException, Spring提供了两种方式来解决这样的问题:

  • 将可选bean的某一个设置为首选的bean
  • 使用限定符(qualifier)来帮助Spring将可选的bean的范围缩小到只有一个bean

标示首选的bean

在 bean 上使用@Primary注解标示当前的bean是首选bean,如果你是用XML来实例化bean

,可以用下面的方式:

但是,如果你设置了两个或者更多的首选bean,那么它就无法正常工作了

限定自动装配的bean

@Qualifier注解是使用限定符的主要方式:

@Autowired@Qualifier("iceCream")public void setDessert(Dessert dessert) {    this.dessert = dessert}

上面的代码片段是最简单的例子,为@Qualifier注解所设置的参数就是想要注入的bean的ID,所有的@Component注解创建的类的ID都是首字母变为小写的类名.需要注意的是,如果没有指定其他的限定符的话,所有的bean都会给定一个默认的限定符,这个限定符与bean的ID相同

这里有个问题就是,指定的限定符与要注入的bean的名称是紧耦合的,如果bean的名字修改了,那么就会无法注入,解决方案是在bean上使用@qualifier指定该bean的限定符

使用自定义的限定符注解

如果iceCream同时被使用在两个或更多的bean上,那怎么办呢?你可能会想到的是使用更多的限定符来缩小范围:

@Component@Qualifier("iceCream")@Qualifier("cold")public class IceCream implements Dessert {...}

这里只有一个小问题,Java不允许在同一个条目上重复出现相同类型的多个注解.如果你这么做了,编译将会报错.但是,我们可以创建自定义的限定符注解:

@Retention(RetentionPolicy.RUNTIME)@Target({ElementType.TYPE, ElementType.METHOD})@Qualifierpublic @interface Cold{}

上面的代码片段定义了一个自定义注解,它本身要使用@Qualifier来标注,这样就可以不断缩小范围,直到唯一.

bean 的作用域

在默认情况下,Spring应用上下文中所有的bean都是作为以单利的形式创建的,不过,Spring提供了多种作用域,可以基于这些作用域创建bean:

  • 单例:在整个应用中,只创建bean的一个实例
  • 原型:每次注入或者通过Spring应用上下文获取的时候,都会创建一个新的bean实例
  • 会话:在Web应用中,为每个会话创建一个bean实例
  • 请求:在Web应用中,为每个请求创建一个bean实例

默认是单例模式,如果选择其他的作用域,要使用@Scope注解,例如,要将一个bean生命为原型,需要这样做:

@bean@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)public class Notepad{...}

使用组件扫描来发现和声明bean,只需要加上@Component注解替换@Bean,同样,如果使用XML来配置bean的话,可以使用scope属性来设置作用域:

对于会话作用域,在当前会话的相关操作中,bean实际上是单例的:

@Component@Scope(value=WebApplicationContext.SCOPE_SESSION,proxyMode=ScopedProxyMode.INTERFACES)public ShoppingCart cart() {...}

要注意的是,同时还有一个proxyMode属性被设置,请看下面的代码:

@Componentpublic class StoreService {    @Autowired    public void setShoppingCart(ShoppingCart shoopingCart) {        this.shoppingCart = shoppingCart    }}

这个service是一个单例的bean,当它创建的时候,Spring会试图将ShoppingCart bean注入,但是ShoppingCart是会话作用域的,此时并不存在,知道某个用户进入到系统才会出现实例,另外,系统中将会有多个ShoppingCart实例被创建,我们希望注入的bean刚好是当前会话对应的那一个,因此,Spring会向StroeService中注入一个到ShoppingCart的代理.关于具体的描述,请看P87

运行时注入

在代码中,最好的方式是不要在代码中出现硬代码,因此我们需要借助Spring的一些配置来注入外部的值:

@Configuration@PropertySource("")public class ExpressiveConfig {    @Autowired    Environment env;        @Bean    public BlankDisc disc() {        return new BlankDisc(env.getProperty("disc.title"));    }}

我们使用了@ PropertySource注解引用了外部的一个属性文件,其中有disc.title属性,会被读取并配置到bean中,如果这个属性没有被定义,获取到的值会是null,如果你希望这个属性必须被定义,可以使用getRequiredProperty()方法.

另外,可以使用Environment.containsProperty()方法来判断是否有某一个属性.最后,如果想将属性解析为类的话,可以使用getPropertyAdClass()方法.

如果我们依赖组件扫描和自动装配来创建和初始化应用组件的话,娜美可以使用@Value注解,它与@Autowired非常相似:

public BlankDisc(@Value("${disc.title}") String title) {    this.title = title;}

为了使用占位符,我们必须要配置一个PropertyPlaceHolderConfigurer bean或 PropertySourcePlaceHolderConfigurer bean,具体请看P92

注解

@Profile

Spring 3.2以后,注解支持在类和方法级别上使用

@Profile("...")括号中可以定义任意的字符串,但建议用有意义的字符串

@ActiveProfiles

@Conditional

@Primary

@Qualifier

@Scope

@PropertySource

转载于:https://www.cnblogs.com/cbzj/p/6294211.html

你可能感兴趣的文章
Java大数——a^b + b^a
查看>>
简单的数据库操作
查看>>
帧的最小长度 CSMA/CD
查看>>
普通求素数和线性筛素数
查看>>
PHP截取中英文混合字符
查看>>
电子眼抓拍大解密
查看>>
51nod1076 (边双连通)
查看>>
Linux pipe函数
查看>>
Zerver是一个C#开发的Nginx+PHP+Mysql+memcached+redis绿色集成开发环境
查看>>
程序的静态链接,动态链接和装载 (补充)
查看>>
关于本博客说明
查看>>
[Kaggle] Sentiment Analysis on Movie Reviews
查看>>
价值观
查看>>
mongodb命令----批量更改文档字段名
查看>>
国外常见互联网盈利创新模式
查看>>
android:scaleType属性
查看>>
shell脚本
查看>>
Upload Image to .NET Core 2.1 API
查看>>
【雷电】源代码分析(二)-- 进入游戏攻击
查看>>
Linux中防火墙centos
查看>>