装配Bean

主要有三种装配机制:

  • 隐式的bean发现机制和自动装配。
  • 在Java中进行显示配置。
  • 在xml中进行显示配置。

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

Spring从两个角度来实现自动化装配

  • 组件扫描:Spring会自动发现应用上文中所创建的bean。
  • 自动装配:Spring自动满足bean之间的依赖。

创建可发现的bean:

@Component
public class Bean1 {
    public Bean1(){
        System.out.println("##########Bean1构造成功######################");
    }
    @Override
    public String toString() {
        return "Bean1{}";
    }
}

Componet :将被注解的类作为bean。

这样Bean1类就是一个组件了,不过组件扫描默认是关闭的,要开启组件扫面有两种方式

  • 通过Spring配置类。
  • 通过xml配置文件。

通过Spring配置类

@Configuration
@ComponentScan(value = "com.spring")
public class ConScan {
}

 Configuration:将被注解的类作为配置类,作用等同配置的XML。

ComponetScan:启动组件扫描,value值表示要扫描的包,如果不写则默认为扫描配置类所在的包。

                           还可以配置扫描多个包:

@ComponentScan(value ={"com.spring.bean","com.spring.bean2"})

 通过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">

    <!-- 告知spring在创建容器时要扫描的包 -->
    <context:component-scan base-package="com.itheima"></context:component-scan>

</beans>

这样便将可被发现的bean创建完成。

bean之间的自动装配:

@Component
public class Bean2 {
    @Autowired(required = false)
    private Bean1 bean11;

    public Bean2(){
        System.out.println("*************Bean2构造成功********");
    }

    @Autowired(required = false)
     public Bean2(Bean1 bean1){
        System.out.println("*************Bean2构造成功********有参构造函数");
         System.out.println(bean1);
         bean1.toString();
     }

    @Override
    public String toString() {
        return "Bean2{}";
    }
}

Bean2类有一个Bean1变量和一个需要传递Bean1的构造函数和一个无参构造函数。

Autowired:在初始化Bean2之后,Spring会尽可能的从容器里寻找满足条件的bean来满足bean之间的依赖关系。

                  Autowired可以作用在属性和方法上。如果注解构造方法那么这个bean在初始化时会执行被Autowired注解的构造方                       法。如果有两个被Autowired注解的方法会导致运行错误。(注意:Spring默认使用无参构造方法进行初始化bean)

测试类:


@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath*:/bean.xml"})
//@ContextConfiguration(classes = ConScan.class)
public class Test {
    @Autowired
    Bean2 bean2;

    @org.junit.Test
    public void test(){
        System.out.println("———————————测试————————");
        System.out.println(bean2.getBean11());
    }
}

 Maven依赖:

<dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.0.2.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
           
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>4.2.4.RELEASE</version>
        </dependency>
    </dependencies>

扩展:

Autowired的required属性:默认值为true

                                          作用:如果Spring找不到匹配的bean进行装配那么会导致运行错误,将required设置为false时,Spring                                           会尝试进行匹配,如果没有匹配的bean,Spring会将这个bean处于为匹配状态即为null。因此如果将                                              required设为false在使用到这个bean时要注意null检查。

                                            此外,将Autowired应用到构造方法上并且将required设置为false时,如果Spring找不到匹配的bean时将不会执行这个构造方法而是执行无参构造方法。

 

为Bean命名:

                    用Componet创建bean时默认的bean名为类名首字母小写,如果需要自定义名称:@Componet("name")

另一种bean的配置方式,通过Java依赖注入规范中提供的@Named注解。

@Named
public class Bean1 {
    public Bean1(){
        System.out.println("##########Bean1构造成功######################");
    }
    @Override
    public String toString() {
        return "Bean1{}";
    }
}

Named也可以自定义bean名称。 

Spring支持将@Named 作为@Componet注解的替代方案。

二、在Java中进行显示配置。

自动装配bean只能用于开发者自己编写的类,不能用于jar包的类。通过Bean注解可以将方法的返回值装配为bean,并且ID为方法名。

 @Bean
 public Bean1 getBean12(){
     return new Bean1();
 }

注意:Bean注解一般作用于有Configuration注解的类。Spring会拦截带有Bean注解的方法,即当在方法内部调用带有Bean注解的方法时不会执行该方法而是从Spring的bean容器中获取id为该方法名的bean。

列如:

@Configuration
public class ConScan {
    @Bean
    public Bean1 getBean(){
        System.out.println("getBean执行");
        return new Bean1();
    }

    @Bean
    public Bean1 getBeanC(){
        System.out.println(getBean());
        System.out.println(getBean());
        return getBean();
    }
}

 在getBeanC方法里调用了三次getBean方法,但其实际上只有注册bean时调用getBean方法。getBeanC方法里的调用直接被Spring拦截不会正真执行,而是将id为getBean的bean直接返回。

测试类:

public class Main {

    public static void main(String[] args) {
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(ConScan.class);
        Bean1 bean12 = (Bean1) applicationContext.getBean("getBean");
        Bean1 bean22 = (Bean1) applicationContext.getBean("getBeanC");
        System.out.println(bean12 == bean22);
    }
}

结果:

getBean执行
##########Bean1构造成功######################
com.spring.bean.Bean1@6cc7b4de
com.spring.bean.Bean1@6cc7b4de
true 

以上结果都是在带有Configuration注解的类里在方法上注解Bean的。在非Configuration类的方法上注解bean,Spring不会拦截该方法而是直接运行:

列如:将Java配置类的方法移到Bean3类里,并在配置类里开启组件扫描。

@Component
public class Bean3 {
    public Bean3(){
        System.out.println("&&&&&&&&&&bean3构造完成&&&&&&&&&&&");
    }

@Bean
public Bean1 getBean(){
    System.out.println("getBean执行");
    return new Bean1();
}

    @Bean
    public Bean1 getBeanC(){

        System.out.println(getBean());
        System.out.println(getBean());
        return getBean();
    }
}

 注意在Java配置类开启组件扫描,不然无法创建bean。

结果:

##########Bean1构造成功######################
&&&&&&&&&&bean3构造完成&&&&&&&&&&&
getBean执行
##########Bean1构造成功######################
getBean执行
##########Bean1构造成功######################
com.spring.bean.Bean1@37574691
getBean执行
##########Bean1构造成功######################
com.spring.bean.Bean1@25359ed8
getBean执行
##########Bean1构造成功######################
false
 

还要注意的时Bean注解配置的bean的id为方法名,并且是整个扫描包内的,因此如果在扫描包内有不同的类但有方法名相同的带有Bean注解的方法,Spring只会装配其中一个类的方法,其他类的方法不会执行。

三、xml配置bean 

由于其内容复杂便直接通过代码讲解。

项目结构:

 

 

 

bean和测试类:

public class Bean1 {
    public Bean1(){
        System.out.println("##########Bean1构造成功######################");
    }
    public Bean1(int a){
        System.out.println("##########Bean1构造成功################有参构造="+a);

    }

}




public class Bean2 {

    public Bean2(){
        System.out.println("*************Bean2构造成功********");
    }

     public Bean2(Bean1 bean1){
        System.out.println("*************Bean2构造成功********有参构造函数bean1");
        System.out.println(bean1);
     }


}






public class Bean3 {
    Bean2 bean2;
    String name;

    List<Bean1> bean1List;
    List<String> strings;

    public List<Bean1> getBean1List() {
        return bean1List;
    }

    public void setBean1List(List<Bean1> bean1List) {
        this.bean1List = bean1List;
    }

    public List<String> getStrings() {
        return strings;
    }

    public void setStrings(List<String> strings) {
        this.strings = strings;
    }

    public Bean2 getBean2() {
        return bean2;
    }

    public void setBean2(Bean2 bean2) {
        this.bean2 = bean2;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }


    public Bean3(){
        System.out.println("&&&&&&&&&&bean3构造完成&&&&&&&&&&&");
        System.out.println(bean2+":"+name);
    }
}




public class Main {
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml");

    @Before
    public void test(){
        System.out.println("************test***********");
    }

    @Test
    public void defaultId(){
        Bean1 bean1 = (Bean1) applicationContext.getBean("com.spring.bean.Bean1#0");
        Bean1 bean2 = (Bean1) applicationContext.getBean("com.spring.bean.Bean1#1");
        System.out.println("com.spring.bean.Bean1#0: "+bean1);
        System.out.println("com.spring.bean.Bean1#1: "+bean2);
    }

    @Test
    public void id(){
        Bean1 bean1 = (Bean1) applicationContext.getBean("bean1");
        System.out.println("bean1: "+bean1);
    }

    @Test
    public void constructorArg(){
        Bean2 bean22 = (Bean2) applicationContext.getBean("bean2");
        System.out.println("constructorArg: "+bean22);
    }

    @Test
    public void ByCNamespaces(){
        Bean2 bean2 = (Bean2) applicationContext.getBean("bean2Byc");
        System.out.println(bean2);
    }

    @Test
    public void property(){
        Bean3 bean3 = (Bean3 ) applicationContext.getBean("bean3");
        System.out.println(bean3.getBean2()+" : "+bean3.getName());
        System.out.println(bean3.getBean1List()+" : "+bean3.getStrings());
    }

    @Test
    public void pNameSpace(){
        Bean3 bean3 = (Bean3) applicationContext.getBean("bean3ByP");
        System.out.println(bean3.getBean2()+" : "+bean3.getName());
        System.out.println(bean3.getBean1List()+" : "+bean3.getStrings());
    }
}

 

 xml文件:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:c="http://www.springframework.org/schema/c"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:util="http://www.springframework.org/schema/util"
       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
        http://www.springframework.org/schema/util
        http://www.springframework.org/schema/util/spring-util.xsd
        ">


    <!--默认id为全限定类名+"#0"-->
    <!--com.spring.bean.Bean1#0-->
    <!--com.spring.bean.Bean1#1-->
    <bean class="com.spring.bean.Bean1"/>
    <bean class="com.spring.bean.Bean1"/>

    <!--自定义ID-->
    <bean id="bean1" class="com.spring.bean.Bean1"/>

    <!--使用指定构造器创建bean-->

    <!--使用默认id注入虽然xml报错但能运行,并且如果仅仅使用全限定类名默认使用#0这个bean。但不建议使用-->
    <bean id="bean2" class="com.spring.bean.Bean2">
        <!--ref表示通过ID引用其他bean-->
        <constructor-arg ref="bean1"/>
    </bean>

    <!--使用c命名空间注入,需要在顶部声明其模式:xmlns:c="http://www.springframework.org/schema/c"-->
    <!--c:构造器参数名 或 _参数索引(0开启)
         -ref:如果参数为引用类型则需添加-ref,表示通过ID引用其他bean-->
    <bean id="bean2Byc" class="com.spring.bean.Bean2" c:_0-ref="bean1"/>

    <!--对成员变量进行注入(赋值)-->

    <!--使用property标签进行注入-->
    <!--
        name:变量名称
        value:变量值
        ref:其他bean的id值,表示将本id的bean注入(赋值)给这个变量。
        list:表示链表。
            value表示链元素,只能用于基本变量。
            ref:bean的id,将这个bean作为链表元素,bean取值为bean的id
    -->
    <bean id="bean3" class="com.spring.bean.Bean3">
        <property name="name" value="李华"/>
        <property name="bean2" ref="bean2Byc"/>
        <property name="strings">
            <list>
                <value>理化</value>
                <value>梨花</value>
                <value>李华</value>
            </list>
        </property>
        <property name="bean1List">
            <list>

                <ref bean="bean1"/>
                <ref bean="bean1"/>
            </list>
        </property>
    </bean>


    <!--util命名空间,需要在顶部声明-->
    <!--
        xmlns:util="http://www.springframework.org/schema/util"

        http://www.springframework.org/schema/util
        http://www.springframework.org/schema/util/spring-util.xsd
    -->
    <!--
        util命名空间中的元素
        <util:list/>        创建一个java.util.List类型的bean
        <util:constant static-field=""/>    引用某个类型的public static域,并将其暴露给bean。
        <util:map/>         创建一个java.util.Map类型的bean
        <util:properties/>  创建一个java.util.Properties类型的bean
        <util:set/>         创建一个java.util.Set类型的bean
        <util:property-path path=""/>   引用一个bean的属性,并将其暴露为bean
    -->
    <!--这是一个类型为List的bean-->
    <util:list id="beanlist">
        <ref bean="bean1"/>
        <ref bean="bean1"/>
    </util:list>

    <util:list id="strings">
        <value>理化</value>
        <value>梨花</value>
        <value>李华</value>
    </util:list>

    <!--p命名空间对属性进行注入,用法和c命名空间相似-->
    <bean id="bean3ByP" class="com.spring.bean.Bean3"
          p:bean2-ref="bean2"
          p:name="丽华"
          p:bean1List-ref="beanlist"
          p:strings-ref="strings"
    />
</beans>

欢迎探讨哦。

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值