Spring学习笔记-第二章-装配Bean

第二章:装配Bean

本章内容:

  • 声明bean
  • 构造器注入和Setter方法注入
  • 装配bean
  • 控制bean的创建和销毁

在Spring中,对象无需自己查找或创建与其所关联的对象,容器负责把需要相互协作的对象引用赋值给各个对象,这种协作关系成为装配


2.1 Spring配置的可选方案

Spring容器负责创建应用程序中的bean并通过DI来协调对象之间的关系。开发人员需要做的是告诉Spring需要创建哪些对象并且如何装配在一起。

Spring提供了三种可选方式:

  • XML配置
  • Java显式配置
  • 隐式的bean发现机制和自动装配

如何选择:尽可能使用自动配置机制,当必须显式配置时使用JavaConfig,当JavaConfig中没有同样实现时使用XML配置。


2.2 自动化装配bean

  • 自动扫描
  • 自动装配

2.2.1 创建可被发现的bean

package com.kotobuki2.soundsys;

/**
 * @author [email protected]
 * @since 2018/11/17 下午7:21
 */
public interface CompactDisc {
    void play();
}
package com.kotobuki2.soundsys;

import org.springframework.stereotype.Component;

/**
 * @author [email protected]
 * @since 2018/11/17 下午7:22
 */
@Component
public class SgtPeppers implements CompactDisc {
    private String title = "SgtPeppers title";
    private String artiest = "The Beatles";

    @Override
    public void play() {
        System.out.println("playing..");
    }
}
package com.kotobuki2.soundsys;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

/**
 * @author [email protected]
 * @since 2018/11/17 下午7:24
 */
@Configuration
@ComponentScan
public class CDPlayerConfig {
}

通过XML配置开启注解扫描:

<context:component-scan base-package="soundsys"/>

自动装配测试:

package com.test;

import com.kotobuki2.soundsys.CDPlayerConfig;
import com.kotobuki2.soundsys.CompactDisc;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import static org.junit.Assert.assertNotNull;

/**
 * @author [email protected]
 * @since 2018/11/17 下午7:28
 */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = CDPlayerConfig.class)
public class CDPlayerTest {
    @Autowired
    private CompactDisc compactDisc;

    @Test
    public void cdTest() {
        assertNotNull(compactDisc);
    }
}

2.2.2 为组件扫描的bean命名

默认将类名第一个字母小写后的字符串作为bean的id。

可以通过注解标示bean的别名:

@Component("alias")

2.2.3 设置组件扫描的基础包

默认以配置类所在的包为基础包进行扫描。

自定义扫描包:

@Configuration
@ComponentScan("package-name")
//扫描多个基础包
@ComponentScan(basePackages = {"package1", "package2"})

但是用直接指定包名会出现问题:包名被变更以后便无法扫描到所需要的类,因此,还有另一种指定扫描包的方法:

@Configuration
@ComponentScan(basePackageClasses = {CDPlayer.class, DVDPlayer.class})

这种方式下,这些类所在的包都会作为基础包进行扫描,即便代码重构也不会受到影响。

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

package com.kotobuki2.soundsys;

/**
 * @author [email protected]
 * @since 2018/11/17 下午8:51
 */
public interface MediaPlayer {
    void play();
}
package com.kotobuki2.soundsys;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * @author [email protected]
 * @since 2018/11/17 下午8:50
 */
@Component
public class CDPlayer implements MediaPlayer {
    private CompactDisc compactDisc;

    @Autowired
    public CDPlayer(CompactDisc compactDisc) {
        this.compactDisc = compactDisc;
    }

    @Override
    public void play() {
        compactDisc.play();
    }
}

@Autowired注解不仅能够用在构造器上,也能用在属性的Setter方法上。


2.3 通过Java装配bean

在进行显式配置的时候,JavaConfig是更好的方案,因为其强大、类型安全并且重构友好。因为其本身就是Java代码。

声明简单的bean:

@Bean(name="alias")
public CompactDisc sgtPeppers() {
    return new SgtPeppers();
}

借助JavaConfig实现注入:

@Bean
public CDPlayer cdPlayer(){
    return CDPlayer(new sgtPeppers());
}

@Bean
public CDPlayer cdPlayer(CompactDisc disc){
    return new CDplayer(disc);
}

后者不要求disc必须在JavaConfig中声明,实际上它可以通过组件扫描功能自动发现或者XML来进行配置。

通过构造器注入:

@Bean
public CDPlayer cdPlayer(CompactDisc disc){
    CDPlayer cdPlayer = new CDPlayer(disc);
    cdPlayer.setCompactDisc(disc);
    return cdPlayer;
}

2.4 通过XML装配Bean

在XML配置中,需要创建一个以作为根元素的XML配置文件。

可以借助Spring Tool Suite创建和管理Spring XML配置文件

2.4.1 声明一个简单的bean:

<bean id="bean_id" class="com.soundsys.SgtPeppers" />

如果没有指明id,bean将会根据类全限定名指定,为了减少XML配置的繁琐,只需要对需要按名称引用的bean进行命名。“com.soundsys.SgtPeppers#0”…

元素:

<bean id="cdPlayer" class="com.soundsys.CDPlayer">
    <constructor-arg ref="compactDisc" />
</bean>

2.4.2 c命名空间

p命名空间和c命名空间

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

<bean id="compactDisc" class="com.soundsys.BlackDisc">
    <constructor-arg value="title" />
    <constructor-arg value="The Beatles" />
</bean>

使用 value 属性,将给定的值注入到构造器中。

2.4.3 装配集合

<bean id="beat" class="com.soundsys.beat">
    <constructor-arg value="The Beatles"/>
    <constructor-arg>
        <list>
            <ref bean="bean1"/>
            <ref bean="bean2"/>
            <ref bean="bean3"/>
        </list>
    </constructor-arg>
</bean>

或者

<bean id="beat" class="com.soundsys.beat">
    <constructor-arg value="The Beatles"/>
    <constructor-arg>
        <set>
            <value>SgtPeppers</value>
            <value>The Beatles</value>
        </set>
    </constructor-arg>
</bean>

使用两者的区别就是 list 和 set 会忽略重复元素。

2.4.4 p命名空间

p命名空间和c命名空间

2.4.5 导入混合配置

在 JavaConfig 中引用 JavaConfig 配置:

@Configuration
@Import(CDConfig.class)
public class CDPlayerConfig {
    @Bean
    public CDPlayer cdPlayer(CompactDisc disc) {
        return new CDPlayer(disc);
    }
}

或者:

@Configuration
@Import(CDPlayerConfig.class, CDConfig.class)
public class SoundSysConfig {
}

新建一个配置类,使用@Import导入两个配置类。

在JavaConfig中引入XML配置:

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

在XML配置中引用XML配置:

<beans>
   <import resource="cd-config.xml"/>
   <bean id="cdPlayer" class="com.soundsys.CDPlayer" c:cd-ref="compactDisc">
</beans>

在XML中引入JavaConfig配置:

<beans>
    <bean class="com.soundsys.CDConfig"/>
    <bean id="cdPlayer" class="com.soundsys.CDPlayer" c:cd-ref="compactDisc"/>
</beans>

或者:

<beans>
    <bean class="com.soundsys.CDConfig"/>
    <import resource="cdplayer-config.xml"/>
</beans>

新建一个配置文件,分别导入JavaConfig配置和XML配置。


小结

Spring框架的核心是Spring容器,负责管理应用中组件的生命周期,它会创建这些组件并保证它们的依赖能够得到满足。

尽可能使用自动配置,以避免显式配置带来的维护成本。

如果确实需要显式配置,应优先选择基于Java的配置,因为其更加强大、类型安全且易于重构。