Formally into the Spring source code analysis module, for the huge project of spring, if a little bit of complete analysis is very difficult, for the application framework, I prefer to master ideas or design, rather than remember the code, for the first time to see the spring source code, I believe that everyone is very big, and see Understanding does not necessarily mean understanding. If you want better results, you need to record it and digress. LZ feels that blogging is really addictive. Once you start writing, you want to continue writing. Every time you finish writing an article, you feel productive and comfortable. But once you stop eating, you don't want to continue writing. This is the case. As a programmer, it is very important to keep on learning in the process of constant struggle and struggle with oneself. It will not only be strengthened in skills, but also have a great impact on one's personality development. Continuous learning is a terrible skill in any industry.
spring's analysis, to be exact, should not be called analysis, but learning. If you can use a complex framework in a simple way to make the reader understand, this is also a kind of ability.
Spring's function is so powerful that I don't know where to start. So the first step of analyzing spring is to disassemble spring's function. The simpler the function is, the clearer the module is. This is also the principle of software design.
Many of the online analysis starts from the ClassPath Xml Application Context class. LZ is not like this. LZ entered from this class at first, and then lost itself. It's okay to analyze the boxes first and not understand the details. After all, the code is not written by you. If you look at the code written by your colleagues, you may also sneer at it.
BeanFactory
BeanFactory provides the most basic function of IOC container. BeanFactory is only an interface class. It does not give the specific implementation of container. Of course, it has different implementation classes to define or extend a function. The main character of this article is it.
Start the IOC container
Here is a simple code to start the IOC container by programming:
public void TestDefaultListableBeanFactory(){ ClassPathResource resource = new ClassPathResource("spring.xml"); DefaultListableBeanFactory factory = new DefaultListableBeanFactory(); XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory); reader.loadBeanDefinitions(resource); MyBean bean = factory.getBean(MyBean.class); System.out.println(bean.toString()); }
The spring.xml configuration file is simple:
<bean id="myBean" class="com.study.spring.bean.MyBean" />
In this way, we can use the DefaultListableBeanFactory IOC container through the factory object. When using the IOC container, we need the following steps:
1) Create Abstract resources of IOC configuration files, that is, configuration files
2) Create a BeanFactory using DefaultListable BeanFactory
3) Create a reader to load BeanDefinition, where you use XmlBeanDefinition Reader to load BeanDefinition in the form of an XML file.
4) Read configuration information from defined resource locations, and the specific parsing process is completed by XmlBean Definition Reader.
spring can be started with a short code, the core is DefaultListable BeanFactory, not directly tracking the process for the time being, or take a look at the design of the entire BeanFactory.
BeanFactory System
BeanFactory, also well understood by name, is the factory (container) of the production management bean, which is responsible for the production and management of individual bean instances.
Let's look at the main inheritance structures associated with the BeanFactory interface:
The above inheritance relationship removes classes that are not currently needed.
emmmmm, this picture looks a bit big, slowly, first focus on the left part, comb the functions of each BeanFactory, how to comb? Look at the source code.
BeanFactory
BeanFactory is a top-level interface that defines the most basic form of an IOC container.
public interface BeanFactory { //You can leave it out here for the time being. String FACTORY_BEAN_PREFIX = "&"; Object getBean(String name) throws BeansException; ... //Eliminate other methods }
Some basic interfaces are defined, such as getting bean s, and of course there are other interfaces, which are not listed here and need to be understood by oneself.
As for the fact that FACTORY_BEAN_PREFIX can be ignored here, LZ simply mentions that if you don't understand it, there is a class named FactoryBean which is very similar to BeanFactory. It is easy to confuse its name. BeanFactory is Factoyr first, and FactoryBean is a bean, but it is a special kind of bean. A special bean produces another bean. For a normal bean, the bean can be obtained by the getBean method of the BeanFactory. For a FactoryBean, the bean produced by the FactoryBean, not the FactoryBean itself, can be prefixed if you want to get the FactoryBean itself. spring knows that you need FactoryBean. This may be in the AOP section later, so much to begin with.
ListableBeanFactory
public interface ListableBeanFactory extends BeanFactory { // Whether a given name contains BeanDefinition boolean containsBeanDefinition(String beanName); // Total number of BeanDefinition s returned to the factory int getBeanDefinitionCount(); // Return the names of all beans in the factory String[] getBeanDefinitionNames(); // Returns the name of the bean obtained for the specified type String[] getBeanNamesForType(ResolvableType type); //Get the name of the bean containing a comment String[] getBeanNamesForAnnotation(Class<? extends Annotation> annotationType); // Find the specified Bean based on the specified Bean name and annotation type <A extends Annotation> A findAnnotationOnBean(String beanName, Class<A> annotationType) throws NoSuchBeanDefinitionException; }
As you can guess from the name, this definition of an enumerable (iterated) BeanFactory allows you to find specific beans through this BeanFactory. Compared with the top BeanFactory, its queries are more diverse, involving BeanDefinition, BeanName, annotations.
Wait a minute. What is Bean Definition? In fact, it's known by name. This packaging is the definition of Bean. It's not what we need to discuss now. It's ok to have an impression from the name.
HierarchicalBeanFactory
public interface HierarchicalBeanFactory extends BeanFactory { BeanFactory getParentBeanFactory(); /** * Return whether the local bean factory contains a bean of the given name, * ignoring beans defined in ancestor contexts. * <p>This is an alternative to {@code containsBean}, ignoring a bean * of the given name from an ancestor bean factory. */ boolean containsLocalBean(String name); }
Layered BeanFactory, which has a very simple factory interface, implements the layering of Bean Factory. Compared with the BeanFactory interface, it only extends one important function - Factory hierarchy, which can specify the parent factory (container), and when looking up beans, it can only look up the container, ignoring the parent container.
AutowireCapableBeanFactory
public interface AutowireCapableBeanFactory extends BeanFactory { // This constant indicates that the factory does not have beans for automatic assembly. int AUTOWIRE_NO = 0; //Indicates automatic assembly by name int AUTOWIRE_BY_NAME = 1; //Indicates automatic assembly according to type int AUTOWIRE_BY_TYPE = 2; //It shows that the assembly is based on the construction method. int AUTOWIRE_CONSTRUCTOR = 3; //Abandoned @Deprecated int AUTOWIRE_AUTODETECT = 4; <T> T createBean(Class<T> beanClass) throws BeansException; // Given objects, automatic assembly is performed according to annotations, post-processors, etc. void autowireBean(Object existingBean) throws BeansException; ...//Omitting follow-up methods }
Autowire Capable BeanFactory has not been studied in depth yet. This BeanFactory adds annotation capabilities that can be assembled (operated) by annotations in the factory (container).
Summary
The above three Factories are the direct relatives of BeanFactory interface, three different types of BeanFactory, hierarchical container, enumerative (query) container, automatic assembly container, single function principle. This interface design should be often encountered in ordinary work.
Next, take a look at other, more diverse BeanFactory.
ConfigurableBeanFactory
public interface ConfigurableBeanFactory extends HierarchicalBeanFactory, SingletonBeanRegistry { String SCOPE_SINGLETON = "singleton"; String SCOPE_PROTOTYPE = "prototype"; //Setting up parent container void setParentBeanFactory(BeanFactory parentBeanFactory) throws IllegalStateException; void setBeanClassLoader(ClassLoader beanClassLoader); ClassLoader getBeanClassLoader(); void setBeanExpressionResolver(@Nullable BeanExpressionResolver resolver); BeanExpressionResolver getBeanExpressionResolver(); /* * Setting up conversion services */ void setConversionService(ConversionService conversionService); ConversionService getConversionService(); void addPropertyEditorRegistrar(PropertyEditorRegistrar registrar); /* * Register Property Editor */ void registerCustomEditor(Class<?> requiredType, Class<? extends PropertyEditor> propertyEditorClass); void copyRegisteredEditorsTo(PropertyEditorRegistry registry); void setTypeConverter(TypeConverter typeConverter); TypeConverter getTypeConverter(); //Setting up a Bean Post Processor void addBeanPostProcessor(BeanPostProcessor beanPostProcessor); int getBeanPostProcessorCount(); void registerScope(String scopeName, Scope scope); String[] getRegisteredScopeNames(); Scope getRegisteredScope(String scopeName); void copyConfigurationFrom(ConfigurableBeanFactory otherFactory); /* * Register an alias for the specified Bean */ void registerAlias(String beanName, String alias) throws BeanDefinitionStoreException; BeanDefinition getMergedBeanDefinition(String beanName) throws NoSuchBeanDefinitionException; //Determine whether the specified Bean is a factory Bean boolean isFactoryBean(String name) throws NoSuchBeanDefinitionException; void setCurrentlyInCreation(String beanName, boolean inCreation); boolean isCurrentlyInCreation(String beanName); void registerDependentBean(String beanName, String dependentBeanName); String[] getDependentBeans(String beanName); String[] getDependenciesForBean(String beanName); void destroyBean(String beanName, Object beanInstance); void destroyScopedBean(String beanName); void destroySingletons(); ...//Omitted partial method }
Configurable BeanFactory inherits Hierarchical BeanFactory, Singleton Bean Registry
First look at the source code for the interface Singleton Bean Registry:
SingletonBeanRegistry
public interface SingletonBeanRegistry { //Register a single case class void registerSingleton(String beanName, Object singletonObject); Object getSingleton(String beanName); boolean containsSingleton(String beanName); String[] getSingletonNames(); int getSingletonCount(); //Unclear Object getSingletonMutex(); }
As you can see, the Singleton Bean Registry interface is very simple and implements the function of single class registration.
Configurable BeanFactory inherits both Hierarchical BeanFactory and Singleton BeanRegistry interfaces, i.e. it inherits the functions of hierarchical and case class registration.
Configurable BeanFactory, just like its name, can be configured with BeanFactory. There are many interface methods in it. I have not studied each method carefully. Later, I use it. Then I can analyze it in detail. Understand it and know its general use.
ConfigurableListableBeanFactory
public interface ConfigurableListableBeanFactory extends ListableBeanFactory, AutowireCapableBeanFactory, ConfigurableBeanFactory { //Ignoring dependency types for automatic assembly void ignoreDependencyType(Class<?> type); //Ignoring Automated Assembly Interface void ignoreDependencyInterface(Class<?> ifc); //Return registered Bean definitions BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException; Iterator<String> getBeanNamesIterator(); ...//Ignoring Partial Method }
The factory interface Configurable Listable BeanFactory inherits three interfaces at the same time, Listable BeanFactory, Autowire Capable BeanFactory and Configurable BeanFactory, which can be said to be functional and comprehensive.
For the left part of the BeanFactory system, it's almost the same. Now let's look at the right half.
BeanDefinitionRegistry
As the name implies, this is a registered BeanDefinition
public interface BeanDefinitionRegistry extends AliasRegistry { //Given the bean name, register a new bean definition void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException; //Remove the corresponding Bean definition according to the specified Bean name void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException; //Get the corresponding bean definition based on the specified bean name BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException; //Find if the specified Bean name contains a Bean definition boolean containsBeanDefinition(String beanName); //Returns all registered Bean definition names in this container String[] getBeanDefinitionNames(); //Specifies whether the Bean name has been registered. int getBeanDefinitionCount(); //Specifies whether the Bean name has been registered. boolean isBeanNameInUse(String beanName); }
The interface is very simple, that is, the operation of Bean Definition. However, we have not yet understood the structure of Bean Definition, but it does not affect our analysis, because we know from the name that this refers to the definition of a bean, that is, to translate beans in xml into specific data structures.
Now, looking back, let's look at the DefaultListableBeanFactory class diagram
For the left part, it's a BeanFactory with various functions, for the right part, it's a function operation of BeanDefinition, for the middle part, it's a single Bean function service, and for the middle part, we haven't analyzed the source code, but we know its function well by name, and FactoryBean Registry Support represents it. Support for FactoryBean (FactoryBean mentioned briefly in BeanFactory earlier)
Now I have a general idea of the functions of each BeanFactory, so that I can know which module this function belongs to at a later time, instead of having my head in a puddle.
For DefaultListableBeanFactory, we did not analyze it, because DefaultListableBeanFactory implements all the methods in the above interface, involving many details. From the code point of view, it is really difficult to analyze, but from the functional module point of view, we also know it. Now that we know the container for beans, where do beans come from, of course, xml, but how can XML be converted into data structures?
public void TestDefaultListableBeanFactory(){ ClassPathResource resource = new ClassPathResource("spring.xml"); //3 DefaultListableBeanFactory factory = new DefaultListableBeanFactory(); //5 XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);//7 reader.loadBeanDefinitions(resour ce);//9 MyBean bean = factory.getBean(MyBean.class); //11 System.out.println(bean.toString()); }
Now that we've got lines 5 and 11, the main ones are 3, 4 and 9, so let's leave that for later.
BeanDefinition
Bean Definition is mainly described by Bean Definition. As the data structure used to wrap beans in Spring, let's first look at an inheritance structure of Bean Definition (incomplete inheritance structure).
A BeanDefinition describes an instance of a bean, including attribute values, constructor parameter values, and more information about classes inherited from it.
Brief Analysis of BeanDefinition Source Code
//Standard singleton scope identifier: "singleton". String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON; //Standard prototype scope identifier: "prototype". String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE; //Represents that BeanDefinition is a role prompt for the main part of the application. Usually it corresponds to a user-defined bean. int ROLE_APPLICATION = 0; //Represents that BeanDefinition is a role hint for the support part of some large configuration, usually an external Component Definition. //When you look at a particular Component Definition, you think bean s are very important. //To be aware of this when looking at the overall configuration of the application. int ROLE_SUPPORT = 1; //Role hints indicate that a BeanDefinition is a role that provides a complete background and has nothing to do with the end user. int ROLE_INFRASTRUCTURE = 2;
ROLE_SUPPORT= 1 actually means that my Bean is a user, coming from the configuration file.
ROLE_INFRASTRUCTURE = 2 means that the Bean is Spring's own.
Above is some basic attribute information of BeanDifinition. One is to identify the scope of the current Bean, and the other is to identify whether the Bean is internal or external. Now let's look at what specific behavior methods this interface provides for its subclasses:
1. ClassName get & set method of current Bean
//Specify the bean class name defined by this bean. //Class names can be modified in bean factory post-processing, usually replacing the original class names with its parsing variants. void setBeanClassName(String beanClassName); //Returns the current bean class name defined by this bean. //It is important to note that this is not necessarily the actual class name used at run time, in case the subclass definition overrides/inherits the class name of its parent class. //In addition, this may be just a class that calls the factory method, or it may even be empty if the factory bean that calls the method references it. //Therefore, don't think of it as a bean type defined at run time, just use it for parsing at a separate bean definition level. String getBeanClassName();
2.Bean's scoped get-set method
//Override the target scope of this bean and specify a new scope name. void setScope(String scope); //Returns the name of the current target scope for this bean, and if not determined, returns null String getScope();
3. Lazy Loading Get & Set Method
//Set whether the bean should be delayed initialization. If {false}, the bean will be instantiated by the bean factory at startup. //These factories perform immediate initialization of the singleton. //Lazy loading < bean lazy-init= "true/false"> void setLazyInit(boolean lazyInit); //Returns whether the bean should be delayed initialization, that is, not instantiated immediately at startup. Only for singleton beans. boolean isLazyInit();
4. Dependency Settings
//Setting this bean depends on the name of the initialized bean. The bean factory will ensure that these beans are initialized first. //<bean depends-on=""> void setDependsOn(String... dependsOn); //Returns the bean name that the bean depends on. String[] getDependsOn();
5. Whether it is automatic transfer settings
//Set whether this bean is a candidate for automatic assembly to other beans. //It should be noted that this flag is intended to affect only type-based automatic assembly. //It does not affect explicit references by name, which can be solved even if the specified bean is not marked as an autowire candidate. //Therefore, if the name matches, a bean will be injected through the automatic assembly of the name. void setAutowireCandidate(boolean autowireCandidate); //Returns whether this bean is a candidate for automatic assembly to other beans. Is it possible to use autowired in other classes to inject the current bean //Is it automatically assembled <bean autowire-candidate= "true/false"> boolean isAutowireCandidate();
There is no complete list of methods or attributes in BeanDifinition. It is generally understood that the definition of Bean is mainly described by BeanDefinition. As the data structure used to wrap beans in Spring, it is enough to implement more interfaces for BeanDifinition. This can be seen according to your own situation.
Summary
After understanding the general structure of BeanFactory, take a look at the following simple code, I believe that the understanding will be more profound:
public void TestDefaultListableBeanFactory(){ DefaultListableBeanFactory factory = new DefaultListableBeanFactory(); AbstractBeanDefinition beanDefinition = new RootBeanDefinition(MyBean.class); factory.registerBeanDefinition("myBean",beanDefinition); //Dependencies can be injected through constructs, but we don't have them here, of course. //beanDefinition.setConstructorArgumentValues(); //Dependencies can be injected through setter methods, but we don't have them here, of course. //beanDefinition.setPropertyValues(); MyBean bean = factory.getBean(MyBean.class); System.out.println(bean.toString()); }
We used ClassPathResource and XmlBean Definition Reader to read the bean configuration information from the file. Now that we know Bean Difinition and Bean Definition Registry, we can actually register Bean Difinition manually, so I subdivide the function again on the basis of the original code. It's also clearer.
summary
Starting from DefaultListable BeanFactory, we have a general understanding of the architecture of BeanFactory, which has three direct relatives:
Listable BeanFactory, Hierarchical BeanFactory and Autowire Capable BeanFactory define the basic features of BeanFactory. Two more complex containers are derived under these three immediate relatives. Containers: Configurable BeanFactory, Configurable Listable BeanFactory, configurable (operable) containers, through which beanFactories can modify beans in containers, more advanced functions, integration of single bean services, and BeanDefinition registration services, then for DefaultListable BeanFactory At this point, it is a registrable, configurable and accessible BeanFactory, which is fully functional in terms of containers.