3. 装配 Bean

简介: Spring 配置的三种方案在XML中进行显式配置。隐式的 bean 发现机制和自动装配。在 Java 中进行显式配置。

Spring 配置的三种方案


  1. 在XML中进行显式配置。


  1. 隐式的 bean 发现机制和自动装配。


  1. 在 Java 中进行显式配置。


使用 xml 配置 bean


通过 ClassPathXmlApplicationContext 进行文件加载。


基于 XML 的配置方法有对构造(有区分了无参构造 和 有参构造)注入和 setter 注入有自己的实现。然后还有工厂方法。后面还新增了 p-schema 和 c-schema。


由于字符串的约束性较差,现在更推荐使用自动扫描 + Java 进行显式配置。


集合类型的 xml形式 注入


package com.shiyanlou.spring.collections;
import java.util.*;
import com.shiyanlou.spring.innerbean.Person;
public class Customer {
    private List<Object> lists; // 这里的 lists 要和 Bean 中 property 标签的 name 一样。详见本段代码下的注释。
    private Set<Object> sets ;
    private Map<Object, Object> maps ;
    private Properties pros;
    public List<Object> getLists() {
        return lists;
    }
    public void setLists(List<Object> lists) {
        this.lists = lists;
    }
    public Set<Object> getSets() {
        return sets;
    }
    public void setSets(Set<Object> sets) {
        this.sets = sets;
    }
    public Map<Object, Object> getMaps() {
        return maps;
    }
    public void setMaps(Map<Object, Object> maps) {
        this.maps = maps;
    }
    public Properties getPros() {
        return pros;
    }
    public void setPros(Properties pros) {
        this.pros = pros;
    }
    private Person person; // 不要忘记写内部要引用的 Bean
    public Customer(Person person) {
        this.person = person;
    }
    public Customer(){}
    public void setPerson(Person person) {
        this.person = person;
    }
    @Override
    public String toString() {
        return "Customer [person=" + person + "]";
    }
}


<?xml version = "1.0" encoding = "UTF-8"?>
<beans xmlns = "http://www.springframework.org/schema/beans"
    xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation = "http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!--bean的 id 最好首字母小写 -->
    <bean id = "customerBean" class = "com.shiyanlou.spring.collections.Customer">
        <!-- java.util.List -->
        <property name = "lists">
            <list>
                <value>1</value>
                <!-- List 属性既可以通过 <value> 注入字符串,也可以通过 <ref> 注入容器中其他的 Bean-->
                 <ref bean = "personBean" />
                 <value>2</value>
                <bean class = "com.shiyanlou.spring.collections.Person">
                    <property name = "name" value = "shiyanlouList" />
                    <property name = "address" value = "chengdu" />
                    <property name = "age" value="25" />
                </bean>
            </list>
        </property>
        <!-- java.util.Set -->
        <property name = "sets">
            <set>
                <value>1</value><!--Set 与 List 类似-->
                <ref bean = "personBean" />
                <bean class = "com.shiyanlou.spring.collections.Person">
                    <property name = "name" value = "shiyanlouSet" />
                    <property name = "address" value = "chengdu" />
                    <property name = "age" value = "25" />
                </bean>
            </set>
        </property>
        <!-- java.util.Map -->
        <property name = "maps">
            <map>
                <entry key = "Key 1" value = "1" />
                <!--一个 entry 就是一个 Map 元素-->
                <entry key = "Key 2" value-ref = "personBean" />
                <entry key = "Key 3">
                    <bean class = "com.shiyanlou.spring.collections.Person">
                        <property name = "name" value = "shiyanlouMap" />
                           <property name = "address" value = "chengdu" />
                        <property name = "age" value = "25" />
                    </bean>
                </entry>
            </map>
        </property>
        <!-- java.util.Properties -->
        <property name = "pros">
        <!-- Properties 类型类似于Map 类型的特例,Map 元素的键值可以对应任何类型的对象,但是Properties只能是字符串-->
            <props>
                <prop key = "admin">admin@nospam.com</prop>
                <prop key = "support">support@nospam.com</prop>
            </props>
        </property>
    </bean>
    <bean id = "personBean" class = "com.shiyanlou.spring.collections.Person">
        <property name = "name" value = "shiyanlouPersonBean" />
        <property name = "address" value = "chengdu" />
        <property name = "age" value = "25" />
    </bean>
</beans>


隐式的 bean 发现机制和自动装配


-组件扫描和自动装配


• @ComponentScan,


4 种注释类型


@Component —— 表示一个自动扫描 component。


@Repository —— 表示持久化层的 DAO component。


@Service —— 表示业务逻辑层的 Service component。


@Controller —— 表示表示层的 Controller component。


我们可以将所有自动扫描组件都用 @Component 注释,Spring 将会扫描所有用 @Component 注释过得组件。实际上,@Repository 、@Service 、@Controller 三种注释是为了加强代码的阅读性而创造的,可以在不同的应用层中,用不同的注释。另外Spring MVC 对@Controller还会有不同的行为。


Spring 将扫描所有带有 @Component 注解的类,将其注册为bean,然后 Spring 找到带有@Autowired注解的变量,把所依赖的 Bean 注入。


不过, 组件扫描默认是不启用的。我们还需要显式配置一下 Spring,从而命令它去寻找带有 @Component 注解的类,并为其创建 bean,以下配置类展现了完成这项任务的最简洁配置。


package soundsystem;
import org.springframework.context.annotation.Componentscan;
import org.sprinqframework.context.annotation.Configuration;
@Configuration
@Componentscan
public class ConfigurationConfig {
)


如果没有其他配置的话, @ComponentScan 默认会扫描与配置类相同的包。Spring将会扫描这个包以及所有子包, 查找带有 @ComponentScan 注解的类,并且会在 Spring 中自动为其创建一个bean。如果包有多个,则可以通过 basePackages 属性进行配置。往往通过字符串进行约束是不安全的。


这里强烈建议使用 basePackageClasses 去替代 。为 basePackageClasses 属性所设置的数组中包含了类。这些类所在的包将会作为组件扫描的基础包。你可以考虑在包中创建一个用来进行扫描的空标记接口(marker interface) 。通过标记接口的方式,你依然能够保持对重构友好的接口引用,但是可以避免引用任何实际的应用程序代码。


如果你更倾向于使用 XML 来启用组件扫描的话,那么可以使用 spring context 命名空间的<context:component-scan>元素。程序清单展示了启用组件扫描的最简洁XML配置

xml 启用组件扫描


<?xml version="1.0" encoding="UTF-8"?>
 <beans xmlns="http://www.springframework.ora/schema/beans" 
xmins:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xmins:context="http://www.sprinqframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans 
http://www.springframework.org/schema/beans/sprinq-beans.xsd 
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
 <context: component-scan base-packaqe="soundsystem" />
 </beans>


为组件扫描的 bean 命名


Spring 应用上下文中所有的bean都会给定一个 ID, 具体来讲, 将类名的第一个字母变为小写


如果想为这个bean设置不同的ID,你所要做的就是将期望的 ID 作为值传递给

@Component 注解。比如说,如果想将这个bean标识为 LonelyHeartsClub ,那么你需要注解上加上 value。 @Component("LonelyHeartsClub") 。


还有另外一种为bean命名的方式, 这种方式不使用 @Component 注解,而是使用Java依赖注入规范(Java Dependency Injection)中所提供的 @Named 注解来为 bean 设置ID。


<bean>标签中配置 scope


在 Spring 中,Bean 的作用域决定了从 Spring 容器中返回的 Bean 实例的类型。在 Spring 4 中,支持以下 7 种类型的作用域:


singleton — 单例模式,由 IOC 容器返回一个唯一的 bean 实例。


prototype — 原型模式,被请求时,每次返回一个新的 bean 实例。


request — 每个 HTTP Request 请求返回一个唯一的 Bean 实例。


session — 每个 HTTP Session 返回一个唯一的 Bean 实例。


globalSession — Http Session 全局 Bean 实例。


application —


websocket —


注:大多数情况下,你可能只需要处理 Spring 的核心作用域 — 单例模式(singleton)和原型模式(prototype),默认情况下,作用域是单例模式。



网络异常,图片无法展示
|

<bean>标签中配置 autowire


Spring 支持 5 种自动装配模式,如下:


  1. no —— 默认情况下,不自动装配,通过 ref attribute 手动设定。


  1. byName —— 根据 Property 的 Name 自动装配,如果一个 bean 的 name,和另一个 bean 中的 Property 的 name 相同,则自动装配这个 bean 到 Property 中。


  1. byType —— 根据 Property 的数据类型( Type )自动装配,如果一个 bean 的数据类型,兼容另一个 bean 中 Property 的数据类型,则自动装配。


  1. constructor —— 根据构造函数参数的数据类型,进行 byType 模式的自动装配。


  1. default:由上级标签<beans>的default-autowire属性确定。


注意:在配置 bean 时,<bean>标签中 autowire 属性的优先级比其上级标签高,即是说,如果在上级标签中定义 default-autowire 属性为 byName,而在<bean>中定义为byType时,Spring IOC 容器会优先使用 <bean> 标签的配置。


通过为bean添加注解实现自动装配


使用 @Autowired 注解注入依赖项有3种方式


  1. 构造方法注入: 只能选取一个构造方法用于添加 @Autowired 注解。如果有且只有构造方法,可以省略 @Autowired 注解。


  1. Setter 注入: 任何带有 @Autowired 注解的方法,都可以注入依赖项,而不仅限于Setter方法。


  1. 字段注入: 通过在对象字段上使用 @Autowired 注解注入依赖项。


实际上, Setter方法并没有什么特殊之处。@Autowired 注解可以用在类的任何方法上。 都能发挥完全相同的作用。


如果没有匹配的 bean,那么在应用上下文创建的时候, Spring 会抛出一个异常。为了 避免异常的出现,你可以将 @Autowired 的 required 属性设置为 false。


注解方式配置Bean之间的依赖关系,可通过注解:@Autowired。如果你不愿意在代码中到处使用 Spring 的特定注解来完成自动装配任务的话,那么你可以考虑将其替换为源于 Java 依赖注入规范的  @Inject。尽管两者之间有着一些细微的差别,但是在大多数场景下,它们都是可以互相替换的。


Spring容器以何种方式匹配Bean?


默认情况下是通过数据类型(byType),当使用 @Qualifier 注解时,是通过名称(byName)。


Java 代码配置 Bean


Java 配置与注解配置不同,Java 配置是把 Java 代码文件当作配置文件,注解配置是在实际 Java 类中使用注解设置依赖关系。


Java 配置也会用到一些注解,主要有:@Configuration + @Bean。 而上面提到的 @ComponentScan 是开启组件扫描用到。


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


要在 JavaConfig 中声明 bean ,我们需要编写一个方法,这个方法会创建所需类型的实例,然后给这个方法添加 @Bean 注解。


默认情况下, bean 的 ID 与带有 @Bean 注解的方法名是一样的。在本例中, bean的名字将会是 streppers 。如果你想为其设置成一个不同的名字的话, 那么可以重命名该方法, 也可以通过 name 属性指定一个不同的名字。


package abc.lei.le;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
// 没有 @ComponentScan 扫描
@Configuration
public class ConfigurationConfig4 {
    @Bean("helloBean") // 最终 id 为 helloBean
    public Object helloWorld() {
        HelloWorld hello = new HelloWorld();
        hello.setName("helloWorld4");
        return hello;
    }
}


选择哪种装配 Bean 方案



答案是尽可能地使用自动配置的机制。显式配置越少越好。当你必须要显式配置 bean 的时候(比如,有些源码不是由你来维护的,而当你需要为这些代码配置 bean的时候) ,我推荐使用类型安全并且比 XML 更加强大的 JavaConfig。最后, 只有当你想要使用便利的 XML 命名空间,并且在 JavaConfig 中没有同样的实现时,才应该使用XML。


导入和混合配置



在 JavaConfig 导入配置:


  • 引用 XML配置,  使用 @ImportResource注解。


  • 导入JavaConfig 则用 @Import 注解。


@Configuration
@Import (CDPlayerconfiq.class)
@ImportResource("classpath:cd-config.xml")
public class SoundSystemConfig {
}


在XML配置中引用配置:


  • 导入 JavaConfig ,简单声明 bean 就可以。


  • 引用 XML配置,  使用 import 标签。


<bean classs"soundsystem.CDConfiq" />
 <import resource="cdplayer-config.xml" />


参考



Spring实战(第4版)-异步社区




目录
相关文章
|
11月前
|
XML 设计模式 Java
什么是bean
什么是bean
247 0
|
12月前
|
Java Spring 容器
Spring-在IoC中装配Bean系列文章导读
Spring-在IoC中装配Bean系列文章导读
49 0
|
XML Java 测试技术
Bean的自动装配
- 自动装配Spring满足bean依赖一种方式! - Spring会在上下文中自动寻找,并自动给Bean装配属性
|
Java Spring
Spring—Bean的装配方式—基于注解的七种装配方式
Spring—Bean的装配方式—基于注解的七种装配方式
130 0
|
Java Spring
Spring中的普通bean和工厂bean
Spring中的普通bean和工厂bean
Spring中的普通bean和工厂bean
|
XML 开发框架 Java
【Spring基础系列】基于注解装配Bean
目前学习java也有一段时间,比较不适应的就是java的各种注解,因为它里面包含了太多的东西,然后使用的姿势也各不相同,今天就简单做个总结和记录,扫一次盲后,后续使用就畅通无阻。
235 0
【Spring基础系列】基于注解装配Bean
|
XML Java 数据格式
@Bean 注解
@Bean 注解
2907 5
|
XML Java 测试技术
就是要让你彻底学会 @Bean 注解(上)
就是要让你彻底学会 @Bean 注解(上)
|
XML Java 数据格式
就是要让你彻底学会 @Bean 注解(下)
就是要让你彻底学会 @Bean 注解(下)
就是要让你彻底学会 @Bean 注解(下)
|
Java 开发者 Spring
_bean 的自动装配| 学习笔记
快速学习 _bean 的自动装配