1.Bean
parsing
1.1 Setting the Configuration class processor
1.1.1 Instantiating context objects
public AnnotationConfigServletWebServerApplicationContext(a) {
this.reader = new AnnotatedBeanDefinitionReader(this);
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
Copy the code
1.1.2 instantiationBeanFactory
AnnotationConfigServletWebServerApplicationContex inherited GenericApplicationContext, executed before the constructor in the superclass constructor
public GenericApplicationContext(a) {
this.beanFactory = new DefaultListableBeanFactory();
}
Copy the code
1.1.3 Instantiating the reader
The reader is instantiated in Section 1.1.1, which injects a series of BeanDefinitions into the container
1.1.4 injectionBeanDefinition
public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
BeanDefinitionRegistry registry, @Nullable Object source) {
DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);
if(! registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) { RootBeanDefinition def =new RootBeanDefinition(ConfigurationClassPostProcessor.class);
def.setSource(source);
/ / injection ConfigurationClassPostProcessor, used to handle @ Configuration annotations Configuration class
beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
}
if(! registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) { RootBeanDefinition def =new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
def.setSource(source);
/ / injection AutowiredAnnotationBeanPostProcessor, Value, used to deal with @autowired, @ @ Inject annotation
beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
}
if(jsr250Present && ! registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) { RootBeanDefinition def =new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
def.setSource(source);
/ / injection CommonAnnotationBeanPostProcessor, used to handle @ Resource annotation
beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
}
return beanDefs;
}
Copy the code
1.1.5 callBeanFactoryPostProcessors
Context when refresh will perform invokeBeanFactoryPostProcessors () method
public static void invokeBeanFactoryPostProcessors( ConfigurableListableBeanFactory beanFactory, List
beanFactoryPostProcessors)
{
// Invoke BeanDefinitionRegistryPostProcessors first, if any.
Set<String> processedBeans = new HashSet<>();
if (beanFactory instanceof BeanDefinitionRegistry) {
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();
List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();
/ / from the container type BeanDefinitionRegistryPostProcessor Bean name,
/ / in section 1.1.4 injection ConfigurationClassPostProcessor has been realized
/ / BeanDefinitionRegistryPostProcessor and PriorityOrdered interface to meet the conditions
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true.false);
for (String ppName : postProcessorNames) {
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
/ / create ConfigurationClassPostProcessor Bean objectcurrentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class)); processedBeans.add(ppName); }}/ / call ConfigurationClassPostProcessor postProcessBeanDefinitionRegistry () method
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());
/ /... Omit some code}}Copy the code
1.2 Parsing configuration Classes
Methods analytic entrance ConfigurationClassParser doProcessConfigurationClass configuration class
1.2.1 Handling internal configuration classes
if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
// Handle the Configuration class annotated by the internal @Configuration annotation
processMemberClasses(configClass, sourceClass, filter);
}
Copy the code
1.2.2 processing@ComponentScan
annotations
// Handle @ComponentScan annotations
Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
if(! componentScans.isEmpty() && !this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
for (AnnotationAttributes componentScan : componentScans) {
// Scan the class annotated by the @Component annotation in the specified path and register it as BeanDefinition
// @controller, @service, @Repository, and @Configuration are all annotated with the @Component annotation
Set<BeanDefinitionHolder> scannedBeanDefinitions =
this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
/ / traverse BeanDefinition
for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
if (bdCand == null) {
bdCand = holder.getBeanDefinition();
}
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
// Parse the configuration class annotated by the @Component annotationparse(bdCand.getBeanClassName(), holder.getBeanName()); }}}}Copy the code
1.2.3 processing@Import
annotations
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
Collection<SourceClass> importCandidates, Predicate<String> exclusionFilter,
boolean checkForCircularImports) {
for (SourceClass candidate : importCandidates) {
// 1. If the @import annotation value specifies a class that implements the ImportSelector interface
if(candidate.isAssignable(ImportSelector.class)) { Class<? > candidateClass = candidate.loadClass();// 1.2 Instantiate objects
ImportSelector selector = ParserStrategyUtils.instantiateClass(candidateClass, ImportSelector.class,
this.environment, this.resourceLoader, this.registry);
Predicate<String> selectorFilter = selector.getExclusionFilter();
if(selectorFilter ! =null) {
exclusionFilter = exclusionFilter.or(selectorFilter);
}
// 1.3 If the DeferredImportSelector interface is implemented, delay processing is performed
/ / @ EnableAutoConfiguration introduce annotations AutoConfigurationImportSelector implements this interface
// Used to finally load the auto-configuration classes in Spring.Factories
if (selector instanceof DeferredImportSelector) {
this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);
}
// 1.4 If implementing the ImportSelector interface
else {
// 1.5 Call the target method
String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames, exclusionFilter);
// 1.6 Recursive invocation
processImports(configClass, currentSourceClass, importSourceClasses, exclusionFilter, false); }}/ / 2. If the implementation ImportBeanDefinitionRegistrar interface
else if(candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) { Class<? > candidateClass = candidate.loadClass();// 2.1 Instantiate objects
ImportBeanDefinitionRegistrar registrar =
ParserStrategyUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class,
this.environment, this.resourceLoader, this.registry);
// 2.2 Store the instantiated object in the current configuration class (used later)
configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
}
else {
// 3. No interface is implemented, so it is parsed as a common configuration class
// This common configuration class is introduced by the current configuration class (used later)
this.importStack.registerImport( currentSourceClass.getMetadata(), candidate.getMetadata().getClassName()); processConfigurationClass(candidate.asConfigClass(configClass), exclusionFilter); }}}Copy the code
1. To deal with@Bean
annotations
// Parse the method with the @bean annotation in the current configuration class and assemble it into MethodMetadata
Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
for (MethodMetadata methodMetadata : beanMethods) {
// Assemble BeanMethod according to MethodMetadata into the current configuration class (we'll use it later)
configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}
Copy the code
1.2.5 processing@EnableAutoConfiguration
annotations
After all configuration classes are parsed, they are put into the map
this.configurationClasses.put(configClass, configClass);
Copy the code
@ EnableAutoConfiguration introduced AutoConfigurationImportSelector AutoConfigurationImportSelector and implements DeferredImportSelector interface, According to the analysis of could discern AutoConfigurationImportSelector 1.2.3 chapter introduced the automatic configuration of class will be in the final parse, join configurationClasses container after parsing is complete
1.2.6 loadBeanDefinition
@import, @Bean, and @EnableAutoConfiguration do not generate a BeanDefinition injection container except for the @ComponentScan annotation scanned configuration class in Section 1.2.2
private void loadBeanDefinitionsForConfigurationClass( ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {
// If the current configuration class is imported, generate BeanDefinition and inject it into the container, as described in Section 1.2.3
if (configClass.isImported()) {
registerBeanDefinitionForImportedConfigurationClass(configClass);
}
// Get the BeanMethod in the current configuration class, generate the BeanDefinition, and inject it into the container, as shown in Section 1.2.4
for (BeanMethod beanMethod : configClass.getBeanMethods()) {
loadBeanDefinitionsForBeanMethod(beanMethod);
}
/ / get the current configuration class ImportBeanDefinitionRegistrar BeanDefinition and injected into the container, corresponding 1.2.3 section in the second part
loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
}
Copy the code
1.2.7 Several ways to inject containers
@Component
annotations@Import
The introduction of@Bean
annotations- in
spring.factories
Defined in theorg.springframework.boot.autoconfigure.EnableAutoConfiguration=xxx
2.Bean
create
After the configuration class is parsed to generate a BeanDefinition and injected into the container, the next step is to instantiate the BeanDefinition in the container
2.1 Bean
instantiation
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
// Make sure bean class is actually resolved at this point.Class<? > beanClass = resolveBeanClass(mbd, beanName);// 1. Instantiate with the supplied SupplierSupplier<? > instanceSupplier = mbd.getInstanceSupplier();if(instanceSupplier ! =null) {
return obtainFromSupplier(instanceSupplier, beanName);
}
// 2.@Bean annotation annotation, instantiated by calling the target method reflectively
if(mbd.getFactoryMethodName() ! =null) {
returninstantiateUsingFactoryMethod(beanName, mbd, args); } Constructor<? >[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);if(ctors ! =null|| mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR || mbd.hasConstructorArgumentValues() || ! ObjectUtils.isEmpty(args)) {// 3. Call the constructor to instantiate
return autowireConstructor(beanName, mbd, ctors, args);
}
ctors = mbd.getPreferredConstructors();
if(ctors ! =null) {
// 4. Call the constructor to instantiate
return autowireConstructor(beanName, mbd, ctors, null);
}
// 5. Call the no-argument constructor to instantiate
return instantiateBean(beanName, mbd);
}
Copy the code
2.2 the fillingBean
After the object is instantiated, it needs to fill in the injected properties, such as @Value, @AutoWired, and @Inject annotated properties or methods
2.2.1 Specifying the fill type
public AutowiredAnnotationBeanPostProcessor(a) {
// 1. Set @autowired
this.autowiredAnnotationTypes.add(Autowired.class);
// 2. Set the @value type
this.autowiredAnnotationTypes.add(Value.class);
try {
// 3. Support @inject type
this.autowiredAnnotationTypes.add((Class<? extends Annotation>)
ClassUtils.forName("javax.inject.Inject", AutowiredAnnotationBeanPostProcessor.class.getClassLoader()));
}
catch (ClassNotFoundException ex) {
}
}
Copy the code
2.2.2 Building metadata
private InjectionMetadata buildAutowiringMetadata(finalClass<? > clazz) {
if(! AnnotationUtils.isCandidateClass(clazz,this.autowiredAnnotationTypes)) {
return InjectionMetadata.EMPTY;
}
List<InjectionMetadata.InjectedElement> elements = newArrayList<>(); Class<? > targetClass = clazz;do {
final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();
Construct AutowiredFieldElement by iterating over the attributes annotated by @Value, @AutoWired, and @Inject annotationsReflectionUtils.doWithLocalFields(targetClass, field -> { MergedAnnotation<? > ann = findAutowiredAnnotation(field);if(ann ! =null) {
// 2. Cannot be modified static
if (Modifier.isStatic(field.getModifiers())) {
if (logger.isInfoEnabled()) {
logger.info("Autowired annotation is not supported on static fields: " + field);
}
return;
}
boolean required = determineRequiredStatus(ann);
currElements.add(newAutowiredFieldElement(field, required)); }});// 3. Construct AutowiredMethodElement by iterating the method annotated by @Value, @AutoWired, @Inject annotation
ReflectionUtils.doWithLocalMethods(targetClass, method -> {
Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
if(! BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {return; } MergedAnnotation<? > ann = findAutowiredAnnotation(bridgedMethod);if(ann ! =null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
// 4. Cannot be modified static
if (Modifier.isStatic(method.getModifiers())) {
if (logger.isInfoEnabled()) {
logger.info("Autowired annotation is not supported on static methods: " + method);
}
return;
}
if (method.getParameterCount() == 0) {
if (logger.isInfoEnabled()) {
logger.info("Autowired annotation should only be used on methods with parameters: "+ method); }}boolean required = determineRequiredStatus(ann);
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
currElements.add(newAutowiredMethodElement(method, required, pd)); }}); elements.addAll(0, currElements);
targetClass = targetClass.getSuperclass();
}
while(targetClass ! =null&& targetClass ! = Object.class);return InjectionMetadata.forElements(elements, clazz);
}
Copy the code
2.2.3 Injecting padding
public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
Collection<InjectedElement> checkedElements = this.checkedElements; Collection<InjectedElement> elementsToIterate = (checkedElements ! =null ? checkedElements : this.injectedElements);
if(! elementsToIterate.isEmpty()) {// 1. Iterate over the metadata constructed in Section 2.2.2
for (InjectedElement element : elementsToIterate) {
// 2. If the annotation is @value, the corresponding configuration is obtained from the Environment based on the Value of the Value attribute
// 3. If the @autoWired annotation annotation is annotated, the corresponding Bean is fetched from the container for injectionelement.inject(target, beanName, pvs); }}}Copy the code
2.3 the initializationBean
2.3.1 Aware
To deal with
private void invokeAwareMethods(String beanName, Object bean) {
if (bean instanceof Aware) {
// 1. If the current Bean implements the BeanNameAware interface, the setBeanName() method is called to set the Bean name
if (bean instanceof BeanNameAware) {
((BeanNameAware) bean).setBeanName(beanName);
}
// 2. The current Bean implements the BeanClassLoaderAware interface, so the setBeanClassLoader() method is called to set the ClassLoader
if (bean instanceof BeanClassLoaderAware) {
ClassLoader bcl = getBeanClassLoader();
if(bcl ! =null) { ((BeanClassLoaderAware) bean).setBeanClassLoader(bcl); }}// 3. If the current Bean implements the BeanFactoryAware interface, the setBeanFactory() method is called to set the BeanFactory
if (bean instanceof BeanFactoryAware) {
((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this); }}}Copy the code
ApplicationContextAwareProcessor preposition
private void invokeAwareInterfaces(Object bean) {
if (bean instanceof EnvironmentAware) {
((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
}
if (bean instanceof EmbeddedValueResolverAware) {
((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
}
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 ApplicationStartupAware) {
((ApplicationStartupAware) bean).setApplicationStartup(this.applicationContext.getApplicationStartup());
}
if (bean instanceof ApplicationContextAware) {
((ApplicationContextAware) bean).setApplicationContext(this.applicationContext); }}Copy the code
Here you can understand why the implementation of xxxAware interface, you can get a certain ability of the reason
2.3.2 BeanPostProcessor
pre-processing
All of the traversal container BeanPostProcessor and call its postProcessBeforeInitialization () method
@Override
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor processor : getBeanPostProcessors()) {
Object current = processor.postProcessBeforeInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
Copy the code
2.3.3 @PostConstruct
Annotation processing
CommonAnnotationBeanPostProcessor implements the BeanPostProcessor interface, therefore also call BeanPostProcessor postProcessBeforeInitialization () method, Used to handle @postconstruct annotations
public CommonAnnotationBeanPostProcessor(a) {
setOrder(Ordered.LOWEST_PRECEDENCE - 3);
setInitAnnotationType(PostConstruct.class);
setDestroyAnnotationType(PreDestroy.class);
ignoreResourceType("javax.xml.ws.WebServiceContext");
}
Copy the code
2.3.4 InitializingBean
To deal with
The Bean implements the InitializingBean interface and calls the afterPropertiesSet() implementation method to initialize the Bean
protected void invokeInitMethods(String beanName, Object bean, @Nullable RootBeanDefinition mbd)
throws Throwable {
boolean isInitializingBean = (bean instanceof InitializingBean);
if (isInitializingBean && (mbd == null| |! mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
if (logger.isTraceEnabled()) {
logger.trace("Invoking afterPropertiesSet() on bean with name '" + beanName + "'"); } ((InitializingBean) bean).afterPropertiesSet(); }}Copy the code
2.3.5 @Bean
The initMethod annotation is handled
if(mbd ! =null&& bean.getClass() ! = NullBean.class) { String initMethodName = mbd.getInitMethodName();if(StringUtils.hasLength(initMethodName) && ! (isInitializingBean &&"afterPropertiesSet".equals(initMethodName)) && ! mbd.isExternallyManagedInitMethod(initMethodName)) {// Find the initialization method specified by initMethod in the Bean and call backinvokeCustomInitMethod(beanName, bean, mbd); }}Copy the code
2.3.6 BeanPostProcessor
Post processing
@Override
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor processor : getBeanPostProcessors()) {
Object current = processor.postProcessAfterInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
Copy the code
3. Bean
Life cycle summary
- Parsing generated
BeanDefinition
Into the container - create
Bean
- fill
@Value
and@Autowired
data - The callback
Aware
Interface implementation method - perform
BeanPostProcessor
pre-processing - The callback
InitializingBean
Interface implementation method - call
@Bean
The method specified by the initMethod property of the annotation - perform
BeanPostProcessor
Post processing