Spring核心容器(二) | bean使用及配置详细介绍

bean

bean获取

bean有下面三种获取方式:

方式一: 使用bean名称获取

BookDao bookDao = (BookDao) ctx.getBean("bookDao");

方式二: 使用bean名称获取并指定类型

BookDao bookDao = ctx.getBean("bookDao", BookDao.class);

方式三: 使用bean类型获取, 传入的类型, 该类型的bean只能有一个

BookDao bookDao = ctx.getBean(BookDao.class);

bean配置

bean基础配置

在上面快速入门的案例中, 我们已经完成了bean基础配置的学习

类别 描述
名称 bean
类型 标签
所属 beans标签
功能 定义Spring核心容器管理的对象
格式 <beans>
<bean/>
<bean></bean>
</beans>
属性列表 id:bean的id,使用容器可以通过id值获取对应的bean,在一个容器中id值唯一
class:bean的类型,即配置的bean的全路径类名
范例 <bean id=“bookDao” class=“com.itheima.dao.impl.BookDaoImpl”/>
<bean id=“bookService” class=“com.itheima.service.impl.BookServiceImpl”></bean>

bean别名配置

开发者直接的命名习惯是不一样的, 因此bean可以取别名, 一个bean可以有多个名称:

bean标签中有一个name属性用于配置别名

类别 描述
名称 name
类型 属性
所属 bean标签
功能 定义bean的别名,可定义多个,多个名称之间使用逗号(,)分号(;)空格( )分隔
范例 <bean id=“bookDao” name=“dao bookDaoImpl” class=“com.itheima.dao.impl.BookDaoImpl”/>
<bean name=“service,bookServiceImpl” class=“com.itheima.service.impl.BookServiceImpl”/>

演示代码:

在配置文件中, 为bean取service和service2两个别名

<?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="bookDao" class="com.chenyq.dao.impl.BookDaoImpl"/>

    <!--通过name属性取别名-->
    <bean id="bookService" name="service, service2" class="com.chenyq.service.impl.BookServiceImpl">
        <property name="bookDao" ref="bookDao"/>
    </bean>

</beans>

在代码中, 现在我们可以通过id: bookService, 以及别名: service和service2获取到bean

public class App {
    
    
    public static void main(String[] args) {
    
    
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        // 通过别名获取bean
        BookService bookService = (BookService) ctx.getBean("service");
        BookService bookService2 = (BookService) ctx.getBean("service2");
        bookService.save();
        bookService2.save();
    }
}

我们还可以给bookDao的bean取别名, 再让bookService进行DI时参照别名

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

    <!--取别名dao-->
    <bean id="bookDao" name="dao" class="com.chenyq.dao.impl.BookDaoImpl"/>

    <bean id="bookService" name="service, service2" class="com.chenyq.service.impl.BookServiceImpl">
        <!--ref属性参照dao这个别名, 同样是可以的-->
        <property name="bookDao" ref="dao"/>
    </bean>

</beans>

注意: 获取bean无论是通过id还是name获取,如果无法获取到,将抛出异常NoSuchBeanDefinitionException

bean作用范围配置

默认情况下bean创建是单例的, 创建多次bean指向同一内存地址, 也就是说多次创建出来的是同一个对象

若想要创建非单例, 那么就要通过scope配置

类别 描述
名称 scope
类型 属性
所属 bean标签
功能 定义bean的作用范围,可选范围如下: singleton:单例(默认); prototype: 非单例
范例 <bean id=“bookDao” class=“com.itheima.dao.impl.BookDaoImpl” scope=“prototype” />

示例代码

<!--设置非单例-->
<bean id="bookDao" class="com.chenyq.dao.impl.BookDaoImpl" scope="prototype"/>

适合交给容器进行管理的bean

表现层对象

业务层对象

数据层对象

工具对象

不适合交给容器进行管理的bean

封装实体的域对象

bean实例化

bean是如何创建出来的, 和我们自己创建一个对象的方式有区别吗?

bean实例化通常有下面几种方式, 下面我们来一一学习

bean实例化的方式一: 构造方法(常用)

bean本质上就是对象,创建bean使用的是无参构造方法完成, 所有我们需要提供可访问的构造方法

public class BookDaoImpl implements BookDao {
    
    
  	public BookDaoImpl() {
    
    
      	System.out.println("book constructor is running ...");
    }
  	public void save() {
    
    
      	System.out.println("book dao save ...");
    }
}

无参构造方法如果不存在,将抛出异常BeanCreationException

实例化bean的方式二: 静态工厂(早期方式, 了解

例如我们有下面这样一个工厂类, 工程类中的getBookDao方法用来造对象

public class BookDaoFactory {
    
    
    public static BookDao getBookDao() {
    
    
        return new BookDaoImpl();
    }
}
public class App {
    
    
    public static void main(String[] args) {
    
    
        BookDao bookDao = BookDaoFactory.getBookDao();
        bookDao.save();
    }
}

我们可以配置该类的bean

<!--注意配置静态工厂类, 需要通过factory-method属性指定使用工厂类的哪一个方法-->
<bean id="bookFactory"
      class="com.chenyq.factory.BookDaoFactory"
      factory-method="getBookDao"
/>

再通过配置的bean进行实例化

public class App2 {
    
    
    public static void main(String[] args) {
    
    
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");

        BookDao bookDao = (BookDao) ctx.getBean("bookFactory");
        bookDao.save();
    }
}

实例化bean的方式三: 实例工厂(了解)

例如我们有下面一个实例工厂, 使用实例工厂创建的方式如下, 与静态工厂相比多了一步实例化工程对象

public class BookDaoFactory {
    
    
    public BookDao getBookDao() {
    
    
        return new BookDaoImpl();
    }
}
public class App2 {
    
    
    public static void main(String[] args) {
    
    
        BookDaoFactory bookFactory = new BookDaoFactory();
        BookDao bookDao = bookFactory.getBookDao();
        bookDao.save();
    }
}

使用实例工厂实例化bean, 首先需要将工厂的bean造出来, 在通过工厂的bean将工厂要创建对象的bean造出来

<!--实例工厂实例化bean-->
<bean id="bookFactory" class="com.chenyq.factory.BookDaoFactory"/>

<bean id="bookDao" factory-method="getBookDao" factory-bean="bookFactory"/>
public class App2 {
    
    
    public static void main(String[] args) {
    
    
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");

        BookDao bookDao = (BookDao) ctx.getBean("bookFacDao");
        bookDao.save();
    }
}

实例化bean方式三的改良: 使用FactoryBean实例化(重点掌握)

但是上面方法中, 工厂bean是为了创建方法bean而存在的, 是为了配合使用并无实际意义, 并且方法名不固定, 每次都需要配置

因此Spring针对第三种方式进行了改良

我们使用这个方法, 创建一个工程时需要实现FactoryBean接口, 并重写方法

public class BookDaoFactoryBean implements FactoryBean<BookDao> {
    
    
    /**
        代替原始实例工厂中创建对象的方法
        返回要创建的对象即可
     */
    public BookDao getObject() throws Exception {
    
    
        return new BookDaoImpl();
    }

    /**
        该方法返回工厂创建对象的类型
     */
    public Class<?> getObjectType() {
    
    
        return BookDao.class;
    }
}

使用FactoryBean, 我们的配置就会变得简单

<!--FactoryBean实例化bean-->
<bean id="bookFacDao" class="com.chenyq.factory.BookDaoFactoryBean"/>

实现FactoryBean接口工厂创建出来的对象, 默认是单例的;

如果想要设置非单例模式, 我们需要重写isSingleton方法,该方法返回一个布尔值, true代表单例, false代表非单例

public class BookDaoFactoryBean implements FactoryBean<BookDao> {
    
    
    public BookDao getObject() throws Exception {
    
    
        return new BookDaoImpl();
    }

    public Class<?> getObjectType() {
    
    
        return BookDao.class;
    }

    /**
        返回true单例
        返回false非单例
     */
    public boolean isSingleton() {
    
    
        return false;
    }
}

bean生命周期

生命周期:从创建到消亡的完整过程

bean生命周期:bean从创建到销毁的整体过程

bean生命周期控制:在bean创建后到销毁前做一些事情

bean控制生命周期有两种方式:

配置方式

接口方式(了解)

配置方式控制生命周期:

提供生命周期的控制方法

public class BookDaoImpl implements BookDao {
    
    
    public void save() {
    
    
        System.out.println("book dao save...");
    }

    /**
        表示bean初始化调用的方法
     */
    public void init() {
    
    
        System.out.println("init...");
    }
    /**
        表示bean销毁之前调用的方法
     */
    public void destory() {
    
    
        System.out.println("destory...");
    }
}

提供方法后, 我们还需要配置生命周期控制的方法, 通过init-method和destroy-method属性配置

<!--配置生命周期控制的方法-->
<bean id="bookDao"
      class="com.chenyq.dao.impl.BookDaoImpl"
      init-method="init"
      destroy-method="destory"
/>

接口方式控制生命周期

Spring觉得这样配置任意一个方法就是生命周期太过于随意; 因此Spring提供了InitializingBean和DisposableBean两个接口的方式控制生命周期, 每个接口都提供一个方法, 我们重写其方法即可, 这样还省去了两次配置

public class BookDaoImpl implements BookDao, InitializingBean, DisposableBean {
    
    
    public void save() {
    
    
        System.out.println("book dao save...");
    }

    public void destroy() throws Exception {
    
    
        System.out.println("destroy...");
    }

    public void afterPropertiesSet() throws Exception {
    
    
        System.out.println("init...");
    }
}

下面我们来了解一下, bean在初始化到销毁过程中经历了哪些阶段:

初始化容器

  • 创建对象(内存分配), 可以理解为new在做的事情
  • 执行构造方法
  • 执行属性注入(set操作), 设置属性的操作是优先于初始化生命周期执行的
  • 执行bean初始化方法, 也就是执行初始化的生命周期方法

使用bean:

  • 执行业务操作

关闭/销毁容器:

  • 关闭/销毁容器之前, 执行bean销毁生命周期方法

关闭容器的方式:

手工关闭容器

  • ConfigurableApplicationContext接口close()操作, 该方法属于暴力关闭
ublic static void main(String[] args) {
    
    
    // 使用ClassPathXmlApplicationContext获取IoC容器
    ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");

    BookDao bookDao = (BookDao) ctx.getBean("bookDao");
    bookDao.save();

    // 使用close方法关闭容器
    ctx.close();
}

注册关闭钩子,在虚拟机退出前会先关闭容器再退出虚拟机

  • ConfigurableApplicationContext接口registerShutdownHook()操作
public static void main(String[] args) {
    
    
    // 使用ClassPathXmlApplicationContext获取IoC容器
    ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");

    // 使用registerShutdownHook方法注册关闭钩子, 此代码可以放在任意一样
    ctx.registerShutdownHook();

    BookDao bookDao = (BookDao) ctx.getBean("bookDao");
    bookDao.save();
}

猜你喜欢

转载自blog.csdn.net/m0_71485750/article/details/127947653