Source code analysis of Spring IOC container prestart process
In the application, it is by creating commonly ClassPathXmlApplicationContext or AnnotationConfigApplicationContext the two bottom subclasses to start the Spring IOC container:
ClassPathXmlApplicationContext
:xml
File configuration editionAnnotationConfigApplicationContext
: annotation
Since it is increasingly popular to create our beans based on Java annotations, this article focuses on the annotated version.
AnnotationConfigApplicationContext
Class relation structure of
Let’s start by looking at where we started
public class Main {
public static void main(String[] args) {
new AnnotationConfigApplicationContext(Config.class);
}
@Configuration
public static class Config{}}Copy the code
The demo is simple. So, what’s going on here? Maybe we can see AnnotationConfigApplicationContext class relationship structure:
We can see the top AnnotationConfigApplicationContext has two top interface:
BeanFactory
: Spring’s core interface, a pure bean container, mainly defines andBean
The correlation method ofResourceLoader
: resource loader, definedgetResource
methods
Inherits from three parent classes:
-
DefaultResourceLoader: the DefaultResourceLoader that implements three ways of loading resources
-
Load resources using path
-
Load resources through the classpath
-
Load resources through urls
-
-
AbstractApplicationContext: implements the ApplicationContext interface of the abstract class, major functions
-
Implements the core method for starting the IOC container: refresh()
-
Publish event
-
A number of getBean-related operations are implemented based on subclasses, primarily through the abstract getBeanFactory method
-
A large number of empty methods left for subclass extension
-
Message internationalization
-
-
GenericApplicationContext
:-
Using the combination way of introducing the bottom of the BeanFactory implementation class: DefaultListableBeanFactory
-
Defines the registerBean related operations, is achieved by DefaultListableBeanFactory
-
As you can see, ApplicationContext is literally an ApplicationContext, and bean operations and container management are still implemented by our BeanFactory.
Ready to start
1. Create our instance:AnnotationConfigApplicationContext
new AnnotationConfigApplicationContext(Config.class);
Copy the code
2. To enterAnnotationConfigApplicationContext
A constructor
public AnnotationConfigApplicationContext(Class
... annotatedClasses) {
this(a); register(annotatedClasses); refresh(); }Copy the code
3. Call our empty constructor, which instantiates our parent class first
3.1 instantiationDefaultResourceLoader
public DefaultResourceLoader(a) {
this.classLoader = ClassUtils.getDefaultClassLoader();
}
Copy the code
ClassUtils. GetDefaultClassLoader () there are two major step operation
// The class loader that gets the thread context
ClassLoader cl = = Thread.currentThread().getContextClassLoader();
if(cl == null) // If this parameter is null, the application class loader is the system class loader
cl = ClassLoader.getSystemClassLoader();
Copy the code
Here we are not in a Tomcat environment, so we return AppClassLoader
3.2 instantiationAbstractApplicationContext
// Assign an initial value to BeanFactoryPostProcessor
List<BeanFactoryPostProcessor> BeanFactoryPostProcessor = new ArrayList<>();
public AbstractApplicationContext(a) {
// Introduce a resource resolver
this.resourcePatternResolver = getResourcePatternResolver();
}
protected ResourcePatternResolver getResourcePatternResolver(a) {
return new PathMatchingResourcePatternResolver(this);
}
Copy the code
3.3 instantiationGenericApplicationContext
public GenericApplicationContext(a) {
// Introduce the BeanFactory implementation
this.beanFactory = new DefaultListableBeanFactory();
}
Copy the code
3.4 Instantiate yourself
public AnnotationConfigApplicationContext(a) {
// Initialize the annotation-based bean definition scanner
this.reader = new AnnotatedBeanDefinitionReader(this);
// Initialize the bean definition scanner based on the CLASspath
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
Copy the code
3.4.1 trackAnnotatedBeanDefinitionReader
Initialization process
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry) {
this(registry, getOrCreateEnvironment(registry));
}
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
/ / is our AnnotationConfigApplicationContext registry
this.registry = registry;
// Introduces a Conditional expression calculator to handle @conditional annotations
this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
// Register all annotation-related postprocessors
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}
Copy the code
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry)
public static void registerAnnotationConfigProcessors(BeanDefinitionRegistry registry) {
registerAnnotationConfigProcessors(registry, null);
}
Copy the code
RegisterAnnotationConfigProcessors (registry, null), which mainly do the following things:
-
The two references for DefaultListableBeanFactory assignment
// A dependent collator for beans with Priority, Order annotations, and Ordered interface added beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE); // @autowire candidate parser beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver()); Copy the code
-
Bean definitions with six post-processors registered to the container
Registers the post-processor for the configuration class
RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class); def.setSource(source); registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME); Copy the code
Register a post-processor that handles @Autowired annotations
RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class); def.setSource(source); registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME); Copy the code
Register a post-processor that handles @required annotations (deprecated as of version 5.1)
RootBeanDefinition def = new RootBeanDefinition(RequiredAnnotationBeanPostProcessor.class); def.setSource(source); registerPostProcessor(registry, def, REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME); Copy the code
Register backend handlers that handle jSR-250 specification annotations, @Resource, @postConstruct, @Predestroy
RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class); def.setSource(source); registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME); Copy the code
Register a post-processor that handles the @EventListener annotation
RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class); def.setSource(source); registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME); Copy the code
Factory registered event listeners, give the EventListenerMethodProcessors used above
RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class); def.setSource(source); registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME); Copy the code
3.4.2 ClassPathBeanDefinitionScanner
Initialization process
It goes through a series of constructor passes
public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry) {
this(registry, true);
}
public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters) {
this(registry, useDefaultFilters, getOrCreateEnvironment(registry));
}
public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters,
Environment environment) {
this(registry, useDefaultFilters, environment,
(registry instanceof ResourceLoader ? (ResourceLoader) registry : null));
}
Copy the code
The constructor method for the final implementation
public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters,
Environment environment, @Nullable ResourceLoader resourceLoader) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
this.registry = registry;
// Defaults to true
if (useDefaultFilters) {
// Register the default filter
registerDefaultFilters();
}
// Set the environment
setEnvironment(environment);
// Set the resource loader
setResourceLoader(resourceLoader);
}
Copy the code
RegisterDefaultFilters method
protected void registerDefaultFilters(a) {
// Add a filter to scan @Component annotations so that @Controller, @service...
this.includeFilters.add(new AnnotationTypeFilter(Component.class));
ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader();
try {
// Annotations to the JSR-250 specification
this.includeFilters.add(new AnnotationTypeFilter(
((Class<? extends Annotation>) ClassUtils.forName("javax.annotation.ManagedBean", cl)), false));
}
catch (ClassNotFoundException ex) {
}
try {
// Comments on the JSR-330 specification
this.includeFilters.add(new AnnotationTypeFilter(
((Class<? extends Annotation>) ClassUtils.forName("javax.inject.Named", cl)), false));
}
catch (ClassNotFoundException ex) {
}
}
Copy the code
4. The constructor is executedregister(annotatedClasses)
Method to register the bean definition of the configuration class in the container
public void register(Class
... annotatedClasses) {
Assert.notEmpty(annotatedClasses, "At least one annotated class must be specified");
/ / is used here just AnnotatedBeanDefinitionReader sweep of initialization code
//annotatedClasses are the custom configuration class config.class passed in at the entry
this.reader.register(annotatedClasses);
}
Copy the code
public void register(Class
... annotatedClasses) {
for(Class<? > annotatedClass : annotatedClasses) {// Here we pass only one loopregisterBean(annotatedClass); }}Copy the code
public void registerBean(Class
annotatedClass) {
// Spring implements the do start method
doRegisterBean(annotatedClass, null.null.null);
}
Copy the code
<T> void doRegisterBean(Class<T> annotatedClass, @Nullable Supplier<T> instanceSupplier, @Nullable String name,
@Nullable Class<? extends Annotation>[] qualifiers, BeanDefinitionCustomizer... definitionCustomizers) {
// Encapsulate the class in the bean definition
AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);
Return false because the configuration class does not use the @Conditional annotation
if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
return;
}
abd.setInstanceSupplier(instanceSupplier);
// Parse the scope defined by the bean
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd); abd.setScope(scopeMetadata.getScopeName()); String beanName = (name ! =null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));
// Handle ordinary bean definition annotations, @lazy @primary @dependson @role @description
AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
if(qualifiers ! =null) {
for (Class<? extends Annotation> qualifier : qualifiers) {
if (Primary.class == qualifier) {
abd.setPrimary(true);
}
else if (Lazy.class == qualifier) {
abd.setLazyInit(true);
}
else {
abd.addQualifier(newAutowireCandidateQualifier(qualifier)); }}}for (BeanDefinitionCustomizer customizer : definitionCustomizers) {
customizer.customize(abd);
}
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
// Determine whether proxy encapsulation is required according to the proxy-mode property in scopeMetadata. The default value is no
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
// Register the bean definition in the container
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
}
Copy the code
With most of the preparatory work done, you are ready to call the Refresh method to start the IOC container.
I plan to spend 30 days systematically organizing my knowledge of Spring source code:
Spring Source code series
- Spring source code analysis of IOC container prestart process (completed)
- BeanFactory Architecture for Spring source analysis (completed)
- Spring Source Analysis BeanFactoryPostProcessor call process (completed)
- Spring source analysis of the Bean creation process
- What are cyclic dependencies and solutions for Spring source analysis
- AOP for Spring source analysis from parsing to invocation
- Spring source analysis of transaction management (1), transaction management is a feature of Spring as a container, summarize his basic implementation and principle
- Spring source analysis of transaction management (below), about his underlying thing isolation and thing propagation principle, focus on the analysis
Spring Mvc source code series
- The SpringMvc architecture
- SpringMvc source code analysis Handler parsing process
- Request chain process for SpringMvc source code analysis
Mybatis source series
tentative
Chase more, can pay attention to my public number: geek time, share purely for fun, but also have a sense of achievement, the author of this article to this first