Spring创建Bean的全过程(一)

Spring测试环境搭建

​ Spring模块概览,Spring中八大模块,黑色表示该模块的jar包(也就是组件)。例如我们想要使用IOC容器,也就是绿色的CoreContainer,我们需要导入Beans,Core,Context,SpEL(spring-expression)四个包。
在这里插入图片描述

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.3.13</version>
        </dependency>

resources下面新建beans.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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">


    <bean id="mysqlImpl" class="com.lv.dao.UserDaoMysqlImpl"/>
    <bean id="oracleImple" class="com.lv.dao.UserDaoOracleImpl"/>
    <bean id="UserServiceImpl" class="com.lv.service.UserServiceImpl">

        <property name="userDao" ref="mysqlImpl"></property>
    </bean>
    <!--
            ref :引用Spring容器中创建好的对象
            value:具体的值,基本数据类型
    -->
</beans>

java下建dao包 分别创建下面几个类

public interface UserDao {
    void getUser();
}

public class UserDaoImpl implements UserDao{

    public void getUser(){
        System.out.println("默认");
    }
}

java下建service包分别创建下面几个类

public interface UserSerivce {
    void getUser();
}


public class UserServiceImpl implements UserSerivce {

    private UserDao userDao;

    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

    public void getUser(){
        userDao.getUser();
    }

}

test目录下建MyTest

// 导包的时候记着导junit
public class MyTest {
    @Test
    public void getUser(){

       ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
       UserServiceImpl userServiceImpl = (UserServiceImpl) context.getBean("UserServiceImpl");
       userServiceImpl.getUser();
    }
}

1.2容器创建过程

从测试类的ApplicationContext context = new ClassPathXmlApplicationContext(“beans.xml”);

进入ClassPathXmlApplicationContext

	/*  
		configLocations: 是xml的名字
		refresh :是否自动刷新上下文、加载所有bean定义和创建所有单例。或者,在进一步配置上下文之后,手动调用REFRESH。
		parent: 父类上下文 也就是父容器
	*/
	public ClassPathXmlApplicationContext(
			String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
			throws BeansException {
		// 保存父容器,并将父容器的环境与当前容器环境合并。
		super(parent);
        // 设置配置文件路径
		setConfigLocations(configLocations);
		if (refresh) {
            // 核心步骤
			refresh();
		}
	}

加载配置文件后,进入AbstractApplicationContext 的refresh()方法,该方法是容器初始化的核心步骤。该方法包含十三个方法:

public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {  
             // 容器启动的状态
			StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");

			// Prepare this context for refreshing
            // 准备刷新,做一些最基本的准备化工作
			prepareRefresh();

			// Tell the subclass to refresh the internal bean factory.
            // 获得一个刷新的bean容器,实质就是获取工厂。
            // 加载xml等配置文件,用该文件产生的BeanDefinition来创建一个工厂
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// Prepare the bean factory for use in this context.
            // 准备bean工厂
			prepareBeanFactory(beanFactory);

			try {
				// Allows post-processing of the bean factory in context subclasses.
                // 后置增强 AOP,方便扩展
				postProcessBeanFactory(beanFactory);

				StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
				// Invoke factory processors registered as beans in the context.
                // 实例化和调用所有 BeanFactoryPostProcessor
				invokeBeanFactoryPostProcessors(beanFactory);

				// Register bean processors that intercept bean creation.
                // 实例化并且注册所有的BeanPostProcessor
				registerBeanPostProcessors(beanFactory);
				beanPostProcess.end();

				// Initialize message source for this context.
                // 国际化设置,一般不用
				initMessageSource();

				// Initialize event multicaster for this context.
                // 初始化事件监听多路广播器
				initApplicationEventMulticaster();

				// Initialize other special beans in specific context subclasses.
                // 空方法,预留给子类做扩展。对于子类:默认情况下不做任何操作。
				onRefresh();

				// Check for listener beans and register them.
                // 注册监听器
				registerListeners();

				// Instantiate all remaining (non-lazy-init) singletons.
                // 实例化所有非懒加载的实例对象
				finishBeanFactoryInitialization(beanFactory);

				// Last step: publish corresponding event.
                // 发布相应事件  完成刷新
				finishRefresh();
			}

			catch (BeansException ex) {
				if (logger.isWarnEnabled()) {
					logger.warn("Exception encountered during context initialization - " +
							"cancelling refresh attempt: " + ex);
				}

				// Destroy already created singletons to avoid dangling resources.
                // 销毁已经创建的单例避免资源浪费
				destroyBeans();

				// Reset 'active' flag.
                // 重启 active 标记
				cancelRefresh(ex);

				// Propagate exception to caller.
                // 抛出异常
				throw ex;
			}

			finally {
				// Reset common introspection caches in Spring's core, since we
				// might not ever need metadata for singleton beans anymore...
                // 重置Spring核心中的常见内核缓存,因为我们可能不再需要单例bean的元数据了
				resetCommonCaches();
				contextRefresh.end();
			}
		}
	}

接下来我们一个一个看,一个一个具体方法分析:

PrepareRefresh: 准备刷新,做一些基本的准备工作

	/**
	 * Prepare this context for refreshing, setting its startup date and
	 * active flag as well as performing any initialization of property sources.
	 */
	protected void prepareRefresh() {
		// Switch to active.
        // 设置开始事件
		this.startupDate = System.currentTimeMillis();
        // 关闭状态设置为false
		this.closed.set(false);
        // 活跃状态设置为true
		this.active.set(true);
		
        // 日志打印
		if (logger.isDebugEnabled()) {
			if (logger.isTraceEnabled()) {
				logger.trace("Refreshing " + this);
			}
			else {
				logger.debug("Refreshing " + getDisplayName());
			}
		}

		// Initialize any placeholder property sources in the context environment.
        // 初始化上下文属性资源
		initPropertySources();

		// Validate that all properties marked as required are resolvable:
		// see ConfigurablePropertyResolver#setRequiredProperties
        // 获取环境  验证上下文需要的属性信息
		getEnvironment().validateRequiredProperties();

		// Store pre-refresh ApplicationListeners...
        // 存储预刷新的一些应用信息的监听器
		if (this.earlyApplicationListeners == null) {
			this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);
		}
		else {
			// Reset local application listeners to pre-refresh state.
            // 将本地应用程序监听器重置为与刷新状态
			this.applicationListeners.clear();
			this.applicationListeners.addAll(this.earlyApplicationListeners);
		}

		// Allow for the collection of early ApplicationEvents,
		// to be published once the multicaster is available...
        //  创建一些监听器事件的集合
		this.earlyApplicationEvents = new LinkedHashSet<>();
	}

总结:

perpareRefresh()方法

1.设置启动事件

2.设置关闭、活跃的状态

3.初始化属性资源、获取环境信息并验证属性信息

4.设置监听器、重置本地应用的监听器状态以及创建监听事件的集合

重要的点

  • 获取环境信息,验证属性信息 getEnvironment().validateRequiredProperties();
  • 存储预刷新的一些应用信息的监听器,在Spring中是空实现,但是SpringBoot中,是由具体的值的
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

晓风残月Lx

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值