前言
-
IOC,全称
Inversion of Control
,中文名控制反转,是Spring框架的基石。 -
Spring 发展至今,家族越来越庞大,有SpringBoot提供一站式开发,SpringCloud微服务开发等等,各种框架提供了各种各样的功能,底层依旧是IOC。例如:使用SpringMVC,自定义一个类,添加@Controller,@RequstMapping注解就能实现接收HTTP请求,其原理就是通过IOC管理自定义的类,并提供相关功能。
-
IOC可以用于对象之间的解耦。它还有个别名,依赖注入(DI), DI是实现控制反转的方式。程序员将创建对象的权利交给Spring IOC容器,它通过DI的方式实现IOC。
一、SpringBoot流程简介
-
从一个SpringBoot工程的main方法开始,简单浏览一下SpringBoot的流程
public static void main(String[] args) { SpringApplication.run(FlowableApplication.class, args); }
-
跟进源码
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定义注册进容器中
-
主要流程位于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(); } } }
-
画个流程图记一下
三、Bean初始化流程
加载bean流程如下,图来自一位大佬的博客
四、Bean单例循环依赖
循环依赖根据注入的时机分成两种类型:
- 构造器循环依赖。依赖的对象是通过构造器传入的,发生在实例化 Bean 的时候。
- 设值循环依赖。依赖的对象是通过 setter 方法传入的,对象已经实例化,发生属性填充和依赖注入的时候。
Spring中单例Bean,构造函数的循环依赖无法解决,但设值循环依赖是可以解决的。Spring通过提前暴露创建中的单例来解决设置循环依赖。
五、Bean的生命周期
上述创建bean的流程包含bean的生命周期接口,在开始初始化后面,但没不是很明显,下面详细介绍一下
根据官方文档,BeanFactory是Spring IOC容器根接口,Bean工厂实现应尽可能支持标准Bean生命周期接口, 全部初始化方法顺序如下:
-
BeanNameAware’s
setBeanName
-
BeanClassLoaderAware’s
setBeanClassLoader
-
BeanFactoryAware’s
setBeanFactory
-
EnvironmentAware’s
setEnvironment
-
EmbeddedValueResolverAware’s
setEmbeddedValueResolver
-
ResourceLoaderAware’s
setResourceLoader
(only applicable when running in an application context) -
ApplicationEventPublisherAware’s
setApplicationEventPublisher
(only applicable when running in an application context) -
MessageSourceAware’s
setMessageSource
(only applicable when running in an application context) -
ApplicationContextAware’s
setApplicationContext
(only applicable when running in an application context) -
ServletContextAware’s
setServletContext
(only applicable when running in a web application context) -
postProcessBeforeInitialization
methods of BeanPostProcessors -
InitializingBean’s
afterPropertiesSet
-
a custom init-method definition
-
postProcessAfterInitialization
methods of BeanPostProcessors当关闭Bean工厂时,下面生效
-
postProcessBeforeDestruction
methods of DestructionAwareBeanPostProcessors -
DisposableBean’s
destroy
-
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;
}
具体可以从以下源码分析
-
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); } } }
-
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); } }
-
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; }
-
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; }
-
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); } } }
-
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; }
-
AbstractAutowireCapableBeanFactory.destroyBean
public void destroyBean(Object existingBean) { new DisposableBeanAdapter(existingBean, getBeanPostProcessors(), getAccessControlContext()).destroy(); }
六、属性注入
- Spring容器中Bean在实例化后开始填充属性,使用的是BeanPostProcessor子接口InstantiationAwareBeanPostProcessor的实现类来实现注入
- 常见的2个实现类就是AutowiredAnnotationBeanPostProcessor 和 CommonAnnotationBeanPostProcessor,就是使用 @Value,@Autowired,@PostConstruct,@PreDestroy 来自动注入
- 使用的方法是InstantiationAwareBeanPostProcessor的方法postProcessProperties和postProcessPropertyValues
七、常见注解解惑
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,@Autowired | AutowiredAnnotationBeanPostProcessor |
@Scheduled | ScheduledAnnotationBeanPostProcessor |
@Aspect等AOP相关 | AbstractAutoProxyCreator |
@PostConstruct,@PreDestroy | CommonAnnotationBeanPostProcessor |