Spring源码(IOC模块)分析

    前言:Spring是我们日常Java web开发必不可少的框架,有着很优秀的设计思想,在熟练使用它的基础上,很有必要了解其源码,Spring主要有七大模块,分别为(IOC容器)Spring Core,应用上下文(Spring Context),Spring面向切面编程(Spring AOP),JDBC和DAO模块(Spring DAO),对象实体映射(Spring ORM),Web模块(Spring Web),MVC模块(Spring Web MVC)。最核心的模块为IOC和AOP,也是面试常问及的内容,本文将从比较宏观的角度分析IOC的源码,不会太深入一些细节,希望能起到抛砖引玉的作用。

    IOC也就是控制反转,让对象的创建的权力反转给IOC容器,具体通过Spring配置来创建对象,它的底层原理包括xml配置文件,dom4j解析,工厂设计模式,反射等等。使用Spring IOC容器,可以通过使用注解或xml配置的方式,Spring容器在启动的时候,先会从xml配置或者注解中保存所有注册进来的Bean定义信息。很经典的xml方式配置bean方式如下

<?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-3.0.xsd">
  <bean id="boss" class="com.baobaotao.simple.Boss"></bean> 
</beans>

 

  由于现在普遍是Spring Boot项目,xml配置的方式也渐渐被注解方式取代了,注解方式更加方便,避免了xml文件一些繁琐的配置,因此分析Spring源码过程中也是以注解方式,但是原理是一样的,配置xml只是多了一层解析xml文件罢了。

  OK,我们先看看bean的创建。这是主类

public class SpringIOCTest {
	@SuppressWarnings("resource")
	public static void main(String[] args) {
		ApplicationContext applicationContext = new AnnotationConfigApplicationContext(IOCConfig.class);
		// 获取Person bean
		Person bean = applicationContext.getBean(Person.class);
		System.out.println(bean.toString());
	}
}

配置类

@Configuration  //告诉Spring这是一个配置类
public class IOCConfig {
	//给容器中注册一个Bean
	@Bean
	public Person person(){
		return new Person("lisi", 20);
	}
}

这就配置好一个Person类 bean,是不是很简单!AnnotationConfigApplicationContext是注解的Spring上下文类,加载配置类,就可以完成配置,运行主类,就可以从Spring上下文中获取到Person类对象!下面就分析下整个过程的原理。

进入AnnotationConfigApplicationContext构造方法,可以看到有三个方法,this()是调用无参构造函数,初始化读取Bean定义信息的reader以及Bean定义包扫描对象,可以扫描一些@Componet,@Service等注解标注的组件,register方法就是注册配置类,关键是下面refresh()函数

@Override
	public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			// Prepare this context for refreshing.
			prepareRefresh();

			// Tell the subclass to refresh the internal bean factory.
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

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

			try {
				// Allows post-processing of the bean factory in context subclasses.
				postProcessBeanFactory(beanFactory);

				// Invoke factory processors registered as beans in the context.
				invokeBeanFactoryPostProcessors(beanFactory);

				// Register bean processors that intercept bean creation.
				registerBeanPostProcessors(beanFactory);

				// 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.
				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...
				resetCommonCaches();
			}
		}
	}

下面逐一分析下refresh函数里面做的事情

  1. prepareRefresh()函数是刷新前的预处理,里面做的工作主要是初始化一些属性设置;子类自定义个性化的属性设置方法;检验属性的合法等等
  2. obtainFreshBeanFactory()的作用是获取BeanFactory,Spring创建Bean可以直接Bean相关参数创建,也可以通过BeanFactory的getObject方法获取Bean
  3. prepareBeanFactory(beanFactory);这里是BeanFactory的预准备工作(BeanFactory进行一些设置),如:

1)设置BeanFactory的类加载器、支持表达式解析器

2)添加部分BeanPostProcessor。BeanPostProcessor的作用是很强大的,它能在Bean初始化的前后做一些工作,例如ApplicationContextAwareProcessor的工作就是在其方法postProcessBeforeInitialization()中对继承自ApplicationContextAware的bean进行处理,调用其setApplicationContext将Spring上下文注入。因此我们可以简单写一个实现ApplicationContextAware接口类重写setApplicationContext方法就可以得到Spring上下文来做一些事情了。

  4.     postProcessBeanFactory(beanFactory)是BeanFactory准备工作完成之后进行的设置处理工作。子类可以通过重写这个方法来在BeanFactory创建并预准备完成以后做进一步的设置操作,如下面的MyBeanFactoryPostProcessor
@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {

	@Override
	public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
		System.out.println("MyBeanFactoryPostProcessor...postProcessBeanFactory...");
		int count = beanFactory.getBeanDefinitionCount();
		String[] names = beanFactory.getBeanDefinitionNames();
		System.out.println("当前BeanFactory中有"+count+" 个Bean");
		System.out.println(Arrays.asList(names));
	}

}
 5.     invokeBeanFactoryPostProcessor(beanFactory)为执行BeanFactoryPostProcessor的方法。BeanFactoryPostProcessor为BeanFactory的后置处理器,是在BeanFactory初始化之后执行的。
 6.     registerBeanPostProcessors(beanFactory)这步是注册BeanPostProcessor,注意这是Bean的后置处理器,区别是BeanFactoryPostProcessor。两者针对的对象不一样,前者是针对Bean创建对象的方式,后者则是BeanFactory创建Bean的方式(Spring通过BeanFactory的getObject的方法获取Bean对象).不同接口类型的BeanPostProcessor;在Bean创建前后的执行时机是不一样的

        1)、获取所有的 BeanPostProcessor;后置处理器都默认可以通过PriorityOrdered、Ordered接口来执行优先级
        2)、先注册PriorityOrdered优先级接口的BeanPostProcessor;把每一个BeanPostProcessor;添加到BeanFactory中
   beanFactory.addBeanPostProcessor(postProcessor);
        3)、再注册Ordered接口的
        4)、最后注册没有实现任何优先级接口的
        5)、最终注册MergedBeanDefinitionPostProcessor;
        6)、注册一个ApplicationListenerDetector;来在Bean创建完成后检查是否是ApplicationListener,如果是
   applicationContext.addApplicationListener((ApplicationListener<?>) bean)

 7.          initMessageSource()主要是初始化MessageSource组件,来做国际化功能、消息绑定、消息解析

 8.          onRefresh()方法是空的,设计的目的主要是给子类重写,在容器刷新的时候可以自定义逻辑

 9.          finishBeanFactoryInitialization(beanFactory):初始化所有剩下的单实例Bean 。

具体过程如下:
 1、beanFactory.preInstantiateSingletons();初始化后剩下的单实例bean
   1)、获取容器中的所有Bean,依次进行初始化和创建对象
   2)、获取Bean的定义信息;RootBeanDefinition
   3)、Bean不是抽象的,是单实例的,是懒加载;
      1)、判断是否是FactoryBean;是否是实现FactoryBean接口的Bean;
      2)、不是工厂Bean。利用getBean(beanName);创建对象
         0、getBean(beanName); ioc.getBean();
         1、doGetBean(name, null, null, false);
         2、先获取缓存中保存的单实例Bean。如果能获取到说明这个Bean之前被创建过(所有创建过的单实例Bean都会被缓存起来)
            从private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(256);获取的
         3、缓存中获取不到,开始Bean的创建对象流程;
         4、标记当前bean已经被创建
         5、获取Bean的定义信息;
         6、【获取当前Bean依赖的其他Bean;如果有按照getBean()把依赖的Bean先创建出来;】
         7、启动单实例Bean的创建流程;
            1)、createBean(beanName, mbd, args);
            2)、Object bean = resolveBeforeInstantiation(beanName, mbdToUse);让BeanPostProcessor先拦截返回代理对象;
               【InstantiationAwareBeanPostProcessor】:提前执行;
               先触发:postProcessBeforeInstantiation();
               如果有返回值:触发postProcessAfterInitialization();
            3)、如果前面的InstantiationAwareBeanPostProcessor没有返回代理对象;调用4)
            4)、Object beanInstance = doCreateBean(beanName, mbdToUse, args);创建Bean
                1)、【创建Bean实例】;createBeanInstance(beanName, mbd, args);
                  利用工厂方法或者对象的构造器创建出Bean实例;
                2)、applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
                  调用MergedBeanDefinitionPostProcessor的postProcessMergedBeanDefinition(mbd, beanType, beanName);
                3)、【Bean属性赋值】populateBean(beanName, mbd, instanceWrapper);
                  赋值之前:
                  1)、拿到InstantiationAwareBeanPostProcessor后置处理器;
                     postProcessAfterInstantiation();
                  2)、拿到InstantiationAwareBeanPostProcessor后置处理器;
                     postProcessPropertyValues();
                  =====赋值之前:===
                  3)、应用Bean属性的值;为属性利用setter方法等进行赋值;
                     applyPropertyValues(beanName, mbd, bw, pvs);
                4)、【Bean初始化】initializeBean(beanName, exposedObject, mbd);
                  1)、【执行Aware接口方法】invokeAwareMethods(beanName, bean);执行xxxAware接口的方法
                     BeanNameAware\BeanClassLoaderAware\BeanFactoryAware
                  2)、【执行后置处理器初始化之前】applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
                     BeanPostProcessor.postProcessBeforeInitialization();
                  3)、【执行初始化方法】invokeInitMethods(beanName, wrappedBean, mbd);
                     1)、是否是InitializingBean接口的实现;执行接口规定的初始化;
                     2)、是否自定义初始化方法;
                  4)、【执行后置处理器初始化之后】applyBeanPostProcessorsAfterInitialization
                     BeanPostProcessor.postProcessAfterInitialization();
                5)、注册Bean的销毁方法;
            5)、将创建的Bean添加到缓存中singletonObjects;
         ioc容器就是这些Map;很多的Map里面保存了单实例Bean,环境信息。。。。;
   所有Bean都利用getBean创建完成以后;
      检查所有的Bean是否是SmartInitializingSingleton接口的;如果是;就执行afterSingletonsInstantiated();

10.        finishRefresh()这一步就是完成BeanFactory的初始化创建工作,IOC容器到这里就创建完成了。

      总结:

            1. Spring容器在启动的时候,先会保存所有注册进来的Bean定义信息,Bean定义信息有两大来源,一个就是xml配置了,就是本文刚开始提到的Bean配置方式,另一种就是注解注册Bean!就是平常我们开发常用到的@Service、@Componet、@Bean等等注解

            2.Spring容器会在合适的时机创建这些Bean,创建好就保存在容器中,如果是单例的Bean会缓存下来。最后到了统一创建剩下的Bean的时候,就是前面所提到的方法:finishBeanFactoryInitialization()

           3.后置处理器:BeanProcessor非常重要和强大,每一个Bean创建完成,都会使用各种后置处理器进行处理,从而达到增强Bean的功能,Spring另一个强大的模块AOP面向切面编程也依靠到了BeanProcessor来实现

           4.上面其实还有某一两个函数没有提到,比如initApplicationEventMulticaster(),这个函数涉及到Spring事件驱动模型,来进行事件的监听,派发。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值