Spring实战读书笔记Spring装配Bean

Posted xiueer

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring实战读书笔记Spring装配Bean相关的知识,希望对你有一定的参考价值。

目录

一、自动装配bean

1、组件扫描

2、自动装配

二、通过Java代码装配Bean

1、简单配置

2、依赖注入

三、通过Xml装配Bean

借助构造器注入初始化bean

设置属性

混合配置


Spring容器负责创建应用程序中的bean并通过DI来装配(wiring)他们。Spring有三种装配方式,三种方式可以搭配使用

 

(1)隐式的bean发现机制和自动装配(推荐使用)

(2)在java中显式装配

(3)在xml中显式装配

一、自动装配bean

Spring从2个角度实现自动装配

1、组件扫描:自动发现应用上下文中所创建的bean

2、自动装配:Spring自动满足bean之间的依赖

1、组件扫描

//例子,CD和CDPlayer

// CD接口
package soundsystem;

public interface CompactDisc 
    void play();


//实现类
package soundsystem;

import org.springframework.stereotype.Component;

@Component //组件注解
public class SgtPeppers implements CompactDisc 

    public void play() 
        System.out.println("play SgtPeppers");
    

在上面的例子中,SgtPeppers类上加了@Component注解,这个注解就表明该类是一个bean,Spring会自动识别到该bean并处理。Spring还支持使用@Named注解作为@Component的替代方案,使用较少。Spring会为每一个bean设定一个ID,默认情况下,未类型首字母小写,上例中bean id为sgtPeppers。如果需要显式的指定bean id,只需要将期望的ID值传递给@Component注解

@Component("longlyHeatsClub")// 指定bean id
public class SgtPeppers implements CompactDisc 
    ...

不过组件扫描默认是不开启的,需要显式的配置开启组件扫描。Spring提供了2种配置方式:Java方式和xml方式。

java方式开启组件扫描

package soundsystem;

import org.springframework.context.annotation.ComponentScan;

@ComponentScan//开启组件扫描
public class CDPlayerConfigs 

只需要新建一个配置类,并在该类上添加@ComponentScan注解变可以开启组件扫描。在例子中@ComponentScan没有加任何的参数,默认是扫描该配置类所在的包及其子包。如果要显式设定需要扫描的基础包,只需要在注解后面加上basePackages属性即可

@ComponentScan(basePackages="soundsystem")//指定基础包的报名
public class CDPlayerConfigs 


@ComponentScan(basePackages="soundsystem","video")//指定多个基础包的报名
public class CDPlayerConfigs 

以上的指定基础包的包名为字符串形式的,这种方式是类型不安全的,可能存在配置错误的情况。Spring还提供了一种方式,可以通过指定包中所包含的类或接口的方式配置。这些类所在的包将会被作为组件扫描的基础包。

@ComponentScan(basePackageClasses = CDPlayer.class, DVDPlayer.class)
    public class CDPlayerConfigs 

在实际使用中,可以考虑在包中单独创建一个用来进行扫描的空标记接口,将这些空标记接口配置在@ComponentScan中即可为需要的包开启组件扫描。

xml方式开启组件扫描

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:Context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">

    <Context:component-scan base-package="soundsystem"/>

</beans>

以xml方式开启组件扫描需要要加入Context:component-scan元素即可。可以看到,xml方式开启组件扫描明显要比java方式复杂。

2、自动装配

自动装配就是让Spring自动满足bean依赖的一种方法,在满足依赖的过程中,会在Spring应用上下文中寻找匹配某个bean需求的其他bean。可以使用@Autowired开启自动装配。

package soundsystem;

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

@Component
public class CDPlayer implements MediaPalyer 
    private CompactDisc cd;

    @Autowired //自动装配
    public CDPlayer(CompactDisc cd)
        this.cd = cd;
    
    @Override
    public void play() 
        cd.play();
    

@Autowired不仅可以用在构造方法上,还可以用在setter和其他任何方法上。在Spring初始化bean之后,他会尽可能的满足bean的依赖。如果找不到匹配bean,会抛出异常。可以设置required=false避免抛出异常。(谨慎使用)

 @Autowired(required=false)
    public CDPlayer(CompactDisc cd)
        this.cd = cd;
    

@Autowired也可用用在变量上

@Autowired写在变量上和构造器上的区别

@Autowired:构造函数注入和变量注入

二、通过Java代码装配Bean

大部分场景下都可以使用自动装配的方式实现自动化配置,但是在某些场景下还是需要显式的配置bean的,比如想要将第三方库中的组件装配到应用中,我们无法在别人的代码上添加@Component和Autowired注解。此时,就需要显式的配置了,Spring提供了2种显式配置的方式:Java和Xml。Java配置是比Xml更好的配置方式,他更强大,类型安全并且对重构友好。

现在,把前面例子中的@ComponentScan和@Component注解去掉。

...
public class SgtPeppers implements CompactDisc 

    public void play() 
        System.out.println("play SgtPeppers");
    

要如何获取到SgtPeppers bean呢?

1、简单配置

在JavaConfig中,写一个方法返回一个SgtPeppers,并添加@Bean注解就可以啦。@Bean注解会告诉Spring这个方法会返回一个对象,并且这个对象要注册为Spring应用上下文中的Bean。默认bean id与方法名是一样的,也可以指定bean id。

    @Bean // 默认bean id为sgtPeppers
    public CompactDisc sgtPeppers()
        return new SgtPeppers();
    

    @Bean(name = "lonelyHeartsClueBead")
    public CompactDisc sgtPeppers()
        return new SgtPeppers();
    

在这个方法中,可以加入自己的逻辑,这样实际上为bean创建赋予了极大的灵活性。只要最终返回的是一个CompactDisc即可。

2、依赖注入

以上是简单情况下的bean配置。如果要装配的bean又依赖于其他的bean呢?

    @Bean
    public CompactDisc sgtPeppers()
        return new SgtPeppers();
    

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

这样就可以实现cdPlayer的bean装配了。只不过这里需要注意的是,看起来在创建cdPlayer实例的时候是是通过调用sgtPeppers()得到的,但是sgtPeppers()上是添加了@Bean注解的,所以实际上Spring会拦截所有对它的调用,并直接返回在Spring应用上下文中的那个bean(默认情况下,Spring的bean都是单例的)。所有无论有多少个方法调用sgtPeppers()的bean,其实都是用一个bean。

    // 2个sgtPeppers()返回的bean是同一个
    @Bean
    public CDPlayer cdPlayer()
        return new CDPlayer(sgtPeppers());
    

    @Bean
    public CDPlayer cdPlayer2()
        return new CDPlayer(sgtPeppers());   
    

当然,以上代码其实不是最好的依赖注入方式。下面的方式看起来更加的易于理解

    @Bean
    public CDPlayer cdPlayer(CompactDisc compactDisc)
        return new CDPlayer(compactDisc);
    

cdPlayer 方法有一个参数,当Spring创建cdPlayer bean的时候,会自动为其装配一个CompactDisc。而且通过这种方式装配cdPlayer便不需要将compactDisc声明在同一个配置类中。他可以以任意的形式配置(Java/Xml),只要是一个Spring的bean即可。

三、通过Xml装配Bean

声明一个简单的bean

    <bean class="soundsystem.SgtPeppers"/> <!-- 默认bean id为SgtPeppers#0,其中#0是序号 -->
    <bean id="sgtPeppers"  class="soundsystem.SgtPeppers"/> <!-- 指定bean id-->

借助构造器注入初始化bean

在xml中声明DI时,有多种可选的配置方案,具体到构造器注入,可以有2种基本的配置方案(1)<constructor-arg>方案(2)使用Spring3.0所引入的c-命名空间

    public CDPlayer cdPlayer(CompactDisc compactDisc)
        return new CDPlayer(compactDisc);
    

我们以上面的bean为例,假设需要创建这个bean,并且注入CompactDisc bean。可以使用如下方式注入bean引用。

    方式1
    <bean id="cdPlayer" class="soundsystem.CDPlayer">
        <constructor-arg ref="sgtPeppers"/>     //假设sgtPeppers已经在其他地方定义好了
    </bean>

    方式2
    <bean id="cdPlayer" class="soundsystem.CDPlayer" c:cd-ref="sgtPeppers"/>

除了可以注入bean的引用意外,还可以将字面量注入到构造器中。也可以将list/set集合注入到构造器中,而此集合中的元素又可以是字面量或者bean引用。

设置属性

假设存在如下的CDPlayer

package soundsystem;

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

@Component
public class CDPlayer implements MediaPalyer 
    private CompactDisc cd;

    @Autowired
    public void setCompactDisc(CompactDisc cd)
        this.cd = cd;
    
    @Override
    public void play() 
        cd.play();
    

为了注入CDPlayer的cd属性,我们需要定义如下的bean

    方法1 property属性注入
    <bean id="cdPlayer" class="soundsystem.CDPlayer">
        <property name="compactDisc" ref="sgtPeppers"/>
    </bean>

    方法2 p命名空间注入
    <bean id="cdPlayer" class="soundsystem.CDPlayer" p:compactDisc-ref="sgtPeppers"/>

同样的,除了为属性注入引用意外,还可以为其注入字面量(p命名空间不能注入集合)

混合配置

一般的项目规模较大是,不会只有一个配置文件,这时候可能就设计到配制之间的引用。

// Java中引用java
@Configuration
@Import(CDConfig.class)
public class CDPlayerConfigs ...

// Java中引用xml
@Configuration
@ImportResource("classpath:springConfig.xml")
public class CDPlayerConfigs ...
    <!--xml中引用xml-->
    <import resource="SpringConfig2.xml"/>

    <!--xml中本身无法引用java配置,可以通过将java config定义为一个bean的方式间接引用这个java配置-->
    <bean class="soundsystem.CDConfig"/>

当然是实际使用中,更常用的做法是定义一个更高层的配置文件(无论是java还是xml),其中引用所有的分模块的配置,以实现统一管理

 

 

以上是关于Spring实战读书笔记Spring装配Bean的主要内容,如果未能解决你的问题,请参考以下文章

SpringInAction读书笔记--第2章装配Bean

《spring实战》学习笔记-第二章:装配bean

Spring实战笔记二

Spring实战(第4版)读书笔记记录

Spring 实战-第二章-装配Bean

Spring实战之装配Bean