上节介绍了注入各种类型属性的方式,本节将还是基于xml方式实现自动装配,引入外部文件

FactoryBean

在之前学习的bean标签都是只能返回class属性中类型的类,当使用了FactoryBean之后就可以自定义返回类型

BeanFactory和FactoryBean不同,BeanFactory是个Factory,也就是IOC容器或对象工厂,FactoryBean是个Bean。在Spring中,所有的Bean都是由BeanFactory(也就是IOC容器)来进行管理的。但对FactoryBean而言,这个Bean不是简单的Bean,而是一个能生产或者修饰对象生成的工厂Bean,它的实现与设计模式中的工厂模式和修饰器模式类似。

演示:
代码还是使用之前的代码新建一个类需要实现FactoryBean接口并实现三个方法

public class BookFactory implements FactoryBean<Book> {
    @Override
    public Book getObject() throws Exception {
        Book book = new Book();
        return book;
    }

    @Override
    public Class<?> getObjectType() {
        return null;
    }

    @Override
    public boolean isSingleton() {
        return FactoryBean.super.isSingleton();
    }
}

并且在配置文件中将该类创建

<bean class="life.wangquanguo.spring5.FactoryBean.BookFactory" id="bookFactory"> </bean>

可以通过该bean直接获取到Book对象

Bean作用域

在 Spring 里面,默认情况下,bean 是单实例对象
在 spring 配置文件 bean 标签里面有属性(scope)用于设置单实例还是多实例

singleton,表示是单实例对象
prototype,表示是多实例对象

singleton 和 prototype 区别

singleton 单实例,prototype 多实例
设置 scope 值是 singleton 时候,加载 spring 配置文件时候就会创建单实例对象
设置 scope 值是 prototype 时候,不是在加载 spring 配置文件时候创建 对象,在调用getBean 方法时候创建多实例对象

Bean生命周期

  1. 通过无参构造方法创建对象
  2. 通过set方法注入属性
  3. (如果有后置处理器)把bean对象传递给后置处理器处理
  4. 调用初始化方法(如果存在初始化方法,需要在bean标签中单独配置)
  5. (如果有后置处理器)把bean对象传递给后置处理器处理
  6. bean对象正常被使用
  7. 容器关闭时,调用销毁方法(如果存在销毁方法,需要在bean标签中配置)

其中后置处理器需要编写类实现BeanPostProcessor并实现两个方法

public class BookPost implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("后置处理器前置方法");
        return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("后置处理器后置方法");
        return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
    }
}

spring会将bean对象在初始化方法前后分别传递给前置方法和后置方法处理

<bean class="life.wangquanguo.spring5.beanPost.BookPost" id="bookPost"></bean>

并且配置文件中所有bean都会经过后置处理器

初始化方法和销毁方法需要在bean标签中通过init-method和destroy-method两个属性来配置

<bean id="beanLifeClass" class="life.wangquanguo.spring5.BeanLiftClass" init-method="initMethod" destroy-method="destoryMethod">
        <property name="name" value="123"></property>
</bean>

演示:
准备一个类展示生命周期

public class BeanLiftClass {
    public BeanLiftClass() {
        System.out.println("构造方法");
    }
    private String name;

    public void setName(String name) {
        this.name = name;
        System.out.println("set方法");
    }

    public  void initMethod(){
        System.out.println("初始化方法");
    }

    public void destoryMethod(){
        System.out.println("销毁方法");
    }

    public void useMethod(){
        System.out.println("正常使用的方法");
    }
}

测试类

//生命周期测试
    @Test
    public void test5(){
        ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
        BeanLiftClass book = context.getBean("beanLifeClass", BeanLiftClass.class);
        book.useMethod();
        //关闭容器
        ((ClassPathXmlApplicationContext)context).close();
    }

运行结果为

构造方法
set方法
后置处理器前置方法
初始化方法
后置处理器后置方法
后置处理器前置方法
后置处理器后置方法
正常使用的方法

自动装配

之前都是使用ref或者property标签进行对象属性的装配,通过自动装配可以根据指定装配规则(属性名称或者属性类型),Spring 自动将匹配的属性值进行注入

<bean id="book" class="life.wangquanguo.spring5.Book" autowire="byType"></bean>
<bean id="pen1" class="life.wangquanguo.spring5.Pen"></bean>

通过autowire属性就可以不需要ref或者property标签注入属性,其中autowire有两个选项

byName 根据属性名称注入 ,注入值 bean 的 id 值和类属性名称一样
byType 根据属性类型注

引入外部配置文件

如果spring配置文件中bean很多,将对象中的属性放在spring配置文件中,将不利于维护项目和更改配置,所以spring可以引入外部配置文件
首先需要引入命名空间

xmlns:context="http://www.springframework.org/schema/context"
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd

以Druid连接池为例
使用context:property-placeholder标签将外部文件引入进来

<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="url" value="${pool.url}" />
        <property name="driverClassName" value="${pool.driverClass}" />
        <property name="username" value="${pool.userName}" />
        <property name="password" value="${pool.password}" />
</bean>
<!--引入配置文件-->
<context:property-placeholder location="classpath:jdbc.properties"/>

使用${}引入外部文件中的值
创建jdbc.properties文件

pool.url = jdbc:mysql://localhost:3306/user
pool.driverClass = com.mysql.jdbc.Driver
pool.userName = root
pool.password = root

编写测试类

//外部引用
    @Test
    public void test7(){
        ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
        DruidDataSource dataSource = context.getBean("dataSource", DruidDataSource.class);
        System.out.println(dataSource.getUrl());
        System.out.println(dataSource.getDriverClassName());
        System.out.println(dataSource.getUsername());
        System.out.println(dataSource.getPassword());
    }

打印结果

jdbc:mysql://localhost:3306/user
com.mysql.jdbc.Driver
root
root

Q.E.D.

知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议