Day02 Spring和SpringBoot

续第二章

二、通过Java代码装配bean(配置类JavaConfig)

 应用场景:有时候自动化配置的方案行不通,因此需要明确配置Spring。比如说,想要将第三方库中的组件装配到你的应用中,在这种情况下,是没有办法在它的类上添加@Component和
@Autowired注解的,因此就不能使用自动化装配的方案了。

在进行显式配置的时候,有两种可选方案:Java和XML。而JavaConfig(配置代码)是更好的方案,因为它更为强大、类型安全并且对重构友好。因为它就是Java代码,就像应用程序中的其他Java代码一样。

例:

Day02 Spring和SpringBoot_第1张图片

 @Configuration注解表明这个类是一个配置类,该类应该包含在Spring应用上下文中如何创建bean的细节。

@Bean注解会告诉Spring这个方法将会返回一个对象,该对象要注册为Spring应用上下文中的bean。方法体中包含了最终产生bean实例的逻辑。

三、通过XML装配bean(xml文件)

在XML配置中,意味着要创建一个XML文件,并且要以元素为根。

Day02 Spring和SpringBoot_第2张图片

 元素类似于JavaConfig中的@Bean注解。

通常来讲更好的办法是下面那种,借助id属性,为每个bean设置一个自己选择的名字:

---------------------------------------------------------------------------------------------------------------------------------

借助构造器注入初始化bean

---------------------------------------------------------------------------------------------------------------------------------

在XML中声明DI时,会有多种可选的配置方案和风格。具体到构造器注入,有两种基本的配置方案可供选择:

  1. 元素
  2. 使用Spring 3.0所引入的c-命名空间

1.构造器注入bean引用:

方法1:

 当Spring遇到这个元素时,它会创建一个CDPlayer实例。元素会告知Spring要将一个ID为compactDisc的bean引用传递到CDPlayer的构造器中。

方法2:

 

 使用了c-命名空间来声明构造器参数。

Day02 Spring和SpringBoot_第3张图片

 可以将参数名字替换为“_0”,或者“_”

 

2.将字面量注入到构造器中:

方法一:元素

Day02 Spring和SpringBoot_第4张图片

上面例子没有使用“ref”属性来引用其他的bean,而是使用了value属性,通过该属性表明给定的值要以字面量的形式注入到构造器之中。

方法二:c-命名空间

Day02 Spring和SpringBoot_第5张图片

 或

 装配字面量与装配引用的区别在于属性名中去掉了“-ref”后缀。

3.装配集合

Day02 Spring和SpringBoot_第6张图片

 在装配集合方面,比c-命名空间的属性更有优势。目前,使用c-命名空间的属性无法实现装配集合的功能。

----------------------------------------------------------------------------------------------------------------------------

设置属性


Day02 Spring和SpringBoot_第7张图片

 元素为属性的Setter方法所提供的功能与元素为构造器所提供的功能是一样的。在本例中,它引用了ID为compactDisc的bean(通过ref属性),并将其注入到compactDisc属性中(通过setCompactDisc()方法)。

还有另一种方法代替元素:p-命名空间

Day02 Spring和SpringBoot_第8张图片

 Day02 Spring和SpringBoot_第9张图片

 将字面量注入到属性中:

Day02 Spring和SpringBoot_第10张图片

 与c-命名空间一样,装配bean引用与装配字面量的唯一区别在于是否带有“-ref”后缀。如果没有“-ref”后缀的话,所装配的就是字面量。

四、自动化配置、JavaConfig以及XML配置混合匹配

在JavaConfig中引用XML配置


1.使用@Import注解,导入JavaConfig

2. 使用@ImportResource注解,导入xml配置

Day02 Spring和SpringBoot_第11张图片

 


XML配置中引用JavaConfig


在XML中,可以使用import元素来拆分XML配置。


第3章 高级装配

3.1 环境与profile

在Java配置中,可以使用@Profile注解指定某个bean属于哪一个profile。

eg:在开发环境中:

用EmbeddedDatabaseBuilder会搭建一个嵌入式的Hypersonic数据库,它的表(schema)定义在schema.sql中,测试数据则是通过test-data.sql加载的

Day02 Spring和SpringBoot_第12张图片

 在生产环境中:可能会希望使用JNDI从容器中获取一个DataSource

Day02 Spring和SpringBoot_第13张图片

 

另外,我们也可以通过元素的profile属性,在XML中配置profile bean。

Day02 Spring和SpringBoot_第14张图片

 激活profile

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

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

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

eg:使用profile进行测试

Day02 Spring和SpringBoot_第15张图片

 3.2 条件化的bean

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

eg:

Day02 Spring和SpringBoot_第16张图片

 设置给@Conditional的类可以是任意实现了Condition接口的类型。可以看出来,这个接口实现起来很简单直接,只需提供matches()方法的实现即可。如果matches()方法返回true,那么就会创建带有@Conditional注解的bean。如果matches()方法返回false,将不会创建这些bean。

Day02 Spring和SpringBoot_第17张图片

3.3 处理自动装配的歧义性 

当确实发生歧义性的时候,Spring提供了多种可选方案来解决这样的问题:

1.将可选bean中的某一个设为首选(primary)的bean。

2.使用限定符(qualifier)来帮助Spring将可选的bean的范围缩小到只有一个bean。

展开:

第一种:通过@Primary来表达最喜欢的方案。(只能用在一个身上)

 或

Day02 Spring和SpringBoot_第18张图片

 或

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

例如,我们想要确保要将IceCream注入到setDessert()之中:

 所有使用@Component注解声明的类都会创建为bean,并且bean的ID为首字母变为小写的类名。因此,@Qualifier("iceCream")指向的是组件扫描时所创建的bean,并且这个bean是IceCream类的实例。

通过声明自定义的限定符注解,我们可以同时使用多个限定符,不会再有Java编译器的限制或错误。与此同时,相对于使用原始的@Qualifier并借助String类型来指定限定符,自定义的注解也更为类型安全。

3.4 bean的作用域

Spring定义了多种作用域,可以基于这些作用域创建bean,包括:

  • 单例(Singleton):在整个应用中,只创建bean的一个实例。(默认作用域)
  • 原型(Prototype):每次注入或者通过Spring应用上下文获取的时候,都会创建一个新的bean实例。
  • 会话(Session):在Web应用中,为每个会话创建一个bean实例。(eg:购物车)
  • 请求(Rquest):在Web应用中,为每个请求创建一个bean实例。

如果选择其他的作用域,要使用@Scope注解,它可以与@Component或@Bean一起使用。

eg:

(1)使用组件扫描来发现和声明bean,设置了原型作用域

Day02 Spring和SpringBoot_第19张图片

 当然也可以使用@Scope("prototype"),但是使用SCOPE_PROTOTYPE常量更加安全并且不易出错。

(2)在Java配置中将Notepad声明为原型bean,那么可以组合使用@Scope和@Bean来指定所需的作用域:

Day02 Spring和SpringBoot_第20张图片

 (3)使用XML来配置bean的话,可以使用元素的scope属性来设置作用域:

Day02 Spring和SpringBoot_第21张图片


 

proxyMode属性被设置成了ScopedProxyMode.INTERFACES,这表明这个代理要实现
ShoppingCart接口,并将调用委托给实现bean。

Day02 Spring和SpringBoot_第22张图片

 如果ShoppingCart是接口而不是类的话,这是可以的(也是最为理想的代理模式)。但如果ShoppingCart是一个具体的类的话,Spring就没有办法创建基于接口的代理了。此时,它必须使用CGLib来生成基于类的代理。所以,如果bean类型是具体类的话,我们必须要将proxyMode属性设置为ScopedProxyMode.TARGET_CLASS,以此来表明要以生成目标类扩展的方式创建代理。

使用XML来声明会话或请求作用域的bean,需要使用Spring aop命名空间的一个新元素:

 是与@Scope注解的proxyMode属性功能相同的Spring XML配置元素。它会告诉Spring为bean创建一个作用域代理。默认情况下,它会使用CGLib创建目标类的代理。但是我们也可以将proxy-target-class属性设置为false,进而要求它生成基于接口的代理:

3.5 运行时值注入

两种方式:

  • 属性占位符(Property placeholder)。
  • Spring表达式语言(SpEL)。

3.5.1 注入外部的值

使用@PropertySource注解和Environment

Day02 Spring和SpringBoot_第23张图片

 解析属性占位符

形式为使用“${... }”包装的属性名称

Day02 Spring和SpringBoot_第24张图片

 3.5.2 使用Spring表达式语言进行装配

SpEL(Spring Expression Language,SpEL)拥有很多特性,包括:

  • 使用bean的ID来引用bean;
  • 调用方法和访问对象的属性;
  • 对值进行算术、关系和逻辑运算;
  • 正则表达式匹配;
  • 集合操作。

SpEL表达式要放到“#{ ... }”之中,这与属性占位符有些类似,属性占位符需要放到“${ ... }”之中

Day02 Spring和SpringBoot_第25张图片

 或:

 具体语法:

浮点值:#{3.14159}

科学记数法:#{9.87E4}

String类型: #{‘hello’}

Boolean类型:#{false}

通过ID引用其他的bean:#{sgtPeppers}

引用sgtPeppers的artist属性:#{sgtPepper.artist}

在表达式中使用类型:T(java.lang.Math)

Day02 Spring和SpringBoot_第26张图片

 Day02 Spring和SpringBoot_第27张图片

 正则表达式:

eg:判断一个字符串是否包含有效的邮件地址:

 SpEL还提供了查询运算符(.?[]),它会用来对集合进行过滤,得到集合的一个子集。

eg:假设你希望得到jukebox中artist属性为Aerosmith的所有歌曲:

 SpEL还提供了另外两个查询运算符:“.^[]”和“.$[]”,它们分别用来在集合中查询第一个匹配项和最后一个匹配项

eg:

 SpEL还提供了投影运算符(.![]),它会从集合的每个成员中选择特定的属性放到另外一个集合中

eg:假设我们不想要歌曲对象的集合,而是所有歌曲名称的集合

你可能感兴趣的:(spring,spring,boot,java)