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 into
String[]
It is in the form of an array. By default, it is a comma (,) delimited string. - ClassEditor: according to the
String
The type ofclass
Name, which is directly converted to the correspondingClass
Object. - Corresponding FileEditor:
java.io.File
The type ofPropertyEditor
, responsible for resource positioning. - LocaleEditor:
java.util.Locale
The type ofPropertyEditor
. - PatternEditor: Introduced after Java SE 1.4
java.util.regex.Pattern
thePropertyEditor
.
The customPropertyEditor
:
Two ways:
- Direct implementation
java.beans.PropertyEditor
- inheritance
java.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
throughCustomEditorConfigurer
Register customPropertyEditor
- A container for
BeanFactory
When 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 for
ApplicationContext
, asbean
Registration:
<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
- Annotate the implementation classes that need to be processed (can define and implement the markup interface (Aware))
- Implement corresponding
BeanPostProcessor
Process the Bean instances that meet the criteria - Will be custom
BeanPostProcessor
Register 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