There is a beginning but no end
Experienced the history of java development, from the early writing of native servlet s, self-developed mvc and jdbc tools, and the use of open-source framework struts, hibernate, jsp, spring, springmvc, freemaker, springboot, to the final front and back-end separate development, the first development tool is editplus. Relatively speaking, now the development is very good, and the framework Ecology (only spring ecology has been inherited, and others have become history). By the end of the spring ecosystem, its system is too large, sweeping across countries, and the chance of technology transformation of project products is very small.
At first, I did Spring related development, wrote a lot of xml configuration, and later changed to annotation development. Although I can work, I don't know what its internal principle and design concept are. With the accumulation of time, I need to do sping extension or integration, so I need to study how to realize the source level. I'll start with how to create a Spring Bean. Don't underestimate a Bean. Many code farmers can't explain its creation process.
A brief introduction to Spring framework is an open source J2EE Application framework, by Rod Johnson Initiated, is a lightweight container that manages the bean's life cycle. Spring solves many common problems encountered by developers in J2EE development, and provides powerful IOC AOP And Web MVC. Spring can be used to build applications alone, can also be combined with Struts, Webwork, Tapestry and many other Web frameworks, and can be combined with Swing and other desktop applications AP. Therefore, spring can be applied not only to JEE applications, but also to desktop applications and small applications. The spring framework consists of seven parts: Spring Core, Spring AOP, Spring ORM, Spring DAO, Spring Context, Spring Web and Spring Web MVC.
It's the Beans in the picture. Let's get to the main point. Look carefully. It's very important
Before introducing bean s, let's talk about ioc and context context (it can be understood as a host environment)
ioc is the abbreviation of Inversion of Control, which is called Inversion of Control in the industry. In the early stage of development, we need to create an object by ourselves. But with ioc, we don't need to
I have new objects, and let spring ioc container be responsible for the creation and management of objects. In a word, the function of ioc reverses the dependency of objects, and ioc container manages objects.
Trying to understand bean, ioc and context is very important for learning spring ecology in the future.
There are two types of spring beans: ordinary beans and factory beans, but there are many types of processing
1, Common bean s (take xml configuration for example, more and more people are using annotations now)
Prepare raw materials
Spring bean.xml file (take the demonstration as an example)
<?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.xsd">
<bean id="user" class="spring.model.User">
<property name="id" value="1"/>
<property name="name" value="dongguangming"/>
<property name="age" value="99"/>
</bean>
</beans>
User.java
public class User {
private int id;
private String name;
private int age;
//set,get omitted
}
Test class
/**
*
* @author dgm
* @describe "xml bean"
* @date 2020 April 16, 2016
*/
public class XMLConfigurationBeanApp {
public static void main(String[] args) {
/*DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
reader.loadBeanDefinitions("conf/spring-bean.xml");*/
ApplicationContext applicationContext =
new ClassPathXmlApplicationContext("conf/spring-bean.xml");
User user1 = applicationContext.getBean("user", User.class);
User user2 = (User) applicationContext.getBean("user");
System.out.println(user1);
System.out.println(user2);
System.out.println(user1==user2);
//Because it is a common bean, there is no need to write this in case of exception. I test two different types of beans
System.out.println(applicationContext.getBean("&user"));
}
}
Output results
Parse the initialization process from this line of code
ApplicationContext applicationContext =
new ClassPathXmlApplicationContext("spring-bean.xml");
Speaking, let's see how much spring has done
Three stages: bean parsing, bean instantiation, bean initialization and destruction
1. bean resolution definition registration stage
Early developers all know that configuration files are mostly xml files (now people like annotation parsing). They need to parse the contents of xml files into java corresponding classes, or dom parsing for short, such as
spring is the same. At the beginning, a lot of xml file parsing work was carried out, and the class mapping corresponding to java is good
File path org.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException
/**
* Actually load bean definitions from the specified XML file.
* @param inputSource the SAX InputSource to read from
* @param resource the resource descriptor for the XML file
* @return the number of bean definitions found
* @throws BeanDefinitionStoreException in case of loading or parsing errors
* @see #doLoadDocument
* @see #registerBeanDefinitions
*/
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
try {
//xml document parsing
Document doc = doLoadDocument(inputSource, resource);
//Call register bean definition
return registerBeanDefinitions(doc, resource);
}
}
//File path org.springframework.beans.factory.xml.XmlBeanDefinitionReader.registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
int countBefore = getRegistry().getBeanDefinitionCount();
//Call bean registration
documentReader.registerBeanDefinitions(doc,
createReaderContext(resource));
return getRegistry().getBeanDefinitionCount() - countBefore;
}
. . . . . . A lot of nesting
//File path org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate)
/**
* Process the given bean element, parsing the bean definition
* and registering it with the registry.
*/
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
// Register the final decorated instance.
//Call registration tool registration
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error("Failed to register bean definition with name '" +
bdHolder.getBeanName() + "'", ele, ex);
}
// Send registration event.
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
//File path org.springframework.beans.factory.support.DefaultListableBeanFactory.registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException
@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {
Assert.hasText(beanName, "Bean name must not be empty");
Assert.notNull(beanDefinition, "BeanDefinition must not be null");
if (beanDefinition instanceof AbstractBeanDefinition) {
try {
((AbstractBeanDefinition) beanDefinition).validate();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Validation of bean definition failed", ex);
}
}
BeanDefinition oldBeanDefinition;
oldBeanDefinition = this.beanDefinitionMap.get(beanName);
if (oldBeanDefinition != null) {
if (!isAllowBeanDefinitionOverriding()) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
"': There is already [" + oldBeanDefinition + "] bound.");
}
else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) {
// e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
if (this.logger.isWarnEnabled()) {
this.logger.warn("Overriding user-defined bean definition for bean '" + beanName +
"' with a framework-generated bean definition: replacing [" +
oldBeanDefinition + "] with [" + beanDefinition + "]");
}
}
else if (!beanDefinition.equals(oldBeanDefinition)) {
if (this.logger.isInfoEnabled()) {
this.logger.info("Overriding bean definition for bean '" + beanName +
"' with a different definition: replacing [" + oldBeanDefinition +
"] with [" + beanDefinition + "]");
}
}
else {
if (this.logger.isDebugEnabled()) {
this.logger.debug("Overriding bean definition for bean '" + beanName +
"' with an equivalent definition: replacing [" + oldBeanDefinition +
"] with [" + beanDefinition + "]");
}
}
//Finally, the measurement is successful, a data structure
this.beanDefinitionMap.put(beanName, beanDefinition);
}
else {
if (hasBeanCreationStarted()) {
// Cannot modify startup-time collection elements anymore (for stable iteration)
synchronized (this.beanDefinitionMap) {
//Ditto
this.beanDefinitionMap.put(beanName, beanDefinition);
List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
updatedDefinitions.addAll(this.beanDefinitionNames);
updatedDefinitions.add(beanName);
this.beanDefinitionNames = updatedDefinitions;
if (this.manualSingletonNames.contains(beanName)) {
Set<String> updatedSingletons = new LinkedHashSet<>(this.manualSingletonNames);
updatedSingletons.remove(beanName);
this.manualSingletonNames = updatedSingletons;
}
}
}
else {
// Still in startup registration phase
this.beanDefinitionMap.put(beanName, beanDefinition);
this.beanDefinitionNames.add(beanName);
this.manualSingletonNames.remove(beanName);
}
this.frozenBeanDefinitionNames = null;
}
if (oldBeanDefinition != null || containsSingleton(beanName)) {
resetBeanDefinition(beanName);
}
}
This is just a bean definition (there are many bean definitions registered during the development process). It is very important to do so much work to assemble this data structure: this.beanDefinitionMap.put(beanName, beanDefinition); it is defined as follows:
/** Map of bean definition objects, keyed by bean name */
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
Part of the attributes of the beanDefinition, of course, is a structure for assembling data
2. Bean instantiation and initialization phase
When called
ClassPathXmlApplicationContext(AbstractApplicationContext).finishBeanFactoryInitialization(ConfigurableListableBeanFactory) line: 861
{
//Partial code
// 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(new StringValueResolver() {
@Override
public String resolveStringValue(String strVal) {
return getEnvironment().resolvePlaceholders(strVal);
}
});
}
// Instantiate all remaining (non-lazy-init) singletons.
//There are so many things in it
beanFactory.preInstantiateSingletons();
}
preInstantiateSingletons core code:
@Override
public void preInstantiateSingletons() throws BeansException {
// Iterate over a copy to allow for init methods which in turn register new bean definitions.
// While this may not be part of the regular factory bootstrap, it does otherwise work fine.
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
// Trigger initialization of all non-lazy singleton beans...
for (String beanName : beanNames) {
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
if (isFactoryBean(beanName)) {
//Factory beans (there are many in the system, but you can also write them yourself), implement FactoryBean interface or inherit AbstractFactoryBean
final FactoryBean<?> factory = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName);
boolean isEagerInit;
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
isEagerInit = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
@Override
public Boolean run() {
return ((SmartFactoryBean<?>) factory).isEagerInit();
}
}, getAccessControlContext());
}
else {
isEagerInit = (factory instanceof SmartFactoryBean &&
((SmartFactoryBean<?>) factory).isEagerInit());
}
if (isEagerInit) {
getBean(beanName);
}
}
else {
//Ordinary bean, human implemented, does not implement FactoryBean interface or does not inherit AbstractFactoryBean
getBean(beanName);
}
}
}
// Trigger post-initialization callback for all applicable beans...
for (String beanName : beanNames) {
Object singletonInstance = getSingleton(beanName);
if (singletonInstance instanceof SmartInitializingSingleton) {
final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
if (System.getSecurityManager() != null) {
AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override
public Object run() {
smartSingleton.afterSingletonsInstantiated();
return null;
}
}, getAccessControlContext());
}
else {
smartSingleton.afterSingletonsInstantiated();
}
}
}
}
0: DefaultListableBeanFactory(AbstractBeanFactory).getBean(String)
1 DefaultListableBeanFactory(AbstractBeanFactory).doGetBean(String, Class<T>, Object[], boolean) line: 303
2. Defaultlistablebeanfactory (defaultsingletonbeanregistry). getSingleton (string) line: 231, first getSingleton
3 Object org.springframework.beans.factory.support.AbstractBeanFactory.createBean(String beanName, RootBeanDefinition mbd, Object[] args)
To split:
4. org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd)
Determine whether there is an instantiaawarebeanpostprocessor, applybeanpostprocessor sbeforeinstance() > postprocessbeforeinstance(),
applyBeanPostProcessorsAfterInitialization()>postProcessAfterInitialization().
The chance to return the proxy object. Once returned, there is no following. aop proxy can be generated from this
If you return, skip to stage 10
5 org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(String beanName, 4 RootBeanDefinition mbd, Object[] args) is very important
6 org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args). Instantiation is complete. Please continue to see the source code for details. Note that there are more than one instantiation methods: constructor, factory method,
cglid agent
7 org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(beanName, mbd, instanceWrapper), please continue to see the source code for details, the following is the part
if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||
mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
// Add property values based on autowire by name if applicable.
if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {
autowireByName(beanName, mbd, bw, newPvs);
}
// Add property values based on autowire by type if applicable.
if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
autowireByType(beanName, mbd, bw, newPvs);
}
pvs = newPvs;
}
8 org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(String beanName, Object bean, RootBeanDefinition mbd) , initialization complete
protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override
public Object run() {
invokeAwareMethods(beanName, bean);
return null;
}
}, getAccessControlContext());
}
else {
//Implement the call of the suffix Aware interface at this stage
//BeanNameAware
//BeanClassLoaderAware
//BeanFactoryAware
invokeAwareMethods(beanName, bean);
}
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
//Implement the BeanPostProcessor interface
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
//Call the initialization method to determine whether the InitializingBean is implemented. The method name is afterpropertieset(), and the custom initialization method is also here
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
if (mbd == null || !mbd.isSynthetic()) {
//Implement the BeanPostProcessor interface
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
10 org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(String beanName, ObjectFactory The second getSingleton, but the implementation method is different
org.springframework.beans.factory.support.DefaultSingletonBeanRegistry
/** Cache of singleton objects: bean name --> bean instance */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
/** Cache of singleton factories: bean name --> ObjectFactory */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
/** Cache of early singleton objects: bean name --> bean instance */
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
/** Set of registered singletons, containing the bean names in registration order */
private final Set<String> registeredSingletons = new LinkedHashSet<>(256);
Note that the space is limited: some core methods are listed, in fact, there are many, because the code is too much, it will not be pasted
Factory bean
The Bean implements the FactoryBean interface
public class UserFactoryBean<User> implements FactoryBean<User> {
private User user;
/**
* @return the user
*/
public User getUser() {
return user;
}
/**
* @param user the user to set
*/
public void setUser(User user) {
this.user = user;
}
/* (non-Javadoc)
* @see org.springframework.beans.factory.FactoryBean#getObjectType()
*/
@Override
public Class<?> getObjectType() {
return user.getClass();
}
/* (non-Javadoc)
* @see org.springframework.beans.factory.FactoryBean#getObject()
*/
@Override
public User getObject() throws Exception {
// TODO Auto-generated method stub
return user;
}
}
It does not implement the FactoryBean interface in the same way as the previous one. Generally speaking, it is the same. No more details will be given
/**
* Obtain an object to expose from the given FactoryBean.
* @param factory the FactoryBean instance
* @param beanName the name of the bean
* @param shouldPostProcess whether the bean is subject to post-processing
* @return the object obtained from the FactoryBean
* @throws BeanCreationException if FactoryBean object creation failed
* @see org.springframework.beans.factory.FactoryBean#getObject()
*/
protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
if (factory.isSingleton() && containsSingleton(beanName)) {
synchronized (getSingletonMutex()) {
Object object = this.factoryBeanObjectCache.get(beanName);
if (object == null) {
object = doGetObjectFromFactoryBean(factory, beanName);
// Only post-process and store if not put there already during getObject() call above
// (e.g. because of circular reference processing triggered by custom getBean calls)
Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
if (alreadyThere != null) {
object = alreadyThere;
}
else {
if (object != null && shouldPostProcess) {
try {
object = postProcessObjectFromFactoryBean(object, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName,
"Post-processing of FactoryBean's singleton object failed", ex);
}
}
this.factoryBeanObjectCache.put(beanName, (object != null ? object : NULL_OBJECT));
}
}
return (object != NULL_OBJECT ? object : null);
}
}
else {
Object object = doGetObjectFromFactoryBean(factory, beanName);
if (object != null && shouldPostProcess) {
try {
object = postProcessObjectFromFactoryBean(object, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
}
}
return object;
}
}
Sequence diagram:
3. bean destruction
Three manifestations:
3.1 the DisposableBean interface corresponding to InitializingBean,
3.2 custom method, destroy method = "destroyxml"
3.3 @ PreDestroy corresponding to @ PostConstruct
Destruction sequence is as shown in the figure
The code doesn't give an example.
Summary: in fact, you can use new user (6, "dongguangming", 99), but it has nothing to do with spring. Spring is very powerful. There are opportunities to transform the process of participating bean s in all stages, and the degree of composition is also very high
Remember that spring beans: resolve, register, instantiate, initialize and destroy to develop or integrate third-party components (such as mybatis, dubbo, email, zk, redis, etc.) into the spring ecosystem
reference resources:
0 Introduction to spring framework https://www.ibm.com/developerworks/cn/java/wa-spring1/
1. What is spring bean https://www.awaimai.com/2596.html
2 what-in-the-world-are-spring-beans https://stackoverflow.com/questions/17193365/what-in-the-world-are-spring-beans
2. Spring Bean Lifecycle https://www.benchresources.net/spring-bean-lifecycle/
3. Detailed tutorial on Redis caching in the SpringBoot series https://laptrinhx.com/detailed-tutorial-on-redis-caching-in-the-springboot-series-3352915639/
4. Spring Bean creation process http://www.programmersought.com/article/55942589567/
5. Inversion of Control Containers and the Dependency Injection pattern https://martinfowler.com/articles/injection.html