原文地址:http://blog.csdn.net/jin5203344/article/details/78590111
在微服務大趨勢下Springboot,Springcloud成爲更多公司新項目技術框架的選型 ,Springboot簡潔的基本零配置,很重要的一點是將以前通過xml方式配置bean轉換爲
通過@Configuration @Bean的方式來進行,今天主要分析下Spring是如何來實現對這兩個註解進行處理的
通過Springboot的啓動來跟蹤分析容器的啓動(這裏只是簡單的帶過,後面會在springboot源碼分析中,詳細講解),run方法具體實現如下:
- public ConfigurableApplicationContext run(String... args) {
- if (this.running.get()) {
- // If already created we just return the existing context
- return this.context;
- }
- configureAsChildIfNecessary(args);
- if (this.running.compareAndSet(false, true)) {
- synchronized (this.running) {
- // 如果容器未啓動,啓動容器,裝配資源
- this.context = build().run(args);
- }
- }
- return this.context;
- }
- public ConfigurableApplicationContext run(String... args) {
- StopWatch stopWatch = new StopWatch();
- stopWatch.start();
- ConfigurableApplicationContext context = null;
- FailureAnalyzers analyzers = null;
- configureHeadlessProperty();
- SpringApplicationRunListeners listeners = getRunListeners(args);
- listeners.starting();
- try {
- ApplicationArguments applicationArguments = new DefaultApplicationArguments(
- args);
- ConfigurableEnvironment environment = prepareEnvironment(listeners,
- applicationArguments);
- Banner printedBanner = printBanner(environment);//打印beanner
- context = createApplicationContext();//創建默認的上下文
- analyzers = new FailureAnalyzers(context);
- prepareContext(context, environment, listeners, applicationArguments,
- printedBanner);
- refreshContext(context);// 刷新容器
- afterRefresh(context, applicationArguments);
- listeners.finished(context, null);
- stopWatch.stop();
- if (this.logStartupInfo) {
- new StartupInfoLogger(this.mainApplicationClass)
- .logStarted(getApplicationLog(), stopWatch);
- }
- return context;
- }
- catch (Throwable ex) {
- handleRunFailure(context, listeners, analyzers, ex);
- throw new IllegalStateException(ex);
- }
- }
重點關注refreshContext,在refreshContext中 就有第一篇中分析容器入口的refresh方法
- private void refreshContext(ConfigurableApplicationContext context) {
- refresh(context);
- if (this.registerShutdownHook) {
- try {
- context.registerShutdownHook();
- }
- catch (AccessControlException ex) {
- // Not allowed in some environments.
- }
- }
- }
事實上 我們分析的入口依然是refresh這個核心方法,這裏就不重複貼源碼了,這是我們之前loadBeanDefinitions換成 AnnotationConfigWebApplicationContext 類
AnnotationBeanDefinitionReader 對應構造函數 爲:
- public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
- Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
- Assert.notNull(environment, "Environment must not be null");
- this.registry = registry;
- this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
- AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
- }
可以看到 最後一行 註冊AnnotationConfigProcessors,有什麼用呢,接着看其實現:
- public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
- BeanDefinitionRegistry registry, Object source) {
-
- DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
- if (beanFactory != null) {
- if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
- beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
- }
- if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
- beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
- }
- }
-
- Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<BeanDefinitionHolder>(4);
- // 處理Configuration註解的 postProcessor
- if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
- RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
- def.setSource(source);
- beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
- }
- // 處理autowired註解的 postProcessor
- if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
- RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
- def.setSource(source);
- beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
- }
- // 處理required註解的 postProcessor
- if (!registry.containsBeanDefinition(REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
- RootBeanDefinition def = new RootBeanDefinition(RequiredAnnotationBeanPostProcessor.class);
- def.setSource(source);
- beanDefs.add(registerPostProcessor(registry, def, REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
- }
-
- // Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor.
- if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {
- RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
- def.setSource(source);
- beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
- }
-
- // Check for JPA support, and if present add the PersistenceAnnotationBeanPostProcessor.
- if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) {
- RootBeanDefinition def = new RootBeanDefinition();
- try {
- def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME,
- AnnotationConfigUtils.class.getClassLoader()));
- }
- catch (ClassNotFoundException ex) {
- throw new IllegalStateException(
- "Cannot load optional framework class: " + PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex);
- }
- def.setSource(source);
- beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME));
- }
-
- if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {
- RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);
- def.setSource(source);
- beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));
- }
- if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {
- RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);
- def.setSource(source);
- beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));
- }
-
- return beanDefs;
- }
這裏我們只用關係,configuration註解的處理,實際是向容器中接入了 對Configuration註解的 處理類 ConfigurationClassPostProcessor,
那我們有個疑問,這個類什麼時候會調用呢? 回到refresh方法中,有一行關鍵代碼
// Invoke factory processors registered as beans in the context. invokeBeanFactoryPostProcessors(beanFactory);
方法內容比較多,這裏就選取一個分支來說明下
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
// First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered. List<BeanDefinitionRegistryPostProcessor> priorityOrderedPostProcessors = new ArrayList<BeanDefinitionRegistryPostProcessor>();
for (String ppName : postProcessorNames) {
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
sortPostProcessors(beanFactory, priorityOrderedPostProcessors);
registryPostProcessors.addAll(priorityOrderedPostProcessors);
invokeBeanDefinitionRegistryPostProcessors(priorityOrderedPostProcessors, registry);
第一行:從工廠類中得到所有 BeanDefinitionRegistryPostProcessor類型的bean
第三——九行 循環判斷添加到 需要處理的列表中
第十二行:執行具體需要處理的postProcessors
具體實現如下:
private static void invokeBeanDefinitionRegistryPostProcessors(
Collection<? extends BeanDefinitionRegistryPostProcessor> postProcessors, BeanDefinitionRegistry registry) {
for (BeanDefinitionRegistryPostProcessor postProcessor : postProcessors) {
postProcessor.postProcessBeanDefinitionRegistry(registry);
}
}
也就是循環調用postProcessor的 postProcessBeanDefinitionRegistry方法,而ConfigurationClassPostProcessor類的對應方法內部調用邏輯順序
postProcessBeanDefinitionRegistry ——》 processConfigBeanDefinitions ——》
- // Parse each @Configuration class
- ConfigurationClassParser parser = new ConfigurationClassParser(
- this.metadataReaderFactory, this.problemReporter, this.environment,
- this.resourceLoader, this.componentScanBeanNameGenerator, registry);
-
- Set<BeanDefinitionHolder> candidates = new LinkedHashSet<BeanDefinitionHolder>(configCandidates);
- Set<ConfigurationClass> alreadyParsed = new HashSet<ConfigurationClass>(configCandidates.size());
- do {
- parser.parse(candidates);
- parser.validate();
- ....
- }while (!candidates.isEmpty());
從源碼註釋就能看出 是解析 @Configuration 註解的類 通過ConfigurationClassParser 來進行處理
parser ——》processConfigurationClass ——》doProcessConfigurationClass
- protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass) throws IOException {
- // 遞歸處理成員類
- processMemberClasses(configClass, sourceClass);
-
- // 處理 @PropertySource 註解
- for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
- sourceClass.getMetadata(), PropertySources.class, org.springframework.context.annotation.PropertySource.class)) {
- if (this.environment instanceof ConfigurableEnvironment) {
- processPropertySource(propertySource);
- }
- else {
- logger.warn("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
- "]. Reason: Environment must implement ConfigurableEnvironment");
- }
- }
-
- // 處理 @ComponentScan 註解
- AnnotationAttributes componentScan = AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ComponentScan.class);
- if (componentScan != null && !this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
- // The config class is annotated with @ComponentScan -> perform the scan immediately
- Set<BeanDefinitionHolder> scannedBeanDefinitions =
- this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
- // Check the set of scanned definitions for any further config classes and parse recursively if necessary
- for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
- if (ConfigurationClassUtils.checkConfigurationClassCandidate(holder.getBeanDefinition(), this.metadataReaderFactory)) {
- parse(holder.getBeanDefinition().getBeanClassName(), holder.getBeanName());
- }
- }
- }
-
- // 處理 @Import 註解
- processImports(configClass, sourceClass, getImports(sourceClass), true);
-
- // 處理 @ImportResource 註解
- if (sourceClass.getMetadata().isAnnotated(ImportResource.class.getName())) {
- AnnotationAttributes importResource = AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
- String[] resources = importResource.getAliasedStringArray("locations", ImportResource.class, sourceClass);
- Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
- for (String resource : resources) {
- String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
- configClass.addImportedResource(resolvedResource, readerClass);
- }
- }
-
- // 處理 @Bean 註解
- Set<MethodMetadata> beanMethods = sourceClass.getMetadata().getAnnotatedMethods(Bean.class.getName());
- for (MethodMetadata methodMetadata : beanMethods) {
- configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
- }
-
- // 處理接口中默認方法
- for (SourceClass ifc : sourceClass.getInterfaces()) {
- beanMethods = ifc.getMetadata().getAnnotatedMethods(Bean.class.getName());
- for (MethodMetadata methodMetadata : beanMethods) {
- if (!methodMetadata.isAbstract()) {
- // A default method or other concrete method on a Java 8+ interface...
- configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
- }
- }
- }
-
- // 處理父類
- if (sourceClass.getMetadata().hasSuperClass()) {
- String superclass = sourceClass.getMetadata().getSuperClassName();
- if (!superclass.startsWith("java") && !this.knownSuperclasses.containsKey(superclass)) {
- this.knownSuperclasses.put(superclass, configClass);
- // Superclass found, return its annotation metadata and recurse
- return sourceClass.getSuperClass();
- }
- }
-
- // No superclass -> processing is complete
- return null;
- }
其他註解的處理這裏暫且不作分析,後面有機會再補上,有興趣的讀者可以自行查看源碼學習,原理都差不多,解析到對於的信息添加到configClass中
可以看到通過解析@Bean註解,獲取到所有帶有@Bean註解的方法,創建對應的BeanMethod添加到configClass中,回到processConfigBeanDefinitions方法
this.reader.loadBeanDefinitions(configClasses);
通過configClasses加載bean定義
查看具體實現
public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {
TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();
for (ConfigurationClass configClass : configurationModel) {
loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);
}
}
循環加載
private void loadBeanDefinitionsForConfigurationClass(ConfigurationClass configClass,
TrackedConditionEvaluator trackedConditionEvaluator) {
if (trackedConditionEvaluator.shouldSkip(configClass)) {
String beanName = configClass.getBeanName();
if (StringUtils.hasLength(beanName) && this.registry.containsBeanDefinition(beanName)) {
this.registry.removeBeanDefinition(beanName);
}
this.importRegistry.removeImportingClassFor(configClass.getMetadata().getClassName());
return;
}
if (configClass.isImported()) {
registerBeanDefinitionForImportedConfigurationClass(configClass);
}
// 循環加載 beanMethod
for (BeanMethod beanMethod : configClass.getBeanMethods()) {
loadBeanDefinitionsForBeanMethod(beanMethod);
}
loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
}
loadBeanDefinitionsForBeanMethod 字面意思 爲beanMethod加載beanDefinition
private void loadBeanDefinitionsForBeanMethod(BeanMethod beanMethod) {
ConfigurationClass configClass = beanMethod.getConfigurationClass();
MethodMetadata metadata = beanMethod.getMetadata();
String methodName = metadata.getMethodName();
// Do we need to mark the bean as skipped by its condition? if (this.conditionEvaluator.shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN)) {
configClass.skippedBeanMethods.add(methodName);
return;
}
if (configClass.skippedBeanMethods.contains(methodName)) {
return;
}
// Consider name and any aliases AnnotationAttributes bean = AnnotationConfigUtils.attributesFor(metadata, Bean.class);
List<String> names = new ArrayList<String>(Arrays.asList(bean.getStringArray("name")));
String beanName = (names.size() > 0 ? names.remove(0) : methodName);
// Register aliases even when overridden for (String alias : names) {
this.registry.registerAlias(beanName, alias);
}
// Has this effectively been overridden before (e.g. via XML)? if (isOverriddenByExistingDefinition(beanMethod, beanName)) {
return;
}
ConfigurationClassBeanDefinition beanDef = new ConfigurationClassBeanDefinition(configClass, metadata);
beanDef.setResource(configClass.getResource());
beanDef.setSource(this.sourceExtractor.extractSource(metadata, configClass.getResource()));
if (metadata.isStatic()) {
// static @Bean method beanDef.setBeanClassName(configClass.getMetadata().getClassName());
beanDef.setFactoryMethodName(methodName);
}
else {
// instance @Bean method beanDef.setFactoryBeanName(configClass.getBeanName());
beanDef.setUniqueFactoryMethodName(methodName);
}
beanDef.setAutowireMode(RootBeanDefinition.AUTOWIRE_CONSTRUCTOR);
beanDef.setAttribute(RequiredAnnotationBeanPostProcessor.SKIP_REQUIRED_CHECK_ATTRIBUTE, Boolean.TRUE);
AnnotationConfigUtils.processCommonDefinitionAnnotations(beanDef, metadata);
Autowire autowire = bean.getEnum("autowire");
if (autowire.isAutowire()) {
beanDef.setAutowireMode(autowire.value());
}
String initMethodName = bean.getString("initMethod");
if (StringUtils.hasText(initMethodName)) {
beanDef.setInitMethodName(initMethodName);
}
String destroyMethodName = bean.getString("destroyMethod");
if (destroyMethodName != null) {
beanDef.setDestroyMethodName(destroyMethodName);
}
// Consider scoping ScopedProxyMode proxyMode = ScopedProxyMode.NO;
AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(metadata, Scope.class);
if (attributes != null) {
beanDef.setScope(attributes.getAliasedString("value", Scope.class, configClass.getResource()));
proxyMode = attributes.getEnum("proxyMode");
if (proxyMode == ScopedProxyMode.DEFAULT) {
proxyMode = ScopedProxyMode.NO;
}
}
// Replace the original bean definition with the target one, if necessary BeanDefinition beanDefToRegister = beanDef;
if (proxyMode != ScopedProxyMode.NO) {
BeanDefinitionHolder proxyDef = ScopedProxyCreator.createScopedProxy(
new BeanDefinitionHolder(beanDef, beanName), this.registry, proxyMode == ScopedProxyMode.TARGET_CLASS);
beanDefToRegister = new ConfigurationClassBeanDefinition(
(RootBeanDefinition) proxyDef.getBeanDefinition(), configClass, metadata);
}
if (logger.isDebugEnabled()) {
logger.debug(String.format("Registering bean definition for @Bean method %s.%s()",
configClass.getMetadata().getClassName(), beanName));
}
this.registry.registerBeanDefinition(beanName, beanDefToRegister);
}
通過元數據以及相關信息 裝配 註冊beanDefinition