• Spring源码分析之ioc容器是如何创建和获取单实例bean的


    首先创造ioc容器 ,这条语句一执行,所有的bean都已经创建好了,并存放在了ioc的容器中。

    ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");

    ClassPathXmlApplicationContext()方法

    点开ClassPathXmlApplicationContext()类,我们发现无论构造器都是调用了this(String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)

    public ClassPathXmlApplicationContext(
            String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
                throws BeansException {
        super(parent);
       // 解析配置文件的位置 setConfigLocations(configLocations);
    if (refresh) {
         //初始化创建所有的bean refresh(); } }

    refresh()方法

    接着点进去refresh()方法  代码如下

        @Override
        public void refresh() throws BeansException, IllegalStateException {
         
    synchronized (this.startupShutdownMonitor) { // 同步锁,保证多线程下 ioc容器只创建一次 // Prepare this context for refreshing. prepareRefresh(); // 准备了一个bean工厂 要创建所有的bean 也是ioc最大的接口 ApplicationContext也是其子接口
           // 同时也解析了xml文件,把xml文件中的所有bean配置信息保存了起来 方便下次使用
    ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
    // Prepare the bean factory for use in this context.    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); // 支持国际化功能 initMessageSource(); // Initialize event multicaster for this context. initApplicationEventMulticaster(); // 留给子类的方法 onRefresh(); // Check for listener beans and register them. registerListeners(); // I初始化所有的单实例bean (接下来看这个方法) 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(); } } }

    finishBeanFactoryInitialization(beanFactory); 

    protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
            // Initialize conversion service for this context.
            if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
                    beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
                beanFactory.setConversionService(
                        beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
            }
    
            // Register a default embedded value resolver if no bean post-processor
            // (such as a PropertyPlaceholderConfigurer bean) registered any before:
            // at this point, primarily for resolution in annotation attribute values.
            if (!beanFactory.hasEmbeddedValueResolver()) {
                beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
            }
    
            // Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.
            String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
            for (String weaverAwareName : weaverAwareNames) {
                getBean(weaverAwareName);
            }
    
            // Stop using the temporary ClassLoader for type matching.
            beanFactory.setTempClassLoader(null);
    
            // Allow for caching all bean definition metadata, not expecting further changes.
            beanFactory.freezeConfiguration();
    
            // 初始化所有单实例 初始化单实例工作是这个方法完成的  所以接下来进入这个方法来看
            beanFactory.preInstantiateSingletons();
        }

    preInstantiateSingletons()方法

      这个方法是在 DefaultListableBeanFactory下  这个类下有个beanDefinitionMap属性(ConcurrentHashmap)封装了所有的bean ,以bean的name为键

        @Override
        public void preInstantiateSingletons() throws BeansException {
            if (logger.isTraceEnabled()) {
                logger.trace("Pre-instantiating singletons in " + this);
            }
    
            // 这个beanDefinitionNames封装了所有bean的name
            List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
    
            // 遍历所有bean的name
            for (String beanName : beanNames) {
                RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
            // 如果bean是单实例的 且 不是抽象的 且 不是懒加载的
    if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
              // 第一次创建这肯定为为空 当我们创建完成后 调用getBean()时候 这就不为空了 所以这也是ioc得到bean实例的源码
    if (isFactoryBean(beanName)) { Object bean = getBean(FACTORY_BEAN_PREFIX + beanName); if (bean instanceof FactoryBean) { final FactoryBean<?> factory = (FactoryBean<?>) bean; boolean isEagerInit; if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) { isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>) ((SmartFactoryBean<?>) factory)::isEagerInit, getAccessControlContext()); } else { isEagerInit = (factory instanceof SmartFactoryBean && ((SmartFactoryBean<?>) factory).isEagerInit()); } if (isEagerInit) { getBean(beanName); } } } else {
                // 创建bean getBean(beanName); } } }

    从上述代码可以看出  无论是第一次创建bean  还是之后我们去ioc容器中取bean实例  都会经过getBean方法 所以下面来看getBean()方法  

    getBean()方法 实际执行了了 return doGetBean(name, null, null, false);  

    doGetBean(name,null,null,false)  代码有些长 只写关键部分

    protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
                @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
    
            final String beanName = transformedBeanName(name);
            Object bean;
            Object sharedInstance = getSingleton(beanName);
          // 获取单实例 先从缓存中看这个bean有没有被注册 第一次创建 肯定获取为null 第二次获取bean 才会有 所以doGetBean()也是获取bean的源码
    if (sharedInstance != null && args == null) { 省略..... } else { 省略....  // 传的参数是false 所以会进来if (!typeCheckOnly) {
              // 标记bean已经创建了 注意:代码执行到这bean并没有被创建 只是先标记一下bean被创建了
              // 目的是为了在多线程环境下 提前告诉其他线程 这个bean已经创建过了
    markBeanAsCreated(beanName); }
    try { final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); checkMergedBeanDefinition(mbd, beanName, args); // 拿到当前bean所依赖的bean String[] dependsOn = mbd.getDependsOn(); if (dependsOn != null) { for (String dep : dependsOn) { if (isDependent(beanName, dep)) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'"); } registerDependentBean(dep, beanName); try {
                     // 这是个循环调用 一直向上拿到所依赖的bean 直到没有依赖 getBean(dep); }
    catch (NoSuchBeanDefinitionException ex) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "'" + beanName + "' depends on missing bean '" + dep + "'", ex); } } } // 创造单实例. if (mbd.isSingleton()) {
                // 创造bean   sharedInstance
    = getSingleton(beanName, () -> { try { return createBean(beanName, mbd, args); } catch (BeansException ex) { // Explicitly remove instance from singleton cache: It might have been put there // eagerly by the creation process, to allow for circular reference resolution. // Also remove any beans that received a temporary reference to the bean. destroySingleton(beanName); throw ex; } }); bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); }           // 创造原型模式下的实例 else if (mbd.isPrototype()) { 省略.... } else { 省略.... } } catch (BeansException ex) { cleanupAfterBeanCreationFailure(beanName); throw ex; } }  省略....
         
         //最后返回bean return (T) bean; }

    getSingleton()方法

      源码不贴了 核心就是两行代码

      singletonObject = singletonFactory.getObject();  得到单实例bean

      addSingleton(beanName, singletonObject); 向beanDefinitionMap中添加bean 以便下次可以直接取到

    至此Spring就把所有的bean创建完了…………   源码看到吐血!!!

    还有好多细节 奈何自己才疏学浅  只能通个大概  剩下的更细节的原理 就请诸君自行学习查看了……  希望能够帮助到所有热爱java的人

  • 相关阅读:
    OI无关 透彻随笔
    置顶帖(传送门)/to 学弟 一个菜鸡的故事
    洛谷P1494 小Z的袜子 莫队
    关于 对拍 的一些认识
    关于 带权二分/wqs二分 的一些认识
    关于 KDtree 的一些认识
    关于 网络流 的一些认识
    省选 考前模板
    关于 多项式 的一些认识/多项式入门
    小球与盒子 的奇妙关系
  • 原文地址:https://www.cnblogs.com/lxy-java/p/12828792.html
Copyright © 2020-2023  润新知