码迷,mamicode.com
首页 > 编程语言 > 详细

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

时间:2020-05-05 00:58:55      阅读:72      评论:0      收藏:0      [点我收藏+]

标签:comm   efi   -o   singleton   col   tor   rename   pcl   添加   

首先创造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的人

 

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

标签:comm   efi   -o   singleton   col   tor   rename   pcl   添加   

原文地址:https://www.cnblogs.com/lxy-java/p/12828792.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!