Container startup process

Spring’s official science diagram for container startup:



The Spring Container
Fully configured system

The following diagram shows the stages of container startup:

The related interfaces and classes mentioned are shown below:

The BeanDefinitionRegistry in the above class diagram depends on BeanDefinition, and the rest are implementation relationships.

BeanFactoryPostProcessor Container Extension mechanism (after Phase 1)

This mechanism allows us to modify the information held by the BeanDefinition registered with the container before the container instantiates the corresponding object. That is, a process is added at the end of the first phase of the capacitor implementation.

BeanFactoryPostProcessor registration mode

BeanFactory hardcoded register BeanFactoryPostProcessor:

// Declare the BeanFactory instance to be postprocessed
ConfigurableListableBeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("..."));
// Declare the BeanFactoryPostProcessor to use
PropertyPlaceholderConfigurer propertyPostProcessor = new PropertyPlaceholderConfigurer();
propertyPostProcessor.setLocation(new ClassPathResource("..."));
// Perform post-processing operations
propertyPostProcessor.postProcessBeanFactory(beanFactory);
Copy the code

The ApplicationContext configuration file registers BeanFactoryPostProcessor:

    <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="locations">
            <list>
                <value>conf/jdbc.properties</value>
                <value>conf/mail.properties</value>
            </list>
        </property>
    </bean>
Copy the code

Description of common implementation classes

1. PropertyPlaceholderConfigurer

Separate the XML configuration file from the concrete parameter property and use placeholders in the XML to match the concrete parameter in the properties file, as follows:

//XML data source configuration<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
        <property name="url">
            <value>${jdbc.url}</value>
        </property>
        <property name="driverClassName">
            <value>${jdbc.driver}</value>
        </property>
        <property name="username">
            <value>${jdbc.username}</value>
        </property>
        <property name="password">
            <value>${jdbc.password}</value>
        </property>
    </bean>
Copy the code
Jdbc. url= JDBC :mysql://server/MAIN? useUnicode=true&characterEncoding=ms932&failOverReadOnly=false&roundRobinLoadBalance=true jdbc.driver=com.mysql.jdbc.Driver jdbc.username=your username=your password jdbc.passwordCopy the code

Accomplished also will check the Java System Properties in class, Can pass setSystemPropertiesMode () or setSystemPropertiesModeName () to control whether load or cover the System Properties of the corresponding behavior. It offers three modes:

public class PropertyPlaceholderConfigurer extends PlaceholderConfigurerSupport {
    // Do not use the System Properties configuration item
    public static final int SYSTEM_PROPERTIES_MODE_NEVER = 0;
    // Default mode. If the corresponding parameter (configuration item) cannot be found in properties, go to System Properties.
    public static final int SYSTEM_PROPERTIES_MODE_FALLBACK = 1;
    // The System Properties configuration item is preferred
    public static final int SYSTEM_PROPERTIES_MODE_OVERRIDE = 2;
    }
Copy the code

2. PropertyOverrideConfigurer

Can pass PropertyOverrideConfigurer configured in the container any property you want to handle the bean definition information (no need to use the placeholder) to overlay.

For example, for the XML data source configuration above, do the following:

Registered PropertyOverrideConfigurer:

    <bean class="org.springframework.beans.factory.config.PropertyOverrideConfigurer">
        <property name="location" value="pool-adjustment.properties"/>
    </bean>
Copy the code

The pool – adjustment. The properties content:

# Key parameter value pair format: beanname.propertyName =value
dataSource.minEvictableIdleTimeMillis=1000
dataSource.maxActive=50
Copy the code

The parameters of the dataSource can be replaced.

PropertyOverrideConfigurer not used for setting parameters is still using the parameters in the bean definition; If multiple parameters are used to set the same property value, the last parameter prevails

3. CustomEditorConfigurer

Beans defined through XML and their properties need to be converted from strings to objects of various types. This is done by JavaBean PropertyEditor (Spring also provides its own implementation of some PropertyEditor, Mostly located in the org. Springframework. Beans. Propertyeditors).

Part of thePropertyEditor(Container loaded by default) :

  • StringArrayPropertyEditor: will meetCSVFormat the string intoString[]It is in the form of an array. By default, it is a comma (,) delimited string.
  • ClassEditor: according to theStringThe type ofclassName, which is directly converted to the correspondingClassObject.
  • Corresponding FileEditor:java.io.FileThe type ofPropertyEditor, responsible for resource positioning.
  • LocaleEditor:java.util.LocaleThe type ofPropertyEditor.
  • PatternEditor: Introduced after Java SE 1.4java.util.regex.PatternthePropertyEditor.
The customPropertyEditor:

Two ways:

  • Direct implementationjava.beans.PropertyEditor
  • inheritancejava.beans.PropertyEditorSupport, just need to implementsetAsText(String)Methods.

The following is an implementation of PropertyEditorSupport for custom date formats:

public class DatePropertyEditor extends PropertyEditorSupport {
    private String datePattern;

    @Override
    public void setAsText(String text) throws IllegalArgumentException {
        DateTimeFormatter dateTimeFormatter = DateTimeFormat.forPattern(getDatePattern());
        Date dateValue = dateTimeFormatter.parseDateTime(text).toDate();
        setValue(dateValue);
    }

    public String getDatePattern(a) {
        return datePattern;
    }

    public void setDatePattern(String datePattern) {
        this.datePattern = datePattern;
    }
    
    public DatePropertyEditor(String datePattern){
        this.datePattern = datePattern; }}Copy the code
throughCustomEditorConfigurerRegister customPropertyEditor
  • A container forBeanFactoryWhen hard-coded registration:
XmlBeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("..."));
CustomEditorConfigurer ceConfigurer = new CustomEditorConfigurer();

Map customerEditors = new HashMap();
customerEditors.put(java.util.Date.class, new DatePropertyEditor("yyyy/MM/dd"));
ceConfigurer.setCustomEditors(customerEditors);

ceConfigurer.postProcessBeanFactory(beanFactory);
Copy the code
  • A container forApplicationContext, asbeanRegistration:
    <bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">// use customEditors before Spring2.0<property name="customEditors">
            <map>
                <entry key="java.util.Date">
                    <ref bean="datePropertyEditor"/>
                </entry>
            </map>
        </property>
    </bean>
    
    <bean id="datePropertyEditor" class="... DatePropertyEditor">
        <property name="datePattern">
            <value>yyyy/MM/dd</value>
        </property>
    </bean>
Copy the code

Spring2.0 advocates using the propertyEditorRegistrars property to specify custom PropertyEditor:

Additional implementation of PropertyEditorRegistrar:

public class DatePropertyEditorRegistrar implements PropertyEditorRegistrar {
    private PropertyEditor propertyEditor;

    public void registerCustomEditors(PropertyEditorRegistry peRegistry) {
        peRegistry.registerCustomEditor(java.util.Date.class, getPropertyEditor());
    }

    public PropertyEditor getPropertyEditor(a) {
        return propertyEditor;
    }

    public void setPropertyEditor(PropertyEditor propertyEditor) {
        this.propertyEditor = propertyEditor; }}Copy the code

The bean is registered:

    <bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
        <property name="propertyEditorRegistrars">// Multiple PropertyEditorRegistrar can be specified via list<list>
                <ref bean="datePropertyEditorRegistrar"/>
            </list>
        </property>
    </bean>// DatePropertyEditor is advocated after Spring2.0<bean id="datePropertyEditorRegistrar" class="... DatePropertyEditorRegistrar">
        <property name="propertyEditor">
            <ref bean="datePropertyEditor"/>
        </property>
    </bean>
    <bean id="datePropertyEditor" class="... DatePropertyEditor">
        <property name="datePattern">
            <value>yyyy/MM/dd</value>
        </property>
    </bean>
Copy the code

BeanFactoryPostProcessor

BeanFactoryPostProcessor

Bean life cycle (Phase 2)

It is possible to trigger the Bean instantiation phase when a requester requests an object instance through the BeanFactory getBean() method.

  • The client object is called explicitly
  • Implicit calls inside containers
    • For BeanFactory, object instantiation is lazily initialized by default. When an object A is initialized, its dependent object B is implicitly initialized.
    • ApplicationContext starts and instantiates all bean definitions. When an object A is initialized, its dependent object B is implicitly initialized.

Bean instantiation process:

Org. Springframework. Beans. Factory. Support. AbstractBeanFactory view the getBean (); Org. Springframework. Beans. Factory. Support. AbstractAutowireCapableBeanFactory view createBean ();

General logic of getBean() :

Bean instantiation with BeanWrapper

The corresponding bean instance can be initialized or subclassed dynamically through reflection or CGLIB dynamic bytecode generation.

Spring default CglibSubclassingInstantiationStrategy bean production was BeanWrapperImpl packaging of the target class.

InstantiationStrategy class diagram:

BeanWrapper and his dads:

Various Aware interfaces

When the object is instantiated and the associated properties and dependencies are set, the Spring container checks whether the current object instance implements a set of interface definitions ending in the Aware name. If so, the dependencies specified in these Aware interface definitions are injected into the current object instance.

BeanFactory corresponds to Aware:

ApplicationContext
Aware

BeanPostProcessor

The BeanPostProcessor exists in the object instantiation phase.

The interface is defined as follows:

package org.springframework.beans.factory.config;
public interface BeanPostProcessor {

    // execute before instantiation
	@Nullable
	default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}
	// execute after instantiation
	@Nullable
	default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		returnbean; }}Copy the code

ApplicationContextAwareProcessor, for example, is to test the ApplicationContext corresponding Aware execution BeanPostProcessor corresponding operation implementation class, Its postProcessBeforeInitialization method is as follows:

	public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException {
		AccessControlContext acc = null;

        // Check whether this bean implements one or more of the following Aware
		if(System.getSecurityManager() ! =null &&
				(bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
						bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
						bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)) {
			// Get the AccessControlContext of the current applicationContext
			acc = this.applicationContext.getBeanFactory().getAccessControlContext();
		}

		if(acc ! =null) {
			AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
				invokeAwareInterfaces(bean);
				return null;
			}, acc);
		}
		else {
			invokeAwareInterfaces(bean);
		}

		return bean;
	}
Copy the code

Custom BeanPostProcessor

  1. Annotate the implementation classes that need to be processed (can define and implement the markup interface (Aware))
  2. Implement correspondingBeanPostProcessorProcess the Bean instances that meet the criteria
  3. Will be customBeanPostProcessorRegister with the container as follows:
  • For containers of type BeanFactory, hard coding is used
ConfigurableBeanFactory beanFactory = new XmlBeanFactory(newClassPathResource(...) ); beanFactory.addBeanPostProcessor(new CustomPostProcessor());
Copy the code
  • For the ApplicationContext container, XML registration is direct
<beans>
    <bean id="customPostProcessor" class="package.name.CustomPostProcessor">
    <! Inject the necessary dependencies if necessary
    </bean>.</beans>
Copy the code

InitializingBean and init – method

Org. Springframework. Beans. Factory. InitializingBean is one of the widely used inside the container object lifecycle interface, for after the BeanPostProcessor pre-processing performed further editing interface to implement the bean, as follows:

public interface InitializingBean {

	/**
	 * Invoked by the containing {@code BeanFactory} after it has set all bean properties
	 * and satisfied {@link BeanFactoryAware}, {@code ApplicationContextAware} etc.
	 * <p>This method allows the bean instance to perform validation of its overall
	 * configuration and final initialization when all bean properties have been set.
	 * @throws Exception in the event of misconfiguration (such as failure to set an
	 * essential property) or if initialization fails for any other reason
	 */
	void afterPropertiesSet(a) throws Exception;

}
Copy the code

In real development, the init-method property of

is used instead. Typically used to integrate third-party libraries.

DisposableBean and destroy – method

Corresponding to InitializingBean and init-Method, used to perform singleton type object destruction operations.

Register a Callback for object destruction for this instance to execute the destruction logic before these singleton-type object instances are destroyed.

For example, the Spring registered database connection pool:

    <! BasicDataSource ();
    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
          destroy-method="close">
        <property name="url">
            <value>${jdbc.url}</value>
        </property>
        <property name="driverClassName">
            <value>${jdbc.driver}</value>
        </property>
        <property name="username">
            <value>${jdbc.username}</value>
        </property>
        <property name="password">
            <value>${jdbc.password}</value>
        </property>.</bean>
Copy the code

For the BeanFactory: The destroySingletons() method of the ConfigurableBeanFactory (which handles all classes that implement the DisposableBean interface and register the Destroy-Method method) should be called at program exit or other business scenarios to destroy all container-managed Sing An object instance of type Leton.

/** * BeanFactory destroys the singleton instance method call. * /
public class ApplicationLauncher {
    public static void main(String[] args) {
        BasicConfigurator.configure();
        BeanFactory container = new XmlBeanFactory(new ClassPathResource("..."));
        BusinessObject bean = (BusinessObject) container.getBean("...");
        bean.doSth();
        ((ConfigurableListableBeanFactory) container).destroySingletons();
        // The application exits and the container closes}}Copy the code

The ApplicationContext: AbstractApplicationContext provides us with registerShutdownHook () method, the method using standard at the bottom of the Runtime class of addShutdownHook () method to invoke the corresponding bean object destruction of logic.

/** * Use the registerShutdownHook() method to register and trigger the object destruction logic callback behavior */
public class ApplicationLauncher {
    public static void main(String[] args) {
        BasicConfigurator.configure();
        BeanFactory container = new ClassPathXmlApplicationContext("...");
        ((AbstractApplicationContext) container).registerShutdownHook();
        BusinessObject bean = (BusinessObject) container.getBean("...");
        bean.doSth();
        // The application exits and the container closes}}Copy the code