ITPub博客

首页 > 数据库 > 数据库开发技术 > Spring之IoC容器

Spring之IoC容器

原创 数据库开发技术 作者:服务端技术栈 时间:2022-05-04 17:04:31 0 删除 编辑

前言


Spring’s Inversion of Control (IoC) container 简称IoC容器,也称为dependency injection (DI) 依赖注入,是Spring最核心的关键技术之一。


一、对Spring Ioc的理解


Spring IoC是对Bean的全生命周期管理的容器,包括bean创建,依赖注入,销毁。他是Spring技术生态的底座,所有的Spring技术在Ioc容器之上进行扩展实现。


beans和context包是ioc容器的基础,BeanFactory支持配置任意类型的对象。ApplicationContext是BeanFactory的子接口,它更易于集成aop,支持国际化,事件发布,以及应用层特定的上下文,如用于web应用程序的WebApplicationContext。 


二、Spring IoC需要提供的功能


1、 获取不同来源bean的资源


2、 加载读取bean资源


3、 解析资源bean的定义信息


4、 根据bean的定义信息进行实例化,并存储 


三、Spring IoC启动流程


在AbstractApplicationContext类中,Spring使用了模版模式来将Spring Ioc容器初始化流程进行了定义串连。 

public abstract class AbstractApplicationContext extends DefaultResourceLoader        implements ConfigurableApplicationContext {        // ...@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(); } } } // ... }

详细流程说明:

首先是资源定位:ioc容器需要统一创建对象,创建对象的类信息,属性信息需要从不同配置文件中解析出来,所以需要查找类的配置文件。这就是资源定位。


spring设计了如下接口和类用来定位资源路径,通过一个字符串路径获取资源加载器。字符串路径可以是类路径下的文件,网络Url,文件系统等等。其中PathMatchingResourcePatternResolver通过持有ResourceLoader的引用,可以根据不同的资源加载器加载不同位置的资源。 

//资源加载处理器 **此处使用了策略模式** 持有了ResourceResolver的引用,根据不同类型的ResourceResolver来实现加载不同位置的资源public class PathMatchingResourcePatternResolver implements ResourcePatternResolver {
//通过构造函数持有ResourceLoader引用public PathMatchingResourcePatternResolver(ResourceLoader resourceLoader) { Assert.notNull(resourceLoader, "ResourceLoader must not be null"); this.resourceLoader = resourceLoader; } //通过不同的ResourceLoader来加载资源 @Override public Resource[] getResources(String locationPattern) throws IOException { Assert.notNull(locationPattern, "Location pattern must not be null"); if (locationPattern.startsWith(CLASSPATH_ALL_URL_PREFIX)) { // a class path resource (multiple resources for same name possible) if (getPathMatcher().isPattern(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length()))) { // a class path resource pattern return findPathMatchingResources(locationPattern); } else { // all class path resources with the given name return findAllClassPathResources(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length())); } } else { // Generally only look for a pattern after a prefix here, // and on Tomcat only after the "*/" separator for its "war:" protocol. int prefixEnd = (locationPattern.startsWith("war:") ? locationPattern.indexOf("*/") + 1 : locationPattern.indexOf(':') + 1); if (getPathMatcher().isPattern(locationPattern.substring(prefixEnd))) { // a file pattern return findPathMatchingResources(locationPattern); } else { // a single resource with the given name return new Resource[] {getResourceLoader().getResource(locationPattern)}; } } }
}

不同资源类继承图

第2点是资源加载,读取到了资源文件,需要将资源文件转换成BeanDefinition,

1、先获取类信息资源字节流对象

2、加载资源字节流对象成org.w3c.dom.Document对象,在Spring中通过jdk的SAX的xml解析技术,类图如下

3、在DefaultBeanDefinitionDocumentReader类中,读取Document对象里所有xml节点,委派给BeanDefinitionParserDelegate类进行解析,使用了委派设计模式 

public class DefaultBeanDefinitionDocumentReader implements BeanDefinitionDocumentReader {    protected void doRegisterBeanDefinitions(Element root) {    BeanDefinitionParserDelegate parent = this.delegate;    this.delegate = createDelegate(getReaderContext(), root, parent);        // ....        //解析前处理    preProcessXml(root);       //解析bean定义    parseBeanDefinitions(root, this.delegate);        //解析后处理    postProcessXml(root);        //解析    this.delegate = parent;  }}

4、parseBeanDefinitions()方法进行具体解析

先解析bean标签属性,如name,id,class,参数等等,然后构造GenericBeanDefinition对象,并填充属性,这就是bean实例化的原始配方。解析主要有两种情况:

第一种是spring默认支持的标签。 

//构造GenericBeanDefinition定义public static AbstractBeanDefinition createBeanDefinition(      @Nullable String parentName, @Nullable String className, @Nullable ClassLoader classLoader) throws ClassNotFoundException {
GenericBeanDefinition bd = new GenericBeanDefinition(); bd.setParentName(parentName); if (className != null) { if (classLoader != null) { bd.setBeanClass(ClassUtils.forName(className, classLoader)); } else { bd.setBeanClassName(className); } } return bd; }

第二种是应用程序自定义的标签 


对于应用程序自定义的标签,Spring支持灵活定制,方便集成其他组件到spring中。用户可以将自己的解析器注册器放到META-INF/spring.handlers文件中,同时用户还需要自定义xsd文件和META-INF/spring.schemas文件,在tx模块和dubbo中都用到了该扩展点。在加载自定义标签的时候,spring将会加载到具体解析器。具体解析过程中,通过org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#parseCustomElement()方法进行管理解析流程。委派给NamespaceHandlerSupport进行解析,NamespaceHandlerSupport类持有了所有的解析器,由它委派给具体的解析器进行解析。

下面是自定义标签解析器相关类图。 

解析标签流程图 


5、第5步,将生成的GenericBeanDefinition对象,注册到容器中

public abstract class BeanDefinitionReaderUtils {    public static void registerBeanDefinition(      BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)      throws BeanDefinitionStoreException {
// Register bean definition under primary name. //主要名称 String beanName = definitionHolder.getBeanName(); registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition()); //注册别名 // Register aliases for bean name, if any. String[] aliases = definitionHolder.getAliases(); if (aliases != null) { for (String alias : aliases) { registry.registerAlias(beanName, alias); } } }}

注册beandefinition具体过程包括,校验,判断是否可以覆盖,保存。

public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory    implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {    @Override  public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)      throws BeanDefinitionStoreException {
Assert.hasText(beanName, "Bean name must not be empty"); Assert.notNull(beanDefinition, "BeanDefinition must not be null");
if (beanDefinition instanceof AbstractBeanDefinition) { try { ((AbstractBeanDefinition) beanDefinition).validate(); } catch (BeanDefinitionValidationException ex) { throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Validation of bean definition failed", ex); } }
BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName); if (existingDefinition != null) { if (!isAllowBeanDefinitionOverriding()) { throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition); } else if (existingDefinition.getRole() < beanDefinition.getRole()) { // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE if (logger.isInfoEnabled()) { logger.info("Overriding user-defined bean definition for bean '" + beanName + "' with a framework-generated bean definition: replacing [" + existingDefinition + "] with [" + beanDefinition + "]"); } } else if (!beanDefinition.equals(existingDefinition)) { if (logger.isDebugEnabled()) { logger.debug("Overriding bean definition for bean '" + beanName + "' with a different definition: replacing [" + existingDefinition + "] with [" + beanDefinition + "]"); } } else { if (logger.isTraceEnabled()) { logger.trace("Overriding bean definition for bean '" + beanName + "' with an equivalent definition: replacing [" + existingDefinition + "] with [" + beanDefinition + "]"); } } this.beanDefinitionMap.put(beanName, beanDefinition); } else { if (hasBeanCreationStarted()) { // Cannot modify startup-time collection elements anymore (for stable iteration) synchronized (this.beanDefinitionMap) { this.beanDefinitionMap.put(beanName, beanDefinition); List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1); updatedDefinitions.addAll(this.beanDefinitionNames); updatedDefinitions.add(beanName); this.beanDefinitionNames = updatedDefinitions; removeManualSingletonName(beanName); } } else { // Still in startup registration phase this.beanDefinitionMap.put(beanName, beanDefinition); this.beanDefinitionNames.add(beanName); removeManualSingletonName(beanName); } this.frozenBeanDefinitionNames = null; }
if (existingDefinition != null || containsSingleton(beanName)) { resetBeanDefinition(beanName); } }}

6、看的上面,beanDefinition就解析好了。

接下来spring初始化了一系列bean,这些bean比较特殊,他是Spring的bean工厂级别的,比如Environment,ClassLoader, post-processors 

public abstract class AbstractApplicationContext extends DefaultResourceLoader    implements ConfigurableApplicationContext {/**   * Configure the factory's standard context characteristics,   * such as the context's ClassLoader and post-processors.   * @param beanFactory the BeanFactory to configure   */  protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {    // Tell the internal bean factory to use the context's class loader etc.    beanFactory.setBeanClassLoader(getClassLoader());    beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));    beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
// Configure the bean factory with context callbacks. //这个地方是注册容器本身的ApplicationContextAwareProcessor,他的作用是为实现了**Aware接口的bean进行回调赋值。 beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this)); beanFactory.ignoreDependencyInterface(EnvironmentAware.class); beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class); beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class); beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class); beanFactory.ignoreDependencyInterface(MessageSourceAware.class); beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
// BeanFactory interface not registered as resolvable type in a plain factory. // MessageSource registered (and found for autowiring) as a bean. beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory); beanFactory.registerResolvableDependency(ResourceLoader.class, this); beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this); beanFactory.registerResolvableDependency(ApplicationContext.class, this);
// Register early post-processor for detecting inner beans as ApplicationListeners. 检测实现了ApplicationListener接口的bean,并存储下来 beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
// Detect a LoadTimeWeaver and prepare for weaving, if found. if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) { beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory)); // Set a temporary ClassLoader for type matching. beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader())); }
// Register default environment beans.环境对象,里面包含系统环境配置 if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) { beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment()); } if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) { //注册系统属性对象 beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties()); } if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) { //注册系统环境对象 beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment()); }  }    }

7、上一步初始化了内置的bean,接下来执行postProcessBeanFactory(beanFactory);方法方便不同容器对BeanFactory进行定制。

8、调用invokeBeanFactoryPostProcessors(beanFactory);执行所有的BeanFactoryPostProcessor。对beandefinition进行修改,这个是spring提供的扩展点,用来自定义修改beandefinition的。比如mybatis(将mapper的class统一修改成MapperFactoryBean,将mapper的class作为它的构造参数),dubbo,都使用这个技术来和spring进行集成。

9、实例化并注册所有bean的后置处理器,用于拦截bean创建。Register bean processors that intercep registerBeanPostProcessors(beanFactory); 

10、initMessageSource(); 国际化支持

11、initApplicationEventMulticaster(); 初始化事件多播器

12、onRefresh(); 子类使用,初始化其他资源

13、registerListeners(); 注册事件监听器

在spring容器中,提供了一种Event机制,实现Spring容器里的Bean实例之间进行通信。 

14、finishBeanFactoryInitialization(beanFactory); 初始化bean,并完成依赖注入

15、finishRefresh();完成容器初始化函数

16、最后回收资源,清除缓存,结束初始化


总结

Spring IoC容器启动流程是非常复杂的,里面不仅涉及到解析内置的bean资源,而且涉及到解析第三方框架定制化的bean资源,但是Spring统一了第三方对接姿势,这是非常巧妙的设计之一,因为这个扩展点让Spring被称为万能胶和粘合剂,他可以让其他框架无缝集成。

原文作者:服务端技术栈;如有侵权,请联系管理员删除。

请登录后发表评论 登录
全部评论

注册时间:2019-03-08

  • 博文量
    97
  • 访问量
    41428