SpringBoot学习小结之IOC

25 篇文章 3 订阅
18 篇文章 0 订阅

前言

  • IOC,全称Inversion of Control,中文名控制反转,是Spring框架的基石。

  • Spring 发展至今,家族越来越庞大,有SpringBoot提供一站式开发,SpringCloud微服务开发等等,各种框架提供了各种各样的功能,底层依旧是IOC。例如:使用SpringMVC,自定义一个类,添加@Controller,@RequstMapping注解就能实现接收HTTP请求,其原理就是通过IOC管理自定义的类,并提供相关功能。

  • IOC可以用于对象之间的解耦。它还有个别名,依赖注入(DI), DI是实现控制反转的方式。程序员将创建对象的权利交给Spring IOC容器,它通过DI的方式实现IOC。

一、SpringBoot流程简介

  1. 从一个SpringBoot工程的main方法开始,简单浏览一下SpringBoot的流程

    public static void main(String[] args) {
    	SpringApplication.run(FlowableApplication.class, args);
    }
    
  2. 跟进源码

    public ConfigurableApplicationContext run(String... args) {
        	// StopWatch是Spring自带的工具类,通过它可方便的对程序部分代码进行计时(ms级别)
    		StopWatch stopWatch = new StopWatch();
    		stopWatch.start();
    		ConfigurableApplicationContext context = null;
        	// 异常报告器,用于报告启动错误信息
    		Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
        	// 配置java.awt.headless
    		configureHeadlessProperty();
        	// 从spring.factories文件中获取SpringApplicationRunListeners实例
    		SpringApplicationRunListeners listeners = getRunListeners(args);
    		listeners.starting();
    		try {
                // 获取应用命令行启动参数,例如指定server端口,指定profiles等
    			ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
                // 配置环境,判断当前是servlet或reactive web环境,还是非web环境
    			ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
                // 配置spring.beaninfo.ignore
    			configureIgnoreBeanInfo(environment);
                // 打印Banner
    			Banner printedBanner = printBanner(environment);
                // 根据当前环境获取上下文,创建beanfactory
    			context = createApplicationContext();
                // 根据上下文获取异常报告器
    			exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
    					new Class[] { ConfigurableApplicationContext.class }, context);
                // 开始为上下文刷新做准备,主要是基于注解获取bean定义并注册
    			prepareContext(context, environment, listeners, applicationArguments, printedBanner);
                // 刷新上下文,包含IOC容器的刷新流程,下面Spring IOC流程包含在这个方法里面
    			refreshContext(context);
                // 刷新完成后
    			afterRefresh(context, applicationArguments);
    			stopWatch.stop();
    			if (this.logStartupInfo) {
    				new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
    			}
    			listeners.started(context);
                // 执行实现ApplicationRunner和CommandLineRunner接口的方法
    			callRunners(context, applicationArguments);
    		}
    		catch (Throwable ex) {
                // 通过exceptionReporters处理异常
    			handleRunFailure(context, ex, exceptionReporters, listeners);
    			throw new IllegalStateException(ex);
    		}
    
    		try {
                // 
    			listeners.running(context);
    		}
    		catch (Throwable ex) {
    			handleRunFailure(context, ex, exceptionReporters, null);
    			throw new IllegalStateException(ex);
    		}
    		return context;
    	}
    

二、IOC流程

说明:以下是SpringBoot中基于注解的流程,Springboot在refresh之前就已经将bean定义注册到容器中,而Spring基于xml配置会在obtainFreshBeanFactory中解析xml文件,并将bean定义注册进容器中

  1. 主要流程位于AbstractApplicationContext

    public void refresh() throws BeansException, IllegalStateException {
        // 加锁,防止没结束又重新启动容器
        synchronized (this.startupShutdownMonitor) {
        // 准备刷新,记录下容器的启动时间、标记“已启动”状态、处理配置文件中的占位符并校验
        prepareRefresh();
        // 获取 BeanFactory
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
        // 设置 BeanFactory 的类加载器,添加几个 BeanPostProcessor,手动注册几个特殊的 bean
        // BeanPostProcessor中ApplicationContextAwareProcessor用于实现ApplicationContextAware接口注入
        prepareBeanFactory(beanFactory);
    
            try {
                     // 子类的扩展点,web环境下子类在这里添加BeanPostProcessor用于实现ServletContextAware接口注入
                    postProcessBeanFactory(beanFactory);
                    // 调用 BeanFactoryPostProcessor 各个实现类的 postProcessBeanFactory(factory) 方法
                	invokeBeanFactoryPostProcessors(beanFactory);
    
                    // 注册 BeanPostProcessor 的实现类,注意看和 BeanFactoryPostProcessor 的区别
                	registerBeanPostProcessors(beanFactory);
    
                    // 初始化当前 ApplicationContext 的 MessageSource,国际化相关
                    initMessageSource();
    
                	// 初始化当前 ApplicationContext 的事件广播器
                    initApplicationEventMulticaster();
    
                	// 从方法名就可以知道,典型的模板方法(钩子方法),
                    // 具体的子类可以在这里初始化一些特殊的 Bean(在初始化 singleton beans 之前)
                    // 加入了web依赖,会在这里创建tomcat服务器
                	onRefresh();
    
                    // 注册事件监听器,监听器需要实现 ApplicationListener 接口
                    registerListeners();
    
                    // 重点,重点,重点
                    // 初始化所有的 singleton beans
                	//(lazy-init 的除外)
                    finishBeanFactoryInitialization(beanFactory);
    
                    // 最后,广播事件,ApplicationContext 初始化完成
                    finishRefresh();
            }
    
                catch (BeansException ex) {
                    if (logger.isWarnEnabled()) {
                    logger.warn("Exception encountered during context initialization - " + "cancelling refresh attempt: " + ex);
                    }
    
                    // 销毁已经初始化的 singleton 的 Beans,以免有些 bean 会一直占用资源
                    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();
                }
            }
        }
    
  2. 画个流程图记一下

准备刷新,记录容器启动时间,
标记状态,处理配置文件占位符
获取BeanFactory
设置BeanFactory类加载器,
配置SPEL表达式解析器,
添加几个BeanPostProcessor实例
调用BeanFactoryPostProcessor各个实现类的方法
注册BeanPostProcessor各个实现类
初始化国际化相关的MessageSource
初始化当前ApplicationContext 的事件广播器
调用子类重写的onRefresh方法
查找ApplicationListener实现类,并注册
完成BeanFactory单例No-lazy Bean的初始化
完成刷新一系列后置操作,
例如清除缓存,广播已初始化完成时间

三、Bean初始化流程

加载bean流程如下,图来自一位大佬的博客

四、Bean单例循环依赖

循环依赖根据注入的时机分成两种类型:

  • 构造器循环依赖。依赖的对象是通过构造器传入的,发生在实例化 Bean 的时候。
  • 设值循环依赖。依赖的对象是通过 setter 方法传入的,对象已经实例化,发生属性填充和依赖注入的时候。
    在这里插入图片描述

Spring中单例Bean,构造函数的循环依赖无法解决,但设值循环依赖是可以解决的。Spring通过提前暴露创建中的单例来解决设置循环依赖。

五、Bean的生命周期

上述创建bean的流程包含bean的生命周期接口,在开始初始化后面,但没不是很明显,下面详细介绍一下

根据官方文档,BeanFactory是Spring IOC容器根接口,Bean工厂实现应尽可能支持标准Bean生命周期接口, 全部初始化方法顺序如下:

  1. BeanNameAware’s setBeanName

  2. BeanClassLoaderAware’s setBeanClassLoader

  3. BeanFactoryAware’s setBeanFactory

  4. EnvironmentAware’s setEnvironment

  5. EmbeddedValueResolverAware’s setEmbeddedValueResolver

  6. ResourceLoaderAware’s setResourceLoader (only applicable when running in an application context)

  7. ApplicationEventPublisherAware’s setApplicationEventPublisher (only applicable when running in an application context)

  8. MessageSourceAware’s setMessageSource (only applicable when running in an application context)

  9. ApplicationContextAware’s setApplicationContext (only applicable when running in an application context)

  10. ServletContextAware’s setServletContext (only applicable when running in a web application context)

  11. postProcessBeforeInitialization methods of BeanPostProcessors

  12. InitializingBean’s afterPropertiesSet

  13. a custom init-method definition

  14. postProcessAfterInitialization methods of BeanPostProcessors

    当关闭Bean工厂时,下面生效

  15. postProcessBeforeDestruction methods of DestructionAwareBeanPostProcessors

  16. DisposableBean’s destroy

  17. a custom destroy-method definition

上面bean生命周期位于AbstractAutowireCapableBeanFactory内initializeBean方法,10个Aware接口中前三个是写在initializeBean方法中,后7个Aware实际上都是位于BeanPostProcessor前置执行的方法里,只不过有2个实现类ApplicationContextAwareProcessor、ServletContextAwareProcessor专门用来处理这7个Aware。

如何保证这两个BeanPostProcessor的顺序,并且先执行,可以从IOC流程中可以看出已经按顺序加入BeanPostProcessors的List中。

下面是具体代码实现:

	protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
		// 上述1-3位于这里
        if (System.getSecurityManager() != null) {
			AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
				invokeAwareMethods(beanName, bean);
				return null;
			}, getAccessControlContext());
		}
		else {
			invokeAwareMethods(beanName, bean);
		}
		// 4-11在这一步
		Object wrappedBean = bean;
		if (mbd == null || !mbd.isSynthetic()) {
			wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
		}
		// 12-13在这一步
		try {
			invokeInitMethods(beanName, wrappedBean, mbd);
		}
		catch (Throwable ex) {
			throw new BeanCreationException(
					(mbd != null ? mbd.getResourceDescription() : null),
					beanName, "Invocation of init method failed", ex);
		}
        // 14在这一步
		if (mbd == null || !mbd.isSynthetic()) {
			wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
		}

		return wrappedBean;
	}

具体可以从以下源码分析

  1. AbstractAutowireCapableBeanFactory.invokeAwareMethos

    	private void invokeAwareMethods(String beanName, Object bean) {
    		if (bean instanceof Aware) {
    			if (bean instanceof BeanNameAware) {
    				((BeanNameAware) bean).setBeanName(beanName);
    			}
    			if (bean instanceof BeanClassLoaderAware) {
    				ClassLoader bcl = getBeanClassLoader();
    				if (bcl != null) {
    					((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);
    				}
    			}
    			if (bean instanceof BeanFactoryAware) {
    				((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
    			}
    		}
    	}
    
  2. ApplicationContextAwareProcessor.postProcessBeforeInitialization

    	public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    		if (!(bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
    				bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
    				bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)){
    			return bean;
    		}
    
    		AccessControlContext acc = null;
    
    		if (System.getSecurityManager() != null) {
    			acc = this.applicationContext.getBeanFactory().getAccessControlContext();
    		}
    
    		if (acc != null) {
    			AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
    				invokeAwareInterfaces(bean);
    				return null;
    			}, acc);
    		}
    		else {
    			invokeAwareInterfaces(bean);
    		}
    
    		return bean;
    	}
    	private void invokeAwareInterfaces(Object bean) {
    		if (bean instanceof EnvironmentAware) {
    			((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
    		}
    		if (bean instanceof EmbeddedValueResolverAware) {
    			((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
    		}
    		if (bean instanceof ResourceLoaderAware) {
    			((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
    		}
    		if (bean instanceof ApplicationEventPublisherAware) {
    			((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
    		}
    		if (bean instanceof MessageSourceAware) {
    			((MessageSourceAware) bean).setMessageSource(this.applicationContext);
    		}
    		if (bean instanceof ApplicationContextAware) {
    			((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
    		}
    	}
    
  3. ServletContextAwareProcessor.postProcessBeforeInitialization

    	public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    		if (getServletContext() != null && bean instanceof ServletContextAware) {
    			((ServletContextAware) bean).setServletContext(getServletContext());
    		}
    		if (getServletConfig() != null && bean instanceof ServletConfigAware) {
    			((ServletConfigAware) bean).setServletConfig(getServletConfig());
    		}
    		return bean;
    	}
    
  4. AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization

    	public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
    			throws BeansException {
    
    		Object result = existingBean;
    		for (BeanPostProcessor processor : getBeanPostProcessors()) {
    			Object current = processor.postProcessBeforeInitialization(result, beanName);
    			if (current == null) {
    				return result;
    			}
    			result = current;
    		}
    		return result;
    	}
    
  5. AbstractAutowireCapableBeanFactory.invokeInitMethods

    	protected void invokeInitMethods(String beanName, Object bean, @Nullable RootBeanDefinition mbd)
    			throws Throwable {
    
    		boolean isInitializingBean = (bean instanceof InitializingBean);
    		if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
    			if (logger.isTraceEnabled()) {
    				logger.trace("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
    			}
    			if (System.getSecurityManager() != null) {
    				try {
    					AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
    						((InitializingBean) bean).afterPropertiesSet();
    						return null;
    					}, getAccessControlContext());
    				}
    				catch (PrivilegedActionException pae) {
    					throw pae.getException();
    				}
    			}
    			else {
    				((InitializingBean) bean).afterPropertiesSet();
    			}
    		}
    
    		if (mbd != null && bean.getClass() != NullBean.class) {
    			String initMethodName = mbd.getInitMethodName();
    			if (StringUtils.hasLength(initMethodName) &&
    					!(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
    					!mbd.isExternallyManagedInitMethod(initMethodName)) {
    				invokeCustomInitMethod(beanName, bean, mbd);
    			}
    		}
    	}
    
  6. AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsAfterInitialization

    	public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
    			throws BeansException {
    
    		Object result = existingBean;
    		for (BeanPostProcessor processor : getBeanPostProcessors()) {
    			Object current = processor.postProcessAfterInitialization(result, beanName);
    			if (current == null) {
    				return result;
    			}
    			result = current;
    		}
    		return result;
    	}
    
  7. AbstractAutowireCapableBeanFactory.destroyBean

    	public void destroyBean(Object existingBean) {
    		new DisposableBeanAdapter(existingBean, getBeanPostProcessors(), getAccessControlContext()).destroy();
    	}
    

六、属性注入

  1. Spring容器中Bean在实例化后开始填充属性,使用的是BeanPostProcessor子接口InstantiationAwareBeanPostProcessor的实现类来实现注入
  2. 常见的2个实现类就是AutowiredAnnotationBeanPostProcessor 和 CommonAnnotationBeanPostProcessor,就是使用 @Value,@Autowired,@PostConstruct,@PreDestroy 来自动注入
  3. 使用的方法是InstantiationAwareBeanPostProcessor的方法postProcessPropertiespostProcessPropertyValues

七、常见注解解惑

1. @Controller

  • @Controller注解是一个特殊的@Component ,可以被Spring检测到加入Bean容器中。
  • 除了使用@Controller注解之外,我们一般还会用@RequestMapping注解来配置http方法和路径。在SpringMvc中,使用RequestMappingHandlerMapping来处理这种请求。
  • AbstractHandlerMethodMapping这个类实现了InitializingBean接口,而RequestMappingHandlerMapping是它子类的子类。在afterPropertiesSet方法中调用了isHandler方法判断容器中bean是不是处理http请求的handler,在RequestMappingHandlerMapping的实现如下,只要bean加了Controller注解或RequestMapping注解就会被判断是一个handler。
	protected boolean isHandler(Class<?> beanType) {
		return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
				AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
	}
  • RequestMappingHandlerMapping是何时加入Spring容器中的?由WebMvcAutoConfiguration可知RequestMappingHandlerMapping 在自动装配时被SpringBoot加入容器
		@Bean
		@Primary
		@Override
		public RequestMappingHandlerMapping requestMappingHandlerMapping() {
			// Must be @Primary for MvcUriComponentsBuilder to work
			return super.requestMappingHandlerMapping();
		}

2. BeanPostProcessor

BeanPostProcessor是一个十分重要的接口,有很多实现类实现了我们常用注解的功能,具体可以查看类源码,调试了解是如何实现相关功能

注解相关实现类
@Value,@AutowiredAutowiredAnnotationBeanPostProcessor
@ScheduledScheduledAnnotationBeanPostProcessor
@Aspect等AOP相关AbstractAutoProxyCreator
@PostConstruct,@PreDestroyCommonAnnotationBeanPostProcessor

参考

  1. https://docs.spring.io/spring/docs/5.2.8.RELEASE/javadoc-api/
  2. https://docs.spring.io/spring/docs/5.2.8.RELEASE/spring-framework-reference/core.html#beans
  3. 深入理解 Spring 之源码剖析IOC
  4. Spring IOC 容器源码分析
  5. 图文并茂,揭秘 Spring 的 Bean 的加载过程
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

aabond

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

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

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

打赏作者

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

抵扣说明:

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

余额充值