In the Java class, a great man named Rod Johnson found that the initial java enterprise-level development was in a chaotic state.
So it decided to write a general infrastructure that could solve problems.
Because it firmly believes that interface-oriented programming can minimize changes, but also facilitate expansion and change. So, it wrote the following interface.
The first thing to create in a chaotic state is the mother of all objects, the BeanFactory, and with it, you can obtain all the objects and attributes it nurturing, that is, first of all, Gaia - the Mother of the Earth.
With the original mother BeanFactory, Johnson thought, what if I wanted to get a set of Bean objects instead of just one or several? In addition, what if the mother's child also wants to give birth to a partner? Therefore, johnson created ListableBeanFactory to operate a set of bean objects. For example, getBeansOfType can obtain a set of beans of the same type based on it; created HierarchicalBeanFactory to solve the hierarchical problems of multiple BeanFactory, such as getParentBeanFactory can obtain the parent Factory of the BeanFactory.
This BeanFactory is ultimately used on an application, so the BeanFactory needs to be given the ability to move in an application. In BeanFactory, you only need to consider behaviors related to beans, such as how to get beans, type of beans, etc.; and if you want to give them abilities in the application, you need to consider more, such as the application name, startup time, id, etc. behaviors and attributes related to the application itself, so Johnson thought of creating an ApplicationContext. Johnson thought that this ApplicationContext must be able to do many things, and it must be able to handle parameterized and internationalized text information, so it adds the MessageSource interface; it must be able to publish events to decouple components, so it has the ApplicationEventPublisher interface; it must be able to obtain resource files, so it has the ResourcePatternResolver interface; it must be able to have different processing objects in different environments, so it has the EnvironmentCapable interface.
ApplicationContext inherits all these interfaces.
But the most important thing is that both BeanFactory and ApplicationContext need to have configurable capabilities, so there are sub-interfaces ConfigurableBeanFactory and ConfigurableApplicationContext; in addition, the web was a very important trend at that time, and it was a bit unique compared to other applications, so it needed to get ServletContext, so there was WebApplicationContext.
So far, johnson has been abstract thinking about interface behavior and has not implemented them in detail.
Looking at the BeanFactory and ApplicationContext created, Johnson realized that the work of the day was far from over because there was no real solution to how to make the whole system work, so Johnson began to think about how to implement them.
The first thing that johoson thinks about is what capabilities should this implementation have? Of course, we need to include the AutowireCapableBeanFactory, ListableBeanFactory and ConfigurableBeanFactory mentioned earlier. Therefore, the ConfigurableListableBeanFactory was created. Secondly, several abilities for bean objects need to be considered, one is the ability to alias; the second is the ability to save singleton objects; the third is the ability to cache; they are implemented in the SimpleAliasRegistry class, the DefaultSingletonBeanRegistry class and the FactoryBeanRegistrySupport class respectively.
Finally, DefaultListableBeanFactory was created, which is the prototype of all IOC factories in spring and is the first real child of BeanFactory. This child is very important and has become the basis for independent creation of IOC containers. If it is extended and used, most of them are inherited or used in combination.
If you want to initialize a DefaultListableBeanFactory, you can use the following code
ClassPathResource res = new ClassPathResource("applicationContext.xml"); DefaultListableBeanFactory f = new DefaultListableBeanFactory(); XmlBeanDefinitionReader r = new XmlBeanDefinitionReader(f); r.loadBeanDefinitions(res); Next, Johnson thought that BeanFactory has a relatively comprehensive default implementation, so what about ApplicationContext? So johnson tirelessly created three important ApplicationContext implementations: FileSystemXmlApplicationContext, ClassPathXmlApplicationContext, AnnotationConfigWebApplicationContext (in fact, there are many more, such as handling portlets and handling webs)
The first thing Johnson considers is how to do the spring startup process. It should be placed in a relatively abstract level so that all classes in the lower level can be reused. So he implemented the ConfigurableApplicationContext using an AbstractApplicationContext. There is also a very important function, that is, loading a file in the form of a resource, which requires abstracting the resource into a Resource class and abstracting the specific implementation of the positioning resource to the ResourceLoader. AbstractApplicationContext also needs to inherit the DefaultResourceLoader to provide this function. AbstractApplicationContext completed the entire startup process (God arranged it to be completed the next day), but it did not manage BeanFactory. So, its subclass AbstractRefreshableApplicationContext does this specifically, implementing refreshBeanFactory, closeBeanFactory, getBeanFactory specifically manages the life cycle of the BeanFactory, but AbstractRefreshableApplicationContext still does not load all configured beans. Where to load the configured resources, it actually goes to the lower subclass to do it, such as FileSystemXmlApplicationContext, which is to read an xml applicationContext to the file system; ClassPathXmlApplicationContext is to read this applicationContext to the class loading path. AnnotationConfigWebApplicationContext loads beans from the annotation of the class file, and spring scanning starts from now on.
Seeing that the main frame had been established, Johnson fell asleep with satisfaction with a smile.
The first day, Johnson completed a spring overall framework.
On the second day, Johnson was preparing to actually deal with the previous problems. For example, the container initialization process of spring. As shown in the figure, Johnson divides this process into many subprocesses, which are all working around the grand goal of loading beans.
This process is placed in the refresh method in the AbstractApplicationContext. The code is as follows: Johnson divides the refresh process into many subprocesses, and these subprocesses are at the same abstract level. This way of writing is to give future generations a role model.
public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // Prepare this context for refreshing. prepareRefresh(); // Tell the subclass to refresh the internal bean factory. ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // Prepare the bean factory for use in this context. prepareBeanFactory(beanFactory); try { // Allows post-processing of the bean factory in context subclasses. postProcessBeanFactory(beanFactory); // Invoke factory processors registered as beans in the context. invokeBeanFactoryPostProcessors(beanFactory); // Register bean processors that intercept bean creation. registerBeanPostProcessors(beanFactory); // Initialize message source for this context. initMessageSource(); // Initialize event multicaster for this context. initApplicationEventMulticaster(); // Initialize other special beans in specific context subclasses. onRefresh(); // Check for listener beans and register them. registerListeners(); // Instantiate all remaining (non-lazy-init) singletons. finishBeanFactoryInitialization(beanFactory); // Last step: publish corresponding event. finishRefresh(); } catch (BeansException ex) { // Destroy already created singletons to avoid dangling resources. destroyBeans(); // Reset 'active' flag. cancelRefresh(ex); // Propagate exception to caller. throw ex; } } } If you look at it at a higher level, these processes actually revolve around several aspects: 1. Refresh life cycle; 2. Initialization and preparation of beanFactory; 3. Generate and register beanDefinition; 4. BeanFactory postprocessor; 5. Set messages, events and listeners.
1. Refreshing life cycle
prepareRefresh, this process mainly records the log and indicates that spring has started, initializes property resources (such as initializing some resources in serlvet), and verifying property resources (such as only writing key without value).
onRefresh, the purpose is to provide some special ApplicationContexts, so that they can expand during the refresh process. Most of the current usage is to set the theme for the servlet application context
finishRefresh, do some finishing work, such as initializing LifecycleProcessor, publishing event ending for refresh, etc.
cancelRefresh, mainly changes the current state to non-active when an exception occurs.
2. Initialization and preparation of beanFactory
Johnson thought that we should let the beanFactory load and register the bean transparently when initialized, so that my encapsulation is very successful for the outside world, so this step actually does a lot of things. The following figure omits many steps and lists only key points.
AbstractApplicationContext will call refreshBeanFactory. It will first check and close the existing beanFactory, then create a new beanFactory, and then use this factory to load all BeanDefinitions.
Among them, loadBeanDefinitions will be handed over to subclasses for different implementations. For example, AbstractXmlApplicationContext is mainly read through xml; AnnotationConfigWebApplicationContext implementation will call the scanner to scan the beans in the class.
3. Generate and register beanDefinition
After parsing the xml configuration, the parseDefaultElement method of the DefaultBeanDefinitionDocumentReader will perform corresponding processing based on the elements in the xml. Among them, when encountering a bean element, the registerBeanDefinition method in BeanDefinitionReaderUtils will be finally called. The parameter passed in this method is BeanDefinitionRegistry, which actually calls back the registerBeanDefinition method of the DefaultListableBeanFactory to register beanDefinition (DefaultListableBeanFactory implements BeanDefinitionRegistry).
4. beanFactory postprocessor
The beanFactory postprocessor is a way provided by spring to allow its subclasses to be flexible. There are 2 steps in spring: postProcessBeanFactory, invokeBeanFactoryPostProcessors. registerBeanPostProcessors instantiate and call all BeanPostProcessors, which are used to expand the bean before and after bean initialization.
5. Set up messages, events and listeners
Set the default message source to DelegatingMessageSource. If there is already a messageSource in the factory, use this messageSource. The event multicaster is SimpleApplicationEventMulticaster. If there is already an applicationEventMulticaster in the factory, use this applicationEventMulticaster and register all application Listeners to receive events.
MessageSource is an important method for international resource files. Spring supports message sources in applicationContext.
Spring provides the default implementation of MessageSource, using java.util.ResourceBundle to extract messages. Spring can directly access message from ApplicationContext.getMessage() by configuring a bean with a special id as messageSource and setting the file name of i18n. If in jsp, you can also access the message through the spring:message tag.
Event: Events are a relatively important decoupling mechanism. Spring has introduced it in the core ApplicationContext. Its principle is relatively simple. On the one hand, the event generator can send events; on the other hand, it seems that the event listener can respond to events. The specific implementation basically holds an event listener collection in the generator and "register" (that is, join) all listeners to this event listener collection.
In spring, ApplicationContext is used as the event generator, applicationListeners are used as the listener collection, and applicationEventMulticaster is used to publish events.
Several steps to publish an event:
Subscription: Initially addApplicationListener to the listener collection.
Publish: ApplicationContext inherits the ApplicationEventPublisher, thus implementing publishEvent. This method will first traverse the applicationListeners collection of this applicationContext, call onApplicationEvent for each listener, so each listener will be notified; after this step is completed, the same event will be published for all applicationListeners of the applicationContext parent.
Event publishing is very common. Not only can our own applications use this event publishing, but the spring framework itself is also using event publishing. Here are some applications of events in spring:
The ContextRefreshedEvent will be published in finishRefresh to indicate that the refresh ends and notifies the listener. In the ApplicationContext, the start and stop methods will publish events that indicate the context start or end.
After Johnson created the main framework and operation process of spring, he found that spring provides many flexible expansion places. So Johnson is preparing to announce these flexible expansion usage on the third day.
1. BeanPostProcessor. BeanPostProcessor provides an extension interface after bean creation is completed. When you need to do some processing on beans after they are created, BeanPostProcessor is the preferred method.
2. Aware. The injected bean needs to know some parts of its container. Spring completes callbacks through Aware, such as BeanNameAware, which allows the bean to know its name. BeanFactoryAware can let the bean understand BeanFactory, ApplicationContextAware, which allows the bean to operate ApplicationContext. In this way, the bean injected with spring can do a wider range of things.
For the extension of BeanPostProcessor, spring itself has an example of how to identify an Aware bean. Aware beans are relatively special beans, and spring requires some additional attributes to it. So how will spring be used for the injection process? In fact, spring does not write it in the core processing process, but put it in the ApplicationContextAwareProcessor, the BeanPostProcessor, and finally invokeAwareInterfaces to judge the type of the bean and inject corresponding attributes. This approach uses BeanPostProcessor to complete another extended usage, which is really superb.
private void invokeAwareInterfaces(Object bean) { if (bean instanceof Aware) { if (bean instanceof EnvironmentAware) { ((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment()); } if (bean instanceof EmbeddedValueResolverAware) { ((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver( new EmbeddedValueResolver(this.applicationContext.getBeanFactory())); } if (bean instanceof ResourceLoaderAware) { ((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext); } if (bean instanceof ApplicationEventPublisherAware) { ((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext); } if (bean instanceof MessageSourceAware) { ((MessageSourceAware) bean).setMessageSource(this.applicationContext); } if (bean instanceof ApplicationContextAware) { ((ApplicationContextAware) bean).setApplicationContext(this.applicationContext); } } }There are more rules for using Aware. For example, the following code can perceive the ApplicationContext. After spring creates this bean, it will inject the ApplicationContext, so we can use this context to complete the event publishing.
public class HelloBean implements ApplicationContextAware { private ApplicationContext applicationContext; private String helloWord = "Hello!World!"; public void setApplicationContext(ApplicationContext context) { this.applicationContext = context; } public void setHelloWord(String helloWord) { this.helloWord = helloWord; } public String getHelloWord() { applicationContext.publishEvent( new PropertyGettedEvent("[" + helloWord + "] is gotted")); return helloWord; } } 3. BeanFactoryPostProcessor, this PostProcessor is usually used to handle the extended interface created by BeanFactory. An example is as follows. After injecting this bean, it will automatically print the number of injected beans after the BeanFactory creation:
public class BeanCounter implements BeanFactoryPostProcessor{ @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { System.out.println(beanFactory.getBeanDefinitionCount()); } } 4. FactoryBean. FactoryBean is a special bean, which allows injection into spring containers and generating real beans, so it can be defined in this way. FactoryBean itself is a bean, which has the ability to provide beans. The following starts with the FactoryBean call and talks about how spring uses this bean.
To distinguish between ordinary beans and FactoryBeans, spring must also have a process of judging them and handling them specially. This process is in the getObjectForBeanInstance of AbstractBeanFactory
protected Object getObjectForBeanInstance( Object beanInstance, String name, String beanName, RootBeanDefinition mbd) { // Don't let calling code try to dereference the factory if the bean isn't a factory. if (BeanFactoryUtils.isFactoryDereference(name) && !(beanInstance instanceof FactoryBean)) { throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass()); } // Now we have the bean instance, which may be a normal bean or a FactoryBean. // If it's a FactoryBean, we use it to create a bean instance, unless the // caller actually wants a reference to the factory. if (!(beanInstance instance of FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) { return beanInstance; } Object object = null; if (mbd == null) { object = getCachedObjectForFactoryBean(beanName); } if (object == null) { // Return bean instance from factory. FactoryBean<?> factory = (FactoryBean<?>) beanInstance; // Caches object obtained from FactoryBean if it is a singleton. if (mbd == null && containsBeanDefinition(beanName)) { mbd = getMergedLocalBeanDefinition(beanName); } boolean synthetic = (mbd != null && mbd.isSynthetic()); object = getObjectFromFactoryBean(factory, beanName, !synthetic); } return object; } It can be seen that if it is an ordinary bean, it will be returned directly, and if it is a FactoryBean, the final call will call factory.getObject to return the specific object. If you think of the entire spring as an abstract factory and when producing abstract beans, FactoryBean is a specific factory that produces the objects you need.
There are many uses of FactoryBean in spring. To give a relatively common example, when integrating the sessionFactory of hibernate, LocalSessionFactoryBean is usually injected, but this sessionFactory is actually not an ordinary bean. It can be produced simply by injecting it into the configuration file. It has many customized parts, so spring makes this bean a FactoryBean and controls its production object.