1 What is Spring IOC

1.1 What is Spring IOC

IOC is used to create and manage instance objects for users. Users who need instance objects can simply fetch them from the IOC container instead of creating them themselves, thus decoupled from the concrete classes.

To put it simply, Spring IOC is a Map collection. The name of the object is the key in the collection and the value is the corresponding object. We can get an object from the collection by its name.

1.2 IOC implementation process

  1. Bean definition

Spring provides several ways to configure Bean definitions, from Xml to JavaConfig

Xml:

<bean id="user" class="com.ranger.bean.User">
    <constructor-arg type="String" value="ranger"></constructor-arg>
    <constructor-arg ref="cbean"></constructor-arg>
</bean>
<bean id="car" class="com.ranger.bean.Car">
    <constructor-arg type="String" value="mazda"></constructor-arg>
</bean>
Copy the code

JavaConfig method, this way with annotations

@Configuration
public class AppConfig {

    @Bean
    public Service myService(a) {
        return newServiceImpl(); }}Copy the code
  1. Spring reads the definition of the Bean

Specify a configuration file (XML) when creating the SpringIOC container, or specify a path for package scanning (JavaConfig)

// By specifying the configuration file under classpath
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("springcontext.xml");

Copy the code

Or use JavaConfig

AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext();
annotationConfigApplicationContext.register(AppConfig.class);

annotationConfigApplicationContext.refresh();
System.out.println(annotationConfigApplicationContext.getBean(User.class));

Copy the code

2. Start with the entry ApplicationContext

This section Outlines the responsibilities of each parent interface

  • EnvironmentCapable: Gets parameters related to environment variables
  • HierarchicalBeanFactory: Provides parent and child container functions
  • ListableBeanFactory: the BeanFactory implementation
  • ApplicationEventPublisher: Event release
  • ResourcePatternResolver: Loads the Resource file
  • MessageSource: Provides the internationalization function

Methods defined in ApplicationContext

ApplicationContext defines several methods of its own. Here is a brief introduction to these methods:

  • getApplicationName: Returns the name of the application to which the container belongs, an empty string by default
  • getAutowireCapableBeanFactory: show the current container AutowireCapableBeanFactory
  • getDisplayName: Returns a friendly container name
  • getId: Returns the unique Id of the current container
  • getParant: returns the parent container, or null if there is none
  • getStartupDate: Returns the timestamp when the container was first loaded

2.1 Subclasses of Application

2.1.1 AbstarctApplicationContext subclass

Let’s start with the descendants after ApplicationContext

Can be seen from the class diagram above, behind AbastractApplicationContext has two sons, is GernericApplicationContext and AbstractRefreshableApplicationContext respectively. Both sons hold BeanFactory instances, and all of their BeanDefiniton registrations and Bean instantiations are based on this BeanFactory instance

They are divided into two main factions:

  • AbstractRefreshableApplicationContext: this class in every time call the refresh method produces a new the beanfactory instance (usually, but not a must). The application context loads the BeanDefinition through a series of configuration files. Internally held BeanFacoty instances are created when the refresh method is called (see the refreshBeanFactory method in this class)

  • GenericApplicationContext: this class internal hold only a DefaultListableBeanFactory instance, and compared with other ApplicationContext implementation class, The class is created with an instance of the BeanFactory, meaning that the internally held BeanFactory instance is created before the Refresh method is called, and the class is a BeanFacoty instance from start to end.

GenericApplicationContext implements BeanDefinitionRegistry this interface, this interface is stem what of, the name is BeanDefinition registered what east east, yes, this is used to add or remove BeanDefiniton. GenericApplicationContext also has a few son, behind will simple analysis about their differences.

2.1.2 AbstractApplicationContext abstract class simple instructions

The above mentioned the refresh method, this method is AbastractApplicationContext, used to configure the Context. This class uses the template method pattern, leaving many methods to subclasses to implement.

In AbstractApplicationContext, implements the most ApplicationContext interface inherited from BeanFactroy interface methods.

We can also see that the parent class is ConfigurableApplicationContext AbstractApplicationContext, this class provides a configuration method of the Context also provides life cycle method.

3 BeanDefinition loading

From the above analysis, we can see that although there is a common ancestor called ApplicationContext, different descendants have different methods for loading beanDefinitions, but otherwise the same. SpringIOC one of the most important methods in their common dad AbstractApplicationContext refresh. The refresh method creates Bean objects based on BeanDefinition (except for lazy loading)

Let’s start from our common ClasspathXmlApplicationContext analysis:

Now that the project contains the classes and configurations shown in the figure above, we write a main method:

public class Application {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("springcontext.xml"); Person person = applicationContext.getBean(Person.class); System.out.println(person); }}Copy the code

springcontext.xml

<?xml version="1.0" encoding="UTF-8"? >
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="Http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"
       default-lazy-init="true" default-init-method="" default-destroy-method="">

    <bean id="car" class="com.ranger.spring.ioc.bean.Car">
        <constructor-arg name="brand" value="mazda"></constructor-arg>
    </bean>

    <bean id="person" class="com.ranger.spring.ioc.bean.Person">
        <property name="car" ref="car"></property>
    </bean>
</beans>

Copy the code

Debugging starts the main method of the Application class

Because eventually BeanDefinition registration is done in the middle of DefaultListableBeanFactory, So at the registerBeanDefinition(String beanName, BeanDefinition BeanDefinition) interrupt point you can see the call stack below

Look up from the bottom of the thread call stack.

Get a basic flow:

It’s a little bit more complicated here to parse the Document to get a BeanDefinition, so if you’re interested, you can check it out.

So GenericXmlApplicationContext loading BeanDefinition process is also same as above.

You can see that the flow is the same.

But first GenericXmlApplicationContext will call the load to load the BeanDefinition, then call the refresh to complete configuration.

The ClasspathXmlApplicationContext will be done when the refresh method invocation BeanDefinition loading.

4 – DefaultListableBeanFactory bean factory

Through the previous analysis we can see that most of the operations are based on DefaultListableBeanFactory ApplicationContext.

Is the BeanFactory DefaultListableBeanFactory an implementation class

Now let’s get to know it:

  1. Let’s start with the ancestor at the topBeanFactory

By reading the source doc,

  • This interface is the root interface of the Spring Bean container and has subinterfaces ListableBeanFactory and ConfigurableBeanFactory for specific functionality

  • The object implementing this interface holds a series of bean Definitions, each of which has a unique string name. The returned Bean can be singleton or standalone (created each time), depending on the configuration of the ApplicationContext.

  • The BeanFactory performs configuration through dependency injection, usually by using setters or constructor

  • Typically, beanDefinitions loaded by the BeanFactory are stored in a configuration resource, such as an XML file. But there are no restrictions on where to store it, such as LDAP,XML,properties, etc.

  • HierarchicalBeanFactory is sought from this context first, not from the parent BeanFactory, and beans in this factory instance override the parent factory

  • The BeanFactory implementation classes should be as backing bean lifecycle methods, such as BeanNameAware BeanClassLoaderAware, and so on.

    To support these lifecycle methods, BeanFacoty does not provide an abstract interface; the implementation class needs to implement it itself

BeanFactory source code:

public interface BeanFactory {

    // Used to distinguish a FactoryBean from the objects it produces
	String FACTORY_BEAN_PREFIX = "&";

	// Get the Bean from BeanName
	Object getBean(String name) throws BeansException;

	// Get the bean by beanName and its Class type
	<T> T getBean(String name, @Nullable Class<T> requiredType) throws BeansException;

	// Add the parameters to get the bean
	Object getBean(String name, Object... args) throws BeansException;

	// By type
	<T> T getBean(Class<T> requiredType) throws BeansException;

	// Same as above
	<T> T getBean(Class<T> requiredType, Object... args) throws BeansException;

	// Determine whether a Bean is included
	boolean containsBean(String name);

	// Whether the bean is a singleton
	boolean isSingleton(String name) throws NoSuchBeanDefinitionException;

	// Whether the bean is prototype
	boolean isPrototype(String name) throws NoSuchBeanDefinitionException;

	// Query whether the Class type of the named Bean matches the specified type
	boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;

	/ / same as above
	boolean isTypeMatch(String name, @Nullable Class
        typeToMatch) throws NoSuchBeanDefinitionException;

	// Get the Class type of the bean with the specified name
	@NullableClass<? > getType(String name)throws NoSuchBeanDefinitionException;

    // Get the alias of the bean
	String[] getAliases(String name);

}
Copy the code

BeanFactory has three subclass interfaces: ListableBeanFactory, HierarchicalBeanFactory and AutowireCapableBeanFactory, and an implementation class SimpleJndiBeanFactory.

Here for BeanFactory system introduction will not say, too many, write separately.

5 afterword.

ApplicationContext’s architecture is large and captures the core of several important classes: AbstractApplicationContext, as well as its two eldest son GenericApplicationContext and AbstractRefreshableApplicationContext. Most of the functionality is done here.

The two oldest sons had sons based on them.

Reading the code, you can see that many of the methods of ApplicationContext are left to subclasses to implement, using the template method design pattern.

For registered BeanDefinition and ultimately based on BeanDefinition create bean instance is attributed to the DefaultListableBeanFactory.

After looking at the architecture of the Spring container in general, WE’ll look at bean creation.