• Spring系列之装配Bean


    一、概述

      容器是Spring框架的核心,Spring容器使用IOC管理所有组成应用系统的组件。Spring有两种不同的容器:BeanFactory提供最简单的容器,提供了最基础的依赖注入支持,ApplicationContext建立在BeanFactory的基础之上,提供了系统构架服务如从属性文件中读取文本信息,事件传递等。

      在Spring容器中拼凑Bean叫做装配,装配Bean的时候,你是在告诉容器需要哪些Bean以及容器如何使用依赖注入将它们配合在一起。

    二、装配Bean

      2.1  使用XML装配

      BeanFactory采用工厂设计模式,它的实现类负责创建和分发各种类型的Bean。

      Spring中有几种BeanFactory的实现,例如org.springframework.beans.factory.xml.XmlBeanFactory根据XML文件中的定义装载Bean。(现在已经不建议使用)

      ClassPathXmlApplicationContext:一种上下文,它从类路径中载入上下文定义文件

      FileSystemXmlApplicationContext:一种应用上下文,它从文件系统中载入上下文文件

      XmlWebApplicationContext:一种基于Spring的web应用系统上下文,从web应用上下文中载入上下文定义文件

    复制代码
    public class TestMain
    {
        public static void main(String[] args)
        {
            //ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext.xml");
            ClassPathResource res = new ClassPathResource("applicationContext.xml");    
            BeanFactory factory=new XmlBeanFactory(res);//XmlBeanFactory现在已经不建议使用    
            Demo2 t=(Demo2) factory.getBean("demo2");        
            System.out.println(t.getPrice());
        }
    }
    复制代码

      2.2  添加一个bean

      Bean工厂从XML文件中读取Bean的定义信息,但是此时还没有实例化Bean,Bean是被延迟载入到Bean工厂中的。然后调用getBean方法,工厂就会实例化Bean并且使用依赖注入开始设置Bean的属性。

      一个最基本的BeanFactory配置由一个或多个它所管理的Bean定义组成,在一个XmlBeanFactory中,根节点beans中包含一个或多个元素

    复制代码
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
    <beans>
      <bean id="..." class="...">
        ...
      </bean>
      <bean id="..." class="...">
        ...
      </bean>
      ...
    </beans>
    复制代码

      一个XmlBeanFactory中的Bean定义包括:

    • classname:通常是bean的真正的实现类,但是如果一个bean使用一个静态工厂方法所创建而不是被普通的构造函数创建,那么这就是工厂类的classname
    • bean行为配置元素:它声明这个bean在容器中的行为方式,比如自动装配模式、依赖检查模式、初始化和析构方法
    • 构造函数的参数和新创建bean所需要的属性:比如池的大小限制
    • 和这个bean工作相关的其他bean:比如它的合作者

      方向控制/依赖注入存在两种主要的形式:

      1、基于setter的依赖注入:是在调用无参构造函数或无参的静态方法工厂方法实例化你的bean之后,通过调用你的bean上的setter方法实现的。Spring一般提倡使用基于setter方法的依赖注入。下面就这种方法距离:

      构建Bean的实现类为Demo1.java:

    复制代码
    public class Demo1
    {
        private String name;
        private int age;
        public String getName()
        {
            return name;
        }
        public void setName(String name)
        {
            this.name = name;
        }
        public int getAge()
        {
            return age;
        }
        public void setAge(int age)
        {
            this.age = age;
        }
        public Demo1()
        {
            System.out.println("调用无参构造函数");
        }
    }
    复制代码

      applicationContext.xml中的配置为: 

    复制代码
     <bean id="demo1" class="com.Demo1">
            <property name="name">
                <value>xujian</value>
            </property>    
            <property name="age">
                <value>23</value>
            </property>
        </bean>
    复制代码

      编写测试类:

    复制代码
    public class TestMain
    {
        public static void main(String[] args)
        {
            ApplicationContext factory=new ClassPathXmlApplicationContext("applicationContext.xml");
            Demo1 t=(Demo1) factory.getBean("demo1");        
            System.out.println(t.getName());
        }
    }
    复制代码

      运行结果为:

      

      可见,通过setter方法,先是执行了该类的无参构造函数,然后调用setXXX方法来设置属性。

      2、基于构造函数的依赖注入:它是通过调用带有许多参数的构造方法来实现的,每个参数表示一个合作者或者属性,下面就这种方法举例

      使用这种方法,需要在bean的实现类中添加有参构造函数

    复制代码
    public class Demo2
    {
        private String bookName;
        private int price;
        public String getBookName()
        {
            return bookName;
        }
        public void setBookName(String bookName)
        {
            this.bookName = bookName;
        }
        public int getPrice()
        {
            return price;
        }
        public void setPrice(int price)
        {
            this.price = price;
        }
        public Demo2(String bookName, int price)
        {
            System.out.println("执行有参构造函数!");
            this.bookName = bookName;
            this.price = price;
        }
    }
    复制代码

      对应applicationContext.xml的配置为:

    复制代码
     <bean id="demo2" class="com.Demo2" >
            <constructor-arg>
                <value>Java</value>
            </constructor-arg>
            <constructor-arg>
                <value>50</value>
            </constructor-arg>
        </bean>
    复制代码

      编写测试类:  

    复制代码
    public class TestMain
    {
        public static void main(String[] args)
        {
            ApplicationContext factory=new ClassPathXmlApplicationContext("applicationContext.xml");
            Demo2 t=(Demo2) factory.getBean("demo2");    
            System.out.println(t.getBookName());
        }
    }
    复制代码

      执行结果为:

      

      2.3  原型与单实例

      Spring在缺省情况下是单实例模式,在容器分配Bean的时候总是返回同一个实例。

      测试如下:

    复制代码
    public class TestMain
    {
        public static void main(String[] args)
        {
            ApplicationContext factory=new ClassPathXmlApplicationContext("applicationContext.xml");
            Demo2 t1=(Demo2) factory.getBean("demo2");    
            Demo2 t2=(Demo2) factory.getBean("demo2");
             System.out.println(t1==t2);
        }
    }
    复制代码

      执行结果为:

      

      如果我们想每次向上下文请求一个Bean的时候总是得到一个不同的实例,则需要配置scope属性,在原配置文件中scope的默认值是singleton,现在将其设置为prototype

    复制代码
    <bean id="demo2" class="com.Demo2" scope="prototype">
            <constructor-arg>
                <value>Java</value>
            </constructor-arg>
            <constructor-arg>
                <value>50</value>
            </constructor-arg>
        </bean>
    复制代码

      再次执行上面的测试程序,结果如下:

      

      2.4  实例化与销毁

      当一个Bean实例化的时候,可能需要做一些初始化的工作,删除的时候需要做一些清理工作,在Bean的定义中设置自己的init-method和destroy-method并在xml文件中进行配置,这些方法就会在实例化创建或者销毁的时候被调用。示例如下:

      在Demo2类的定义中添加两个函数

    复制代码
      public void initialize()
        {
            System.out.println("执行了初始化函数!");
        }
        public void close()
        {
            System.out.println("执行了销毁函数!");
        }
    复制代码

      然后配置XMl文件

    复制代码
     <bean id="demo2" class="com.Demo2" init-method="initialize" destroy-method="close">
            <constructor-arg>
                <value>Java</value>
            </constructor-arg>
            <constructor-arg>
                <value>50</value>
            </constructor-arg>
        </bean>
    复制代码

      运行测试程序

    复制代码
    public class TestMain
    {
        public static void main(String[] args)
        {
            ApplicationContext factory=new ClassPathXmlApplicationContext("applicationContext.xml");
            Demo2 t1=(Demo2) factory.getBean("demo2");    
             System.out.println(t1.getBookName());
             t1.close();
        }
    }
    复制代码

      结果如下:

      

       2.5  自动装配  

      我们可以通过设置bean中的autowire属性来实现自动装配。有四种自动装配的类型:

    • byName:试图在容器中寻找和需要自动装配的属性名相同的Bean

      

    • byType:在容器中寻找与需要自动装配的属性类型相同的Bean

      

    • constructor:在容器中寻找与需要自动装配的Bean的构造函数参数一致的一个或多个Bean
    • null:无自动装配模式,Bean的引用必须要通过ref元素定义

      

  • 相关阅读:
    使用grpc C++功能
    华为任正非访谈
    苹果产品
    异步编程
    基于磁盘存储
    spring 应用
    java简单框架设计
    消息队列架构
    03 java 基础:注释 关键字 标识符 JShell
    02 java 基础:java 文件名与类名关系 CLASSPATH
  • 原文地址:https://www.cnblogs.com/yachao1120/p/10517054.html
Copyright © 2020-2023  润新知