标签:comm efi -o singleton col tor rename pcl 添加
首先创造ioc容器 ,这条语句一执行,所有的bean都已经创建好了,并存放在了ioc的容器中。
ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
点开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()方法 代码如下
@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(); } } }
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(); }
这个方法是在 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);
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; }
源码不贴了 核心就是两行代码
singletonObject = singletonFactory.getObject(); 得到单实例bean
addSingleton(beanName, singletonObject); 向beanDefinitionMap中添加bean 以便下次可以直接取到
还有好多细节 奈何自己才疏学浅 只能通个大概 剩下的更细节的原理 就请诸君自行学习查看了…… 希望能够帮助到所有热爱java的人
Spring源码分析之ioc容器是如何创建和获取单实例bean的
标签:comm efi -o singleton col tor rename pcl 添加
原文地址:https://www.cnblogs.com/lxy-java/p/12828792.html