Spring Bean的生命周期

一、概述

二、注入单向对象引用属性时

2.1原理

注入单向对象引用属性时,从容器中 getBean 获取后通过 set 方法反射设置进去,如果容器中没有,则先创建被注入对象 Bean 实例(完成整个生命周期)后,在进行注入操作。

2.2实验

1.要注入的属性在要创建bean的前面

applicationContext.xml:

<bean class="com.itheima.service.impl.UserServiceImpl2" id="userService">
      <property name="userDao" ref="userDao"/>
      <property name="userName" value="MM"/>
  </bean>
<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl" init-method="init"></bean>

测试:

package com.itheima.test;

import com.alibaba.druid.pool.DruidDataSource;
import com.itheima.beans.OthrerBean;
import com.itheima.beans.Xxxbean;
import com.itheima.dao.UserDao;
import com.itheima.dao.impl.UserDaoImpl;
import com.itheima.dao.personDao;
import com.itheima.service.UserService;
import com.mysql.jdbc.Connection;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import javax.xml.bind.annotation.XmlAccessOrder;
import java.io.IOException;
import java.io.InputStream;
import java.sql.DriverManager;

public class BeanFactoryTest {
    public static void main(String[] args) throws Exception {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext_beanfac.xml");
        UserService userService = applicationContext.getBean(UserService.class);
    }
}

结果:

直接从BeanDefinitionMap中拿了

2.要注入的属性在要创建bean的后面

applicationContext.xml:

<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl" init-method="init"></bean>
<bean class="com.itheima.service.impl.UserServiceImpl2" id="userService">
      <property name="userDao" ref="userDao"/>
      <property name="userName" value="MM"/>
  </bean>

结果:

在创建userService发现需要userDao属性但是BeanDefinitionMap中没有,就停下来先创建userDao,然后再继续注册。

三、注入双向对象引用属性

源码流程(由于源码剖析较为繁琐,篇幅太大,所以在这里就没有过多的阐述了,不过下面的图片是较为详细的,可以依据下面的图片自行进行剖析):

四、Aware接口

Aware接口在开发中虽然不常用,但是它的思想却经常用在很多框架进行底层注入bean,常用的Aware接口如下:

实验:

UserServiceImpl:

package com.itheima.service.impl;

import com.itheima.dao.UserDao;
import com.itheima.service.UserService;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.web.context.ServletContextAware;

import javax.servlet.ServletContext;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

//@Service("userService")
public class UserServiceImpl2 implements UserService, ServletContextAware, BeanFactoryAware, ApplicationContextAware, BeanNameAware
{
    @Override
    public void show2() {
//        打印集合
//        System.out.println(userDaoList);
//        System.out.println(stringList);
//        打印集合
//        System.out.println(userDaoSet);
////        打印集合
//        System.out.println(stringSet);
//        System.out.println(userDaoMap);
//        System.out.println(properties);
        System.out.println(userDao);
    }

    @Override
    public void show1() {
//        打印集合

    }

    public UserServiceImpl2() {
//        System.out.println("userService已经加载,已执行构造函数");
    }

    private UserDao userDao;

    public void setUserDao(UserDao userDao) {
//        System.out.println("userServerce执行注入UserDao的操作,即执行set方法");
        this.userDao = userDao;
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        System.out.println(beanFactory);
    }

    @Override
    public void setBeanName(String s) {
        System.out.println(s);
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        System.out.println(applicationContext);
    }

    @Override
    public void setServletContext(ServletContext servletContext) {
        System.out.println(servletContext);
    }
}

测试:

package com.itheima.test;

import com.alibaba.druid.pool.DruidDataSource;
import com.itheima.beans.OthrerBean;
import com.itheima.beans.Xxxbean;
import com.itheima.dao.UserDao;
import com.itheima.dao.impl.UserDaoImpl;
import com.itheima.dao.personDao;
import com.itheima.service.UserService;
import com.mysql.jdbc.Connection;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import javax.xml.bind.annotation.XmlAccessOrder;
import java.io.IOException;
import java.io.InputStream;
import java.sql.DriverManager;

public class BeanFactoryTest {
    public static void main(String[] args) throws Exception {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext_beanfac.xml");
        UserService userService = applicationContext.getBean(UserService.class);
    }
}

结果:

由于是没有配置web环境,所以servletContext没有打印出来。

五、SpringIOC总结

至此Spring的bean定义和生命周期都是学习完了,下面就用几幅图来做一一个简单的总结吧:

然后每个阶段的大致流程可以用下面三幅图来概括:

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐