Spring装配Bean的3种方式

要装配bean,首先应该知道bean应该要装到哪里去,在spring中容纳bean(也就是对象实例)的东西叫容器。容器是spring的核心,容器里面装着各种各样的对象实例Bean。

​ spring的容器总体来讲有两个类型,一个是bean工厂,另一个是应用上下文(或者叫应用环境)ApplicationContext。我们常用的是应用上下文这个容器。

装配Bean的三种方式

  1. 在XML配置文件中进行显示配置(最次选择)
  2. 在Java配置类中进行显示配置(次优选择)
  3. 使用注解的spring隐式自动发现机制和自动装配(最优选择)

自动装配

第一步:创建基本显示配置类,开启组件扫描

实现自动装配仍然需要一定的显示配置,首先我们仍然需要一个配置类,这个配置类中什么都不需要写,但是需要加上必要的注解。

@Configuration
@ComponentScan(value = {"aop"})
public class AopConfig {
}
@Configuration

@Configuration注解会告诉spring这是一个配置类,这是必须的注解

@ComponentScan

@ComponentScan注解指明需要扫描哪些包下的类,并为他们创建实例放入spring容器中,也就是开启组件扫描。

@ComponentScan的基本使用:

如果直接在配置类上贴上@ComponentScan注解,表示只扫描被贴上注解的配置类所在的包以及所在包的子包。

@Configuration
@ComponentScan
public class AopConfig {
}

但是我们很多时候需要将配置类单独放到一个包中。这样就他的默认扫描范围就不满足我们的要求。于是我们可以这样修改。可以指定需要扫描的包,值是一个string类型的数组,值的具体元素为包得类路径,所以可以指定多个扫描的范围。

@Configuration
@ComponentScan(value = {"aop"})
public class AopConfig {
}

明确的指明所设置的包是基础包

@Configuration
@ComponentScan(basePackages = {"com.ctbu.spring_demo1.config"})
public class AppConfig {
}

扫描的基础包可以有多个,支持接收集合

@Configuration
@ComponentScan(basePackages = {"com.ctbu.spring_demo1.config", "com.ctbu.spring_demo1.controller"})
public class AppConfig {
}

支持类作为扫描标记,使用这种方式的话对重构代码很友好,spring会自动去寻找这个类,并把这个类所在的包作为扫描的基础包。如果需要的时候,可以创建一个空的接口为组件扫描提供标记。

@Configuration
@ComponentScan(basePackageClasses = Person.class)
public class AppConfig {
}   

第二步:标注需要加入容器的类

@Component
public class Dance implements Performance {
}
@Component

@Component注解会将贴上注解的类作为spring的组件扫描进spring容器中。

@Component详解

spring应用上下文会给所有的bean都分配一个id,作为这个对象实例的唯一标识,当我们没有明确的指定这个id的时候,spring会自动为其分配一个id

情况 措施
在xml配置文件中没有明确指定beanID spring会以全限定类名写作为BeanID
在组件扫描中没有明确指定BeanID spring会以类名的首字母小写作为BeanID
在Java配置类中没有明确指定BeanID spring会以方法名作为BeanID

如果想自定义beanID

情况 措施
在组件扫描中 指定@Component的值:@Component("person")
在xml配置文件中 指定bean的id属性 :id="person"
在Java配置类中 指定@Bean注解的值:@Bean(name=“person”)

spring还支持使用@Name来为bean(对象实例)命名,用法:@Name(“person”),但是此方法基本不使用。

第三步:使用容器中的组件

public class MagicTest {
    @Autowired
    private Performance magic;
    
    @Test
    public void perform() {
        magic.perform(20);
        SpecialService service = (SpecialService) magic;
        service.specialService();
    }
}
@Autowired

@Autowired注解表示spring会对被标注的变量使用自动装配,spring会从容器中找出适合的bean实例,并将他赋值给这个变量。

@Autowired注解的使用

@Autowired注解不仅可以使用在一般的变量上,还可以使用在构造器方法,和属性的setter方法上。实际上@Autowired注解可以用在类中的任何方法上,spring会尽力去满足方法上所声明的依赖。

在自动注入的过程中,如果spring没有在spring容器中找到合适的bean进行注入,spring就会抛出异常,为了避免这个异常的发生,我们以及将@Autowired注解的required属性设置为false

@Autowired(required = false)

但此时也要注意空指针异常的情况。

同样@Autowired注解也有替代方案@Inject,但是我们基本不使用这个注解,@Autowired更加适合spring,也更加让人容易接收。

使用Java配置类进行显示配置

为什么要使用Java配置类的方式?尽管自动装配已经很强大了,对于我们自己写的bean,自动装配完全可以满足要求,但是,对于第三方的bean,比如datesource等,我们无法在其源码上贴上@Component注解,因此必须通过new其对象来创建对应的bean,而基于xml配置文件的方式也可以达到这样的效果,但是xml实在是太繁琐了。

第一步:创建配置类

@Configuration
public class AopConfig {
}

如上代码是一个完整的基于Java配置类的组件装配设置。

如果完全使用Java配置类来为spring容器中添加bean,那么就可以不用开启组件扫描。

@Configuration

@Configuration注解表示被标注的类是一个配置类,spring容器对象可以从这个配置类中加载需要装入容器的bean实例。

第二步:声明Bean

@Configuration
public class AopConfig {
    @Bean
    public Dance dance(){
        return new Dance();
    }
}

如上代码,当spring加载这个配置类的时候就会把创建的对象实例,作为组件,放入到spring容器中。默认情况下,这里创建的bean的名称ID为方法名,但是我们也可以自己指定名称ID。(在上面的表格中有详细归纳)

@Bean(name = "dance")
@Bean

@Bean注解会告诉spring这个被标注的方法会返回一个对象,而这个返回的对象要注册为spring容器中的bean

第三步:使用组件

这一步和自动装配是一样的,同样可以使用@Autowired进行注入。

Java配置类装配存在引用的bean

很多时候,我们在装配一个bean的时候,这个bean可能引用了其他的bean实例,这样的配置在Java配置类中同样可以实现。下面的代码展示如何装配存在对象引用的bean

public class Man {

    Food food;

    public Man(Food food){
        this.food = food;
    }

    public void eat() {
        System.out.println("吃:" + this. food);
    }
}

在上面的代码中,可以知道,如果要通过Java配置类的方式将Man这个bean放入spring容器中,那么newMan对象的时候需要有一个Food对象的引用。可以这样做。

@Configuration
@ComponentScan(basePackageClasses = Person.class)
public class AppConfig {

    @Bean
    public Food food(){
        return new Food();
    }

    @Bean
    public Man man(){
        return new Man(food());
    }
}

直接在man这个方法中调用food()方法,以为food方法一定会产生一个Food类型的实例bean。

还有一种更加简单的当时来实现有引用的装配。

@Configuration
@ComponentScan(basePackageClasses = Person.class)
public class AppConfig {

    @Bean
    public Food food(){
        return new Food();
    }

    @Bean
    public Man man(Food food){
        return new Man(food);
    }
}

如上Java配置类,直接将要引用的对象作为方法的形参传入,在创建对应bean的时候可以直接使用这个形参,spring会自动满足这个依赖。而且,要强调的是,这个要传入的形参food并不一定要求和Man在同一个配置类中,它可以是通过自动装配实现的,也可以在其他Java配置类中,甚至可以是在xml配置文件中,只要spring能在容器中发现他的存在。

使用XML配置文件进行装配

使用XML配置文件进行bean的装配之前,首先需要创建一个xml配置文件,这一步相当于Java配置类中的@Configuration注解的作用。

<?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">

</beans>
声明一个简单的Bean
<?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 class="com.ctbu.xmlconfigtest.domain.Person"/>

</beans>

如上就声明了一个最简单的,以XML配置文件形式装配的bean实例

这里没有明确指定bean的id,所以默认情况下,会以类的全限定名称,也就是:com.ctbu.xmlconfigtest.domain.Person 作为bean的默认id,但是这太麻烦了,每一次引用难道都要写这么大一串?

因此,可以使用id属性指定bean的id;

<?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="person" class="com.ctbu.xmlconfigtest.domain.Person"/>

</beans>
XML中构造器参数的注入

XML配置文件中也会存在要配置对象引用的时候,这个使用有两种方式

  1. <constructor-arg/>元素
  2. c-命名空间:spring3.0后引入的功能
使用<constructor-arg / >元素
<?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="person" class="com.ctbu.xmlconfigtest.domain.Person"/>

    <bean id="work" class="com.ctbu.xmlconfigtest.domain.Work">
        <constructor-arg ref="person"/>
    </bean>

</beans>

可以看到,创建work对象的时候需要注入一个person对象的引用,使用<constructor-arg ref="person"/>元素实现了这一需求。

使用c-命名空间

这里的c:后面使用了构造器参数的名称

<?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:c="http://www.springframework.org/schema/c"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="person" class="com.ctbu.xmlconfigtest.domain.Person"/>

    <bean id="work" class="com.ctbu.xmlconfigtest.domain.Work" c:person-ref="person"/>

</beans>

使用位置标志

<?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:c="http://www.springframework.org/schema/c"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="person" class="com.ctbu.xmlconfigtest.domain.Person"/>

    <bean id="work" class="com.ctbu.xmlconfigtest.domain.Work" c:_0-ref="person"/>

</beans>

当构造器只有一个参数的时候,可以直接使用下划线(这种方式在IDEA集成环境下会报错,但是并不影响使用,这是集成环境的检查机制)所以选择一个最合适的即可

<?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:c="http://www.springframework.org/schema/c"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="person" class="com.ctbu.xmlconfigtest.domain.Person"/>

    <bean id="work" class="com.ctbu.xmlconfigtest.domain.Work" c:_-ref="person"/>

</beans>
构造器中注入字面量值

使用xml元素注入(此时的constructor-arg后不再用ref进行引用,而直接是value属性)

<?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:c="http://www.springframework.org/schema/c"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="person" class="com.ctbu.xmlconfigtest.domain.Person">
        <constructor-arg value="李白"/>
    </bean>

</beans>

使用c-命名空间

<?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:c="http://www.springframework.org/schema/c"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="person" class="com.ctbu.xmlconfigtest.domain.Person" c:name="李白"/>

</beans>
构造器装配集合

这种装配在XML中只有<constructor-arg/>属性能办到

<?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:c="http://www.springframework.org/schema/c"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="person" class="com.ctbu.xmlconfigtest.domain.Person">
        <constructor-arg>
            <list>
                <value>篮球</value>
                <value>足球</value>
                <value>游戏</value>
            </list>
        </constructor-arg>
    </bean>

</beans>

这里person对象的构造器需要一个string数据类型的数据,同样的如果实际上你需要的是一个其他对象类型的引用,你可以把value改成ref即可完成bean引用列表的装配。

对于集合类型的变化也可以自行选择,使用list还是set,他们的差别和Java语法中,list和set集合的差别是一样的。

<?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:c="http://www.springframework.org/schema/c"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="person" class="com.ctbu.xmlconfigtest.domain.Person">
        <constructor-arg>
            <set>
                <value>篮球</value>
                <value>足球</value>
                <value>游戏</value>
            </set>
        </constructor-arg>
    </bean>

</beans>
XML中属性值的注入

属性值的注入方式也有2种,都需要提供属性的setter方法

  • XML元素注入
  • p命名空间注入
字面量属性注入——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:c="http://www.springframework.org/schema/c"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="person" class="com.ctbu.xmlconfigtest.domain.Person">
        <property name="name" value="李白"/>
    </bean>

</beans>
p-命名空间的方式
<?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:c="http://www.springframework.org/schema/c" xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="person" class="com.ctbu.xmlconfigtest.domain.Person" p:name="李白"/>

</beans>

若属性值为对象引用,同样使用ref的方式进行引用

<?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:c="http://www.springframework.org/schema/c" xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="person" class="com.ctbu.xmlconfigtest.domain.Person">
        <property name="work" ref="work"/>
    </bean>
    
    <bean id="work" class="com.ctbu.xmlconfigtest.domain.Work"/>

</beans>
属性中集合的装配
<?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:c="http://www.springframework.org/schema/c" xmlns:p="http://www.springframework.org/schema/p"
       xmlns:util="http://www.springframework.org/schema/util"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util https://www.springframework.org/schema/util/spring-util.xsd">

    <bean id="person" class="com.ctbu.xmlconfigtest.domain.Person">
        <property name="hobby">
            <list>
                <value>唱</value>
                <value>鬼畜</value>
            </list>
        </property>
    </bean>

</beans>

使用util命名空间完成属性集合的装配,如果使用util命名空间则需要在头部引入util命名空间规范。

<?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:c="http://www.springframework.org/schema/c" xmlns:p="http://www.springframework.org/schema/p"
       xmlns:util="http://www.springframework.org/schema/util"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util https://www.springframework.org/schema/util/spring-util.xsd">

    <bean id="person" class="com.ctbu.xmlconfigtest.domain.Person">
        <property name="hobby" ref="hobby"/>
    </bean>

    <util:list id="hobby">
        <value>唱</value>
        <value>跳</value>
        <value>rap</value>
    </util:list>

</beans>

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容