Spring source code analysis (1) IOC source code analysis

Spring-ioc source code analysis

Overview: Spring is an ioc container. Ioc means we hand over the dependencies between objects to spring for management. For example, we define various bean relationships in configuration files or java configuration classes, and spring is responsible for loading these beans, and The dependencies between classes are maintained. If we need to use beans, just getBean directly. This is the main function of spring as an Ioc container.

One, class introduction

1. Overview of ApplicationContext

In order to analyze the principle of ioc, we start with the applicationContent class that can be touched. The following is our startup code.

ApplicationContext context = new ClassPathXmlApplicationContext(xmlPath)。

The above code can use the configuration file to start a Spring container. This code is to load beans from the configuration file into the spring container. In addition to ClassPathXmlApplicationContext, we also have AnnotationConfigApplicationContext (java configuration) and FileSystemXmlApplicationContext (similar to ClassPathXml).

Let's take a look at the class structure of ApplicationContext first. The implementation classes we have used are mainly ClassPathXmlApplicationContext and AnnotationConfigApplicationContext.

ApplicationContext
           ConfigurableApplicationContext
            AbstractApplicationContext
            AbstractRefreshableApplicationContext                  GenericApplicationContext
                                                                                             AnnotationConfigApplicationContext
            AbstractRefreshableConfigApplicationContext
            AbstractXmlApplicationContext
           ClassPathXmlApplicationContext

2. Introduction of BeanFactory

We are talking about the BeanFactory interface, BeanFactory is the interface that provides beans, and its sub-interfaces add extended functions on this basis. Our ApplicationContext above also implements the BeanFactory interface, but it is another implementation that is really responsible for loading the bean. The class DefaultListableBeanFactory completes bean parsing and registration . // You can find the properties of the DefaultListableBeanFactory type from AbstractRefreshableConfigApplicationContext.

    BeanFactory ( ApplicationContext series also have many classes or interfaces that implement BeanFactory )
    AutowireCapableBeanFactory HierarchicalBeanFactory ListableBeanFactory
    ConfigurableListableBeanFactory // inherits the above three interfaces
    DefaultListableBeanFactory // implements ConfigurableListableBeanFactory and BeanDefinitionRegistry (responsible for registering beanDefinition)

3. Introduction of BeanDefinition

When introducing BeanDefinition, we know that DefaultListableBeanFactory implements the BeanDefinitionRegistry interface function to load and register beans.

Let's first look at what the DefaultListableBeanFactory uses to store the created bean, intercept some member variables, beanDefinitionMap is to store BeanDefinition information.

    private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>(64);
    private final Map<Class<?>, String[]> allBeanNamesByType = new ConcurrentHashMap<Class<?>, String[]>(64);
    private final Map<Class<?>, String[]> singletonBeanNamesByType = new ConcurrentHashMap<Class<?>, String[]>(64);

BeanDefinition saves the name of our bean, the type of bean, which class it depends on, and whether it is a singleton, and so on.
 

2. Process analysis

1. Refresh backbone method

ClassPathXmlApplicationContext mainly calls the refresh method, and there are many other methods called in the refresh() method, see below for details.

public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			prepareRefresh();
			// 标记1---加载bean配置以及注册 
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
			prepareBeanFactory(beanFactory);
			try {
				postProcessBeanFactory(beanFactory);
				invokeBeanFactoryPostProcessors(beanFactory);
				registerBeanPostProcessors(beanFactory);
				initMessageSource();
				initApplicationEventMulticaster();
				onRefresh();
				registerListeners();
				// 标记2--- 初始化所有的 singleton beans
				finishBeanFactoryInitialization(beanFactory);
				finishRefresh();
			}
		}
	}

The mark 1 method function above indicates how to load the BeanDefinition into the container, the mark 2 method is to create Bean and initialize, and the others are some subsidiary processing functions.

Let's first look at the main functions of these subsidiary methods:

prepareBeanFactory: Register the default BeanPostProcessor to implement some functions.

invokeBeanFactoryPostProcessors: Execute methods of various implementation classes of BeanFactoryPostProcessor.

registerBeanPostProcessors: Register the implementation class of BeanPostProcessor. This method will enhance the bean before and after initialization, which has not been initialized here.

2. ObtainFreshBeanFactory--load registered bean

After introducing some of the common processing of refresh, let's take a look at the starting point method of refresh, obtainFreshBeanFactory, to see how spring loads various beans from the configuration file to the internal DefaultListableBeanFactory.

obtainFreshBeanFactory actually calls the obtainFreshBeanFactory method.

    protected final void refreshBeanFactory() throws BeansException {
        if (hasBeanFactory()) {// ... }
        try {
           // 创建了DefaultListableBeanFactory,下面设置成this.beanFactory赋值
            DefaultListableBeanFactory beanFactory = createBeanFactory();
            beanFactory.setSerializationId(getId());
            customizeBeanFactory(beanFactory);
            // 实际加载方法
            loadBeanDefinitions(beanFactory); 
            synchronized (this.beanFactoryMonitor) {
                this.beanFactory = beanFactory;
            }
        }
    }
	protected DefaultListableBeanFactory createBeanFactory() {
		return new DefaultListableBeanFactory(getInternalParentBeanFactory());
	}

From the above we can see that refreshBeanFactory creates a DefaultListableBeanFactory to load registered beans.

The loadBeanDefinitions series call stack, the specific implementation is too complicated, we know that the main thing is to load the configured bean into the DefaultListableBeanFactory. ( Follow-up supplement )

3. FinishBeanFactoryInitialization --- create bean and initialize bean

protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
        // ....
		beanFactory.setTempClassLoader(null);

		// 允许缓存元数据,即以后不会变更 
		beanFactory.freezeConfiguration();

		// 实例化所有此时没有实例的单例bean  【主要调用方法】
		beanFactory.preInstantiateSingletons();
	}

As you can see from the above code, finishBeanFactoryInitialization actually calls the preInstantiateSingletons method of DefaultListableBeanFactory .

public void preInstantiateSingletons() throws BeansException {
		
		List<String> beanNames = new ArrayList<String>(this.beanDefinitionNames);

		for (String beanName : beanNames) {
            // 得到的BeanDefinition加工成RootBeanDefinition
			RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
            // 不是抽象方法不是懒加载和多例
			if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) { 
				if (isFactoryBean(beanName)) {
					final FactoryBean<?> factory = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName);
					boolean isEagerInit;
					if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
					   // ....
					}
					else {
						isEagerInit = (factory instanceof SmartFactoryBean &&
								((SmartFactoryBean<?>) factory).isEagerInit());
					}
					if (isEagerInit) {
						getBean(beanName);  
					}
				}
				else { // 创建bean的核心方法
					getBean(beanName);
				}
			}
		}

	    // ....略
	}

As you can see from the above, only singletons that are not lazy loaded and multiple instances will execute the get'Bean method, and this method calls doGetBean , which is super long.

	protected <T> T doGetBean(final String name, final Class<T> requiredType, finalObject[] args, boolean typeCheckOnly)throws BeansException {

		final String beanName = transformedBeanName(name);
		Object bean;

		Object sharedInstance = getSingleton(beanName);
		if (sharedInstance != null && args == null) {
			// 缓存中取
			bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
		} else {
			// 父工厂取
			BeanFactory parentBeanFactory = getParentBeanFactory();
			if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
				String nameToLookup = originalBeanName(name);
				if (args != null) {
					return (T) parentBeanFactory.getBean(nameToLookup, args);
				}
				else {
					return parentBeanFactory.getBean(nameToLookup, requiredType);
				}
			}
			if (!typeCheckOnly) {
				markBeanAsCreated(beanName);
			}
			try {
				final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
				checkMergedBeanDefinition(mbd, beanName, args);
				String[] dependsOn = mbd.getDependsOn();
				if (dependsOn != null) {
					for (String dependsOnBean : dependsOn) {
						if (isDependent(beanName, dependsOnBean)) {
							throw new BeanCreationException(""); //循环依赖了
 						}
						registerDependentBean(dependsOnBean, beanName);
						getBean(dependsOnBean); // 依赖执行注册和getBean
					}
				}

				if (mbd.isSingleton()) {
					sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
						@Override
						public Object getObject() throws BeansException {
							try {
                                // 创建bean 核心调用方法
								return createBean(beanName, mbd, args);
							}
							catch (BeansException ex) {
					
								destroySingleton(beanName);
								throw ex;
							}
						}
					});
					bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
				}

				else if (mbd.isPrototype()) {
					 // 多例略....
				}

				else {
					 // 其他略....
				}
			}
		}

		// ....

		return (T) bean;
	}

The doGetBean method is still very long after my deletion. It mainly includes fetching from the cache, returning from the parent container if it exists, and returning if found, then judging the dependent bean inside the BeanDefinition, and registering the dependency if there is a dependency, and The same execution of getBean() is equivalent to recursively calling all dependent beans and executing a series of getBean methods. Finally, the dependencies are created, the current Bean is created, and the createBean method is executed . The actual call is doCreateBean.

The code of doCreateBean is relatively long and only the main ones are posted.

   Object exposedObject = bean;
        try {
            填充属性
            populateBean(beanName, mbd, instanceWrapper);
            if (exposedObject != null) {
                初始化,包含BeanPostProcess的前置和后置处理
                exposedObject = initializeBean(beanName, exposedObject, mbd);
            }
        }
protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
	
        // 各种awre的执行
		invokeAwareMethods(beanName, bean);

		if (mbd == null || !mbd.isSynthetic()) {
        // 其他BeanPostProcess对本Bean的前置处理
        wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean,beanName);
		}

		try {
            // 初始化方法执行
			invokeInitMethods(beanName, wrappedBean, mbd);
		}
		catch (Throwable ex) {
			// ...
		}

		if (mbd == null || !mbd.isSynthetic()) {
        // 其他BeanPostProcess对本Bean的后置处理
        wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
		}
		return wrappedBean;
	}

From the initializeBean method, we can know that some Aware, BeanPostProcess, InitMethod and other life cycle methods of the creation process of a bean in spring are reflected in this method. For details, please refer to: https://blog.csdn.net/shuixiou1/article/details/79682954   // various initialization methods in spring chaos

So far, the spring IOC related code and the main interface classes of the spring container have been introduced. You can write some examples yourself and view the breakpoints in conjunction with debug.

 

 

 

 

 

Guess you like

Origin blog.csdn.net/shuixiou1/article/details/113358591