这是我参与8月更文挑战的第16天,活动详情查看:8月更文挑战
接上篇Spring IoC 控制反转,本文主要内容如下:
Spring装配Bean
举例:beanAssemble 项目
Bean的装配,即Bean对象的创建。容器根据代码要求创建 Bean 对象后再传递给代码的过程,称为Bean的装配。
默认装配方式
代码通过getBean()方式从容器获取指定的 Bean实例,容器首先会调用Bean类的无参构造器,创建空值的实例对象。
举例:
容器中Bean的作用域
当通过 Spring 容器创建一个 Bean 实例时,不仅可以完成 Bean 的实例化,还可以通过 scope 属性,为 Bean 指定特定的作用域。Spring 支持 5 种作用域。
● singleton:单态模式。即在整个 Spring 容器中,使用 singleton 定义的 Bean 将是单例的, 只有一个实例。默认为单态的。
● prototype:原型模式。即每次使用 getBean 方法获取的同一个的实例都是一个 新的实例。
● request:对于每次 HTTP 请求,都将会产生一个不同的 Bean 实例。
● session:对于每个不同的 HTTP session,都将产生一个不同的 Bean 实例。
注意:
● 对于 scope 的值 request、session 只有在 Web 应用中使用 Spring 时,该作用域才有效。
● 对于 scope 为 singleton 的单例模式,该 Bean 是在容器被创建时即被装配好了。
● 对于 scope 为 prototype 的原型模式,Bean 实例是在代码中使用该 Bean 实例时才进行 装配的。
举例:
定制Bean 的生命始末
可以为 Bean 定制初始化后的生命行为,也可以为 Bean 定制销毁前的生命行为。
举例:
首先,这些方法需要在 Bean 类中事先定义好:是方法名随意的 public void 方法。
其次,在配置文件的标签中增加如下属性:
init-method:指定初始化方法的方法名
destroy-method:指定销毁方法的方法名
注意,若要看到 Bean 的 destroy-method 的执行结果,需要满足两个条件:
● Bean 为 singleton,即单例
● 要确保容器关闭。接口 ApplicationContext 没有 close()方法,但其实现类有。所以,可以将 ApplicationContext 强转为其实现类对象,或直接创建的就是实现类对象。
Spring XML注入
举例:项目 di-xml
注入分类
bean 实例在调用无参构造器创建了空值对象后,就要对 bean对象的属性进行初始化。初始化是由容器自动完成的,称为注入。
根据注入方式的不同,常用的有两类:设值注入、构造注入。
1、设值注入
设值注入是指,通过 setter 方法传入被调用者的实例。这种注入方式简单、直观,因而在 Spring 的依赖注入中大量使用。
举例:
当指定 bean 的某属性值为另一 bean 的实例时,通过 ref 指定它们间的引用关系。ref 的值必须为某 bean 的 id 值。
对于其它 Bean 对象的引用,除了标签的 ref 属性外,还可以使用标签。
2、构造注入
构造注入是指,在构造调用者实例的同时,完成被调用者的实例化。即,使用构造器设置依赖关系。
举例:
标签中用于指定参数的属性有:
name:指定参数名称。
index:指明该参数对应着构造器的第几个参数,从 0 开始。不过,该属性不要也行, 但要注意,若参数类型相同,或之间有包含关系,则需要保证赋值顺序要与构造器中的参数顺序一致。
具有集合性质的属性注入
举例:di03 包
● 为数组注入值
● 为 List 注入值
● 为 Set 注入值
● 为 Map 注入值
● 为 Properties 注入值
● 复杂集合属性的注入
MyCollections 类中增加新的属性
在容器配置文件注入方式:
对于引用类型属性的自动注入
对于引用类型属性的注入,也可不在配置文件中显示的注入。可以通过为标签设置autowire属性值,为引用类型属性进行隐式自动注入(默认是不自动注入引用类型属性)。根据自动注入判断标准的不同,可以分为两种:
- byName:根据名称自动注入
- byType:根据类型自动注入
1、byName 方式自动注入
当配置文件中被调用者 bean 的 id 值与代码中调用者 bean 类的属性名相同时,可使用byName 方式,让容器自动将被调用者bean注入给调用者 bean。容器是通过调用者的bean类的属性名与配置文件的被调用者bean的id进行比较而实现自动注入的。
举例:
2、byType 方式自动注入
使用 byType 方式自动注入,要求:配置文件中被调用者 bean 的 class 属性指定的类,要与代码中调用者 bean 类的某引用类型属性类型同源。即要么相同,要么有 is-a 关系(子类,或是实现类)。但这样的同源的被调用 bean 只能有一个。多于一个,容器就不知该匹配哪一个了。
举例:
为应用指定多个Spring 配置文件
在实际应用里,随着应用规模的增加,系统中Bean数量也大量增加,导致配置文件变得非常庞大、臃肿。为了避免这种情况的产生,提高配置文件的可读性与可维护性,可以将Spring 配置文件分解成多个配置文件。
1、 平等关系的配置文件
将配置文件分解为地位平等的多个配置文件,并将所有配置文件的路径定义为一个String 数组,将其作为容器初始化参数出现。其将与可变参的容器构造器匹配。
各配置文件间为并列关系,不分主次。
举例:
2、包含关系的配置文件
各配置文件中有一个总文件,总配置文件将各其它子文件通过引入。在 Java代码中只需要使用总配置文件对容器进行初始化即可。
举例:
也可使用通配符*。但,此时要求父配置文件名不能满足所能匹配的格式,否则将出现循环递归包含。就本例而言,父配置文件不能匹配 spring-.xml 的格式,即不能起名为 spring-total.xml。
Spring中基于注解的DI依赖注入
举例:di-annotation 项目
对于 DI 使用注解,将不再需要在 Spring 配置文件中声明 bean 实例。Spring 中使用注解,需要在原有 Spring 运行环境基础上再做一些改变,完成以下三个步骤。
1、导入 AOP 的 Jar 包。因为注解的后台实现用到了 AOP 编程。
2、 需要更换配置文件头,即添加相应的约束。
约束在 %SPRING_HOME%\docs\spring-framework-reference\html\xsd-configuration.html 文件中。
3、需要在 Spring 配置文件中配置组件扫描器,用于在指定的基本包中扫描注解。
(1)使用多个 context:component-scan 指定不同的包路径
(2) 指定 base-package 的值使用分隔符
分隔符可以使用逗号(,)分号(;)还可以使用空格,不建议使用空格。
逗号分隔:
分号分隔:
(3) base-package 是指定到父包名
base-package 的值表是基本包,容器启动会扫描包及其子包中的注解,当然也会扫描到子包下级的子包。所以 base-package 可以指定一个父包就可以。
或者最顶级的父包
但不建议使用顶级的父包,扫描的路径比较多,导致容器启动时间变慢。指定到目标包和合适的。也就是注解所在包全路径。例如注解的类在 com.bjpowernode.beans 包中
定义 Bean 的注解@Component
需要在类上使用注解@Component,该注解的 value 属性用于指定该 bean 的 id 值。
举例:di01
另外,Spring 还提供了 3 个功能基本和@Component 等效的注解:
● @Repository 用于对 DAO 实现类进行注解
● @Service 用于对 Service 实现类进行注解
● @Controller 用于对 Controller 实现类进行注解
之所以创建这三个功能与@Component 等效的注解,是为了以后对其进行功能上的扩展。
@Component 不指定 value 属性,bean 的 id 是类名的首字母小写。
简单类型属性注入@Value
需要在属性上使用注解@Value,该注解的 value 属性用于指定要注入的值。
使用该注解完成属性注入时,类中无需 setter。当然,若属性有 setter,则也可将其加到 setter 上。
举例:
byType 自动注入@Autowired
需要在引用属性上使用注解@Autowired,该注解默认使用按类型自动装配 Bean 的方式。
使用该注解完成属性注入时,类中无需 setter。当然,若属性有 setter,则也可将其加到 setter 上。
举例:
byName 自动注入@Autowired 与@Qualifier
需要在引用属性上联合使用注解@Autowired 与@Qualifier。@Qualifier 的 value 属性用于指定要匹配的 Bean 的 id 值。同样类中无需 setter,也可加到 setter 上。
举例:
@Autowired 还有一个属性 required,默认值为 true,表示当匹配失败后,会终止程序运行。若将其值设置为 false,则匹配失败,将被忽略,未匹配的属性值为 null。
JDK 注解@Resource 自动注入
Spring提供了对 jdk中@Resource注解的支持。@Resource 注解既可以按名称匹配Bean,也可以按类型匹配 Bean。默认是按名称注入。使用该注解,要求 JDK 必须是 6 及以上版本。
@Resource 可在属性上,也可在 set 方法上。
1、byType 注入引用类型属性
@Resource 注解若不带任何参数,采用默认按名称的方式注入,按名称不能注入 bean,则会按照类型进行 Bean 的匹配注入。
举例:
2、byName 注入引用类型属性
@Resource 注解指定其 name 属性,则 name 的值即为按照名称进行匹配的 Bean 的 id。
举例:
Bean 的生命始末@PostConstruct 与@PreDestroy
在方法上使用@PostConstruct 与原来的 init-method 等效。在方法上使用@PreDestroy,与 destroy-method 等效。
举例:
注解与 XML 的对比
注解优点是:
● 方便
● 直观
● 高效(代码少,没有配置文件的书写那么复杂)。
其弊端也显而易见:以硬编码的方式写入到Java代码中,修改是需要重新编译代码的。
● 配置和代码是分离的
● 在xml中做修改,无需编译代码,只需重启服务器即可将新的配置加载。
● xml的缺点是:编写麻烦,效率低,大型项目过于复杂。