欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

SpringBoot注解@Import原理之關(guān)于ConfigurationClassPostProcessor源碼解析

 更新時(shí)間:2024年07月18日 14:18:29   作者:談?wù)?974  
這篇文章主要介紹了SpringBoot注解@Import原理之關(guān)于ConfigurationClassPostProcessor源碼解析,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

1. @Import 介紹

1.1 @Import 的作用

Spring 中將一個(gè)普通類交給容器管理除了使用 @Bean@Component等注解再使用 @ComponentScan 掃描包之外,還可以使用 @Import 注解

@Import只能用在類或者其他注解上 ,該注解能夠方便快速地實(shí)現(xiàn)把實(shí)例加入到 Spring 的 IOC 容器中,可用于導(dǎo)入第三方包

1.2 @Import 的使用方式

@Import 可以快速導(dǎo)入目標(biāo)類,其主要有以下幾種用法:

  • 直接填寫 class 數(shù)組,導(dǎo)入目標(biāo)類
  • 導(dǎo)入實(shí)現(xiàn) ImportSelector 接口的類
  • 導(dǎo)入實(shí)現(xiàn) ImportBeanDefinitionRegistrar 接口的類
1.2.1 直接導(dǎo)入目標(biāo)類

這種方式直接在@Import中指定 class 數(shù)組,Spring 會(huì)在啟動(dòng)過程把 @Import 中配置的 bean 直接導(dǎo)入到 Spring 容器中,其 beanName 為類的全限定名,使用方法如下:

@Import({ abc.class , abd.class... })
public class Config {
}
1.2.2 導(dǎo)入實(shí)現(xiàn) ImportSelector 接口的類

ImportSelector是一個(gè)導(dǎo)入的選擇器,可以通過這個(gè)接口的實(shí)現(xiàn)決定引入哪些配置。

@EnableAsync上通過@Import導(dǎo)入的 AsyncConfigurationSelector 為例,Spring 容器會(huì)在啟動(dòng)過程中實(shí)例化該選擇器并調(diào)用其selectImports()方法。

AsyncConfigurationSelector#selectImports() 根據(jù) @EnableAsync 中指定的模式選擇對(duì)應(yīng)的配置類,默認(rèn)代理模式,則導(dǎo)入指定的 ProxyAsyncConfiguration配置類

public class AsyncConfigurationSelector extends AdviceModeImportSelector<EnableAsync> {

	private static final String ASYNC_EXECUTION_ASPECT_CONFIGURATION_CLASS_NAME =
			"org.springframework.scheduling.aspectj.AspectJAsyncConfiguration";
			
	@Override
	@Nullable
	public String[] selectImports(AdviceMode adviceMode) {
		switch (adviceMode) {
			case PROXY:
				return new String[] {ProxyAsyncConfiguration.class.getName()};
			case ASPECTJ:
				return new String[] {ASYNC_EXECUTION_ASPECT_CONFIGURATION_CLASS_NAME};
			default:
				return null;
		}
	}

}
1.2.3 導(dǎo)入實(shí)現(xiàn) ImportBeanDefinitionRegistrar 接口的類

ImportBeanDefinitionRegistrar 是一個(gè) bean 定義注冊(cè)器,以 @EnableAspectJAutoProxy注解通過 @Import(AspectJAutoProxyRegistrar.class) 引入了注冊(cè)類 AspectJAutoProxyRegistrar 為例,在框架啟動(dòng)過程中會(huì)回調(diào)其實(shí)現(xiàn)的接口方法 AspectJAutoProxyRegistrar#registerBeanDefinitions()方法將目標(biāo) bean 注冊(cè)到容器中

class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {

	@Override
	public void registerBeanDefinitions(
			AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {

		AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);

		AnnotationAttributes enableAspectJAutoProxy =
				AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
		if (enableAspectJAutoProxy != null) {
			if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
				AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
			}
			if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
				AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
			}
		}
	}

2. @Import 注冊(cè)目標(biāo)類的流程

以下流程圖以 @EnableAsync 注解使用 @Import 導(dǎo)入 AsyncConfigurationSelector 為例子,全流程展現(xiàn)了@Import 導(dǎo)入的類被解析為 BeanDefinition 并注冊(cè)到 Spring 容器中過程,以及 @Async注解核心原理。

簡(jiǎn)單來說,整個(gè)過程總共分為以下幾步:

  • 配置解析類ConfigurationClassPostProcessor的注冊(cè)
  • ConfigurationClassPostProcessor 解析配置類,并將其注冊(cè)到容器
  • BeanPostProcessor 后置處理器對(duì)象的優(yōu)先創(chuàng)建
  • @Async 異步任務(wù)代理對(duì)象的生成及其生效原理

2.1 配置解析類ConfigurationClassPostProcessor的注冊(cè)

SpringApplication#run() 方法為框架啟動(dòng)的入口,啟動(dòng)過程中 prepareContext() 方法會(huì)為 Context 準(zhǔn)備必要的組件,其中就包括 ConfigurationClassPostProcessor 的注冊(cè)

public ConfigurableApplicationContext run(String... args) {
 	
 	......
 	
 	try {
 		ApplicationArguments applicationArguments = new DefaultApplicationArguments(
 				args);
 		ConfigurableEnvironment environment = prepareEnvironment(listeners,
 				applicationArguments);
 		configureIgnoreBeanInfo(environment);
 		Banner printedBanner = printBanner(environment);
 		context = createApplicationContext();
 		exceptionReporters = getSpringFactoriesInstances(
 				SpringBootExceptionReporter.class,
 				new Class[] { ConfigurableApplicationContext.class }, context);
 		prepareContext(context, environment, listeners, applicationArguments,
 				printedBanner);
 		refreshContext(context);
 		afterRefresh(context, applicationArguments);
 		stopWatch.stop();
 		
 	......
 	
 	return context;
 }

SpringApplication#prepareContext() 中會(huì)調(diào)用 SpringApplication#load() 將必要的組件加載進(jìn)容器中,以下為 load() 方法實(shí)現(xiàn),可以看到方法內(nèi)部調(diào)用了 createBeanDefinitionLoader() 方法

protected void load(ApplicationContext context, Object[] sources) {
 	if (logger.isDebugEnabled()) {
 		logger.debug(
 				"Loading source " + StringUtils.arrayToCommaDelimitedString(sources));
 	}
 	BeanDefinitionLoader loader = createBeanDefinitionLoader(
 			getBeanDefinitionRegistry(context), sources);
 	if (this.beanNameGenerator != null) {
 		loader.setBeanNameGenerator(this.beanNameGenerator);
 	}
 	if (this.resourceLoader != null) {
 		loader.setResourceLoader(this.resourceLoader);
 	}
 	if (this.environment != null) {
 		loader.setEnvironment(this.environment);
 	}
 	loader.load();
 }

SpringApplication#createBeanDefinitionLoader() 會(huì)創(chuàng)建 BeanDefinition 的加載器,最終創(chuàng)建的對(duì)象為 BeanDefinitionLoader

protected BeanDefinitionLoader createBeanDefinitionLoader(
		BeanDefinitionRegistry registry, Object[] sources) {
	return new BeanDefinitionLoader(registry, sources);
}

BeanDefinitionLoader 的構(gòu)造方法中會(huì)初始化一系列的組件,其中包括了 AnnotatedBeanDefinitionReader

BeanDefinitionLoader(BeanDefinitionRegistry registry, Object... sources) {
 	Assert.notNull(registry, "Registry must not be null");
 	Assert.notEmpty(sources, "Sources must not be empty");
 	this.sources = sources;
 	this.annotatedReader = new AnnotatedBeanDefinitionReader(registry);
 	this.xmlReader = new XmlBeanDefinitionReader(registry);
 	if (isGroovyPresent()) {
 		this.groovyReader = new GroovyBeanDefinitionReader(registry);
 	}
 	this.scanner = new ClassPathBeanDefinitionScanner(registry);
 	this.scanner.addExcludeFilter(new ClassExcludeFilter(sources));
 }

AnnotatedBeanDefinitionReader 的構(gòu)造方法會(huì)通過工具類AnnotationConfigUtils#registerAnnotationConfigProcessors()注冊(cè)注解配置的處理器

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);
 }

AnnotationConfigUtils#registerAnnotationConfigProcessors() 方法會(huì)注冊(cè)許多 Spring 必須的處理器,本文主要關(guān)注 ConfigurationClassPostProcessor 這個(gè)配置類的后置處理器,可以看到此時(shí)已經(jīng)將其包裝到 BeanDefinition中了

public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
 		BeanDefinitionRegistry registry, @Nullable Object source) {
    ......

 	Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);

 	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));
 	}
    ......

 	return beanDefs;
 }

2.2 ConfigurationClassPostProcessor 解析配置類

Context 準(zhǔn)備完畢,會(huì)調(diào)用 SpringAppliction#refreshContext() 方法,最終調(diào)用到著名的 AbstractApplicationContext#refresh() 方法。

該方法體內(nèi)各個(gè)方法的作用可參考Spring啟動(dòng)流程源碼解析,本文主要關(guān)注 invokeBeanFactoryPostProcessors()方法

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();
 		}

 		......
 	}
 }

AbstractApplicationContext#invokeBeanFactoryPostProcessors()方法會(huì)調(diào)用 PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors() 方法,這個(gè)方法的源碼如下,可以看到其主要做了以下幾件事:

  • 從 bean 工廠中獲取所有實(shí)現(xiàn) BeanFactoryPostProcessor 接口的 bean 名稱
  • 通過 beanFactory.getBean() 去創(chuàng)建注冊(cè)到容器中的 BeanFactoryPostProcessor 實(shí)例
  • 通過 invokeBeanFactoryPostProcessors() 方法調(diào)用 BeanFactoryPostProcessor 接口方法
public static void invokeBeanFactoryPostProcessors(
 		ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
     
     ......
 	
 	// Do not initialize FactoryBeans here: We need to leave all regular beans
 	// uninitialized to let the bean factory post-processors apply to them!
 	String[] postProcessorNames =
 			beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);

 	// Separate between BeanFactoryPostProcessors that implement PriorityOrdered,
 	// Ordered, and the rest.
 	List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
 	List<String> orderedPostProcessorNames = new ArrayList<>();
 	List<String> nonOrderedPostProcessorNames = new ArrayList<>();
 	for (String ppName : postProcessorNames) {
 		if (processedBeans.contains(ppName)) {
 			// skip - already processed in first phase above
 		}
 		else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
 			priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
 		}
 		else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
 			orderedPostProcessorNames.add(ppName);
 		}
 		else {
 			nonOrderedPostProcessorNames.add(ppName);
 		}
 	}

 	// First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered.
 	sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
 	invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);

 	// Next, invoke the BeanFactoryPostProcessors that implement Ordered.
 	List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>();
 	for (String postProcessorName : orderedPostProcessorNames) {
 		orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
 	}
 	sortPostProcessors(orderedPostProcessors, beanFactory);
 	invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);

 	// Finally, invoke all other BeanFactoryPostProcessors.
 	List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>();
 	for (String postProcessorName : nonOrderedPostProcessorNames) {
 		nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
 	}
 	invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);

 	// Clear cached merged bean definitions since the post-processors might have
 	// modified the original metadata, e.g. replacing placeholders in values...
 	beanFactory.clearMetadataCache();
 }

ConfigurationClassPostProcessor 已經(jīng)完成注冊(cè),且實(shí)現(xiàn)了 BeanFactoryPostProcessor 接口,則經(jīng)過步驟 2 ConfigurationClassPostProcessor#postProcessBeanFactory() 方法將被調(diào)用,可以看到方法內(nèi)部核心其實(shí)是ConfigurationClassPostProcessor#processConfigBeanDefinitions() 方法

public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
 	int factoryId = System.identityHashCode(beanFactory);
 	if (this.factoriesPostProcessed.contains(factoryId)) {
 		throw new IllegalStateException(
 				"postProcessBeanFactory already called on this post-processor against " + beanFactory);
 	}
 	this.factoriesPostProcessed.add(factoryId);
 	if (!this.registriesPostProcessed.contains(factoryId)) {
 		// BeanDefinitionRegistryPostProcessor hook apparently not supported...
 		// Simply call processConfigurationClasses lazily at this point then.
 		processConfigBeanDefinitions((BeanDefinitionRegistry) beanFactory);
 	}

 	enhanceConfigurationClasses(beanFactory);
 	beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
 }

ConfigurationClassPostProcessor#processConfigBeanDefinitions() 方法,其內(nèi)部比較重要的步驟如下:

  • 生成 ConfigurationClassParser 對(duì)象并調(diào)用其 parse() 方法用于解析配置類,緩存其配置的 Bean
  • 使用 ConfigurationClassBeanDefinitionReader 對(duì)象調(diào)用其 loadBeanDefinitions() 將配置類中的 Bean 注冊(cè)到容器中
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {

 	......
 	
 	// Parse each @Configuration class
 	ConfigurationClassParser parser = new ConfigurationClassParser(
 			this.metadataReaderFactory, this.problemReporter, this.environment,
 			this.resourceLoader, this.componentScanBeanNameGenerator, registry);

 	Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
 	Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
 	do {
 		parser.parse(candidates);
 		parser.validate();

 		Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
 		configClasses.removeAll(alreadyParsed);

 		// Read the model and create bean definitions based on its content
 		if (this.reader == null) {
 			this.reader = new ConfigurationClassBeanDefinitionReader(
 					registry, this.sourceExtractor, this.resourceLoader, this.environment,
 					this.importBeanNameGenerator, parser.getImportRegistry());
 		}
 		this.reader.loadBeanDefinitions(configClasses);
 		alreadyParsed.addAll(configClasses);

 		candidates.clear();
 		if (registry.getBeanDefinitionCount() > candidateNames.length) {
 			String[] newCandidateNames = registry.getBeanDefinitionNames();
 			Set<String> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames));
 			Set<String> alreadyParsedClasses = new HashSet<>();
 			for (ConfigurationClass configurationClass : alreadyParsed) {
 				alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
 			}
 			for (String candidateName : newCandidateNames) {
 				if (!oldCandidateNames.contains(candidateName)) {
 					BeanDefinition bd = registry.getBeanDefinition(candidateName);
 					if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&
 							!alreadyParsedClasses.contains(bd.getBeanClassName())) {
 						candidates.add(new BeanDefinitionHolder(bd, candidateName));
 					}
 				}
 			}
 			candidateNames = newCandidateNames;
 		}
 	}
 	while (!candidates.isEmpty());

 	// Register the ImportRegistry as a bean in order to support ImportAware @Configuration classes
 	if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
 		sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
 	}

 	if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {
 		// Clear cache in externally provided MetadataReaderFactory; this is a no-op
 		// for a shared cache since it'll be cleared by the ApplicationContext.
 		((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache();
 	}
 }

ConfigurationClassParser#parse() 方法是解析配置類的核心入口,其最終調(diào)用到了 ConfigurationClassParser#processConfigurationClass()方法。

這個(gè)方法主要處理邏輯是調(diào)用 doProcessConfigurationClass()解析配置類,并將解析得到的 Bean 緩存在 Map 集合 configurationClasses 中供后續(xù)注冊(cè)使用

protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
 	if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
 		return;
 	}

 	ConfigurationClass existingClass = this.configurationClasses.get(configClass);
 	if (existingClass != null) {
 		if (configClass.isImported()) {
 			if (existingClass.isImported()) {
 				existingClass.mergeImportedBy(configClass);
 			}
 			// Otherwise ignore new imported config class; existing non-imported class overrides it.
 			return;
 		}
 		else {
 			// Explicit bean definition found, probably replacing an import.
 			// Let's remove the old one and go with the new one.
 			this.configurationClasses.remove(configClass);
 			this.knownSuperclasses.values().removeIf(configClass::equals);
 		}
 	}

 	// Recursively process the configuration class and its superclass hierarchy.
 	SourceClass sourceClass = asSourceClass(configClass);
 	do {
 		sourceClass = doProcessConfigurationClass(configClass, sourceClass);
 	}
 	while (sourceClass != null);

 	this.configurationClasses.put(configClass, configClass);
 }

ConfigurationClassParser#doProcessConfigurationClass() 是解析配置的核心方法,其主要的處理步驟如下,本文主要關(guān)注 processImports() 處理 @Import 注解引入 Bean 的流程

  • processMemberClasses() 處理內(nèi)部類
  • processPropertySource() 處理加了@PropertySource 注解的屬性資源文件
  • 解析出類上的@ComponentScan和@ComponentScans注解,然后根據(jù)其配置包路徑掃描出所有需要交給Spring管理的類,因?yàn)閽呙璩龅念愔锌赡芤脖患恿薂ComponentScan和@ComponentScans注解,因此需進(jìn)行遞歸解析,直到所有標(biāo)注了這兩個(gè)注解的類被解析完畢
  • processImports() 處理通過 @Import注解配置的 Bean
  • 處理 @ImportResource 注解標(biāo)注的配置文件
  • doProcessConfigurationClass() 會(huì)被遞歸調(diào)用,則最終會(huì)處理配置類中加了@Bean 注解的方法
  • processInterfaces() 處理接口的默認(rèn)方法。從JDK8開始,接口中的方法可以有自己的默認(rèn)實(shí)現(xiàn)如果這個(gè)接口中的方法也加了@Bean注解,也需要被解析
  • 解析父類,如果被解析的配置類繼承了某個(gè)類,那么配置類的父類也會(huì)被進(jìn)行解析(父類是全類名以 java 開頭的JDK內(nèi)置的類例外)
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
 		throws IOException {

 	if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
 		// Recursively process any member (nested) classes first
 		processMemberClasses(configClass, sourceClass);
 	}

 	// Process any @PropertySource annotations
 	for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
 			sourceClass.getMetadata(), PropertySources.class,
 			org.springframework.context.annotation.PropertySource.class)) {
 		if (this.environment instanceof ConfigurableEnvironment) {
 			processPropertySource(propertySource);
 		}
 		else {
 			logger.info("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
 					"]. Reason: Environment must implement ConfigurableEnvironment");
 		}
 	}

 	// Process any @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) {
 			// 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 needed
 			for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
 				BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
 				if (bdCand == null) {
 					bdCand = holder.getBeanDefinition();
 				}
 				if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
 					parse(bdCand.getBeanClassName(), holder.getBeanName());
 				}
 			}
 		}
 	}

 	// Process any @Import annotations
 	processImports(configClass, sourceClass, getImports(sourceClass), true);

 	// Process any @ImportResource annotations
 	AnnotationAttributes importResource =
 			AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
 	if (importResource != null) {
 		String[] resources = importResource.getStringArray("locations");
 		Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
 		for (String resource : resources) {
 			String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
 			configClass.addImportedResource(resolvedResource, readerClass);
 		}
 	}

 	// Process individual @Bean methods
 	Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
 	for (MethodMetadata methodMetadata : beanMethods) {
 		configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
 	}

 	// Process default methods on interfaces
 	processInterfaces(configClass, sourceClass);

 	// Process superclass, if any
 	if (sourceClass.getMetadata().hasSuperClass()) {
 		String superclass = sourceClass.getMetadata().getSuperClassName();
 		if (superclass != null && !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;
 }

ConfigurationClassParser#processImports() 方法主要處理 3 種類型的 Bean:

  • ImportSelector 接口的實(shí)現(xiàn)
  • 實(shí)例化這個(gè)類的對(duì)象,然后調(diào)用其 selectImports() 方法去獲得所需要的引入的配置類, 然后調(diào)用 processImports() 遞歸處理
  • ImportBeanDefinitionRegistrar 接口的實(shí)現(xiàn)
  • 實(shí)例化這個(gè)類的對(duì)象,將其添加到緩存到 Map 集合中
  • 普通類
  • 把它當(dāng)作 @Configuration 標(biāo)注的類調(diào)用最外層的processConfigurationClass()繼續(xù)處理
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
 		Collection<SourceClass> importCandidates, boolean checkForCircularImports) {

 	if (importCandidates.isEmpty()) {
 		return;
 	}

 	if (checkForCircularImports && isChainedImportOnStack(configClass)) {
 		this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
 	}
 	else {
 		this.importStack.push(configClass);
 		try {
 			for (SourceClass candidate : importCandidates) {
 				if (candidate.isAssignable(ImportSelector.class)) {
 					// Candidate class is an ImportSelector -> delegate to it to determine imports
 					Class<?> candidateClass = candidate.loadClass();
 					ImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class);
 					ParserStrategyUtils.invokeAwareMethods(
 							selector, this.environment, this.resourceLoader, this.registry);
 					if (selector instanceof DeferredImportSelector) {
 						this.deferredImportSelectorHandler.handle(
 								configClass, (DeferredImportSelector) selector);
 					}
 					else {
 						String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
 						Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);
 						processImports(configClass, currentSourceClass, importSourceClasses, false);
 					}
 				}
 				else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
 					// Candidate class is an ImportBeanDefinitionRegistrar ->
 					// delegate to it to register additional bean definitions
 					Class<?> candidateClass = candidate.loadClass();
 					ImportBeanDefinitionRegistrar registrar =
 							BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class);
 					ParserStrategyUtils.invokeAwareMethods(
 							registrar, this.environment, this.resourceLoader, this.registry);
 					configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
 				}
 				else {
 					// Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar ->
 					// process it as an @Configuration class
 					this.importStack.registerImport(
 							currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
 					processConfigurationClass(candidate.asConfigClass(configClass));
 				}
 			}
 		}
 		catch (BeanDefinitionStoreException ex) {
 			throw ex;
 		}
 		catch (Throwable ex) {
 			throw new BeanDefinitionStoreException(
 					"Failed to process import candidates for configuration class [" +
 					configClass.getMetadata().getClassName() + "]", ex);
 		}
 		finally {
 			this.importStack.pop();
 		}
 	}
 }

經(jīng)過步驟5-7處理,引入的類都被解析完畢,接下來則會(huì)調(diào)用 ConfigurationClassBeanDefinitionReader#loadBeanDefinitions() 將配置類中的解析出來的 Bean 注冊(cè)到容器中

從代碼來看,其實(shí)核心是 loadBeanDefinitionsForConfigurationClass() 方法完成注冊(cè)工作,這里主要把需要注冊(cè)的類分為了以下 4 類。

通過這個(gè)步驟,@EnableAsync 注解上經(jīng) @Import 導(dǎo)入的 AsyncConfigurationSelector 選擇器選中的配置類 ProxyAsyncConfiguration 注冊(cè)到了容器中,并且這個(gè)配置類內(nèi)部配置的AsyncAnnotationBeanPostProcessor 也注冊(cè)到了容器中

  • 被 @Configuration 標(biāo)注的配置類或者 @Import 導(dǎo)入的普通類
  • 被 @Bean 標(biāo)注的方法配置的類
  • 被 @ImportResource 導(dǎo)入的類
  • 被 @Import 導(dǎo)入的 ImportBeanDefinitionRegistrar 接口實(shí)現(xiàn)類
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.removeImportingClass(configClass.getMetadata().getClassName());
 		return;
 	}

 	if (configClass.isImported()) {
 		registerBeanDefinitionForImportedConfigurationClass(configClass);
 	}
 	for (BeanMethod beanMethod : configClass.getBeanMethods()) {
 		loadBeanDefinitionsForBeanMethod(beanMethod);
 	}

 	loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
 	loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
 }

2.3 BeanPostProcessor 后置處理器對(duì)象的優(yōu)先創(chuàng)建

容器啟動(dòng)過程中AbstractApplicationContext#invokeBeanFactoryPostProcessors() 準(zhǔn)備 Bean 工廠的后置處理器完畢,就需要調(diào)用 AbstractApplicationContext#registerBeanPostProcessors() 將 Bean 的后置處理器注冊(cè)到容器中了。

這個(gè)過程通過 PostProcessorRegistrationDelegate.registerBeanPostProcessors() 方法完成,其流程與 Bean 工廠后置處理器的注冊(cè)大致相同:

  • 首先 beanFactory.getBeanNamesForType() 獲取所有實(shí)現(xiàn) BeanPostProcessor 接口的類名數(shù)組
  • beanFactory.getBean() 創(chuàng)建 BeanPostProcessor 實(shí)例
  • registerBeanPostProcessors() 將 BeanPostProcessor 實(shí)例保存下來,在創(chuàng)建 Bean 的時(shí)候根據(jù)匹配規(guī)則確定某個(gè) BeanPostProcessor 是否需應(yīng)用于創(chuàng)建 Bean 代理對(duì)象
public static void registerBeanPostProcessors(
 		ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {

 	String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);
     
     ......
 	
 	// Now, register all regular BeanPostProcessors.
 	List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<>();
 	for (String ppName : nonOrderedPostProcessorNames) {
 		BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
 		nonOrderedPostProcessors.add(pp);
 		if (pp instanceof MergedBeanDefinitionPostProcessor) {
 			internalPostProcessors.add(pp);
 		}
 	}
 	registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);

 	// Finally, re-register all internal BeanPostProcessors.
 	sortPostProcessors(internalPostProcessors, beanFactory);
 	registerBeanPostProcessors(beanFactory, internalPostProcessors);

 	// Re-register post-processor for detecting inner beans as ApplicationListeners,
 	// moving it to the end of the processor chain (for picking up proxies etc).
 	beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
 }

此處著重分析beanFactory.getBean() Bean 工廠創(chuàng)建 BeanPostProcessor 對(duì)象的過程,追蹤代碼容易得知獲取 Bean 調(diào)用到了 AbstractBeanFactory#doGetBean() 方法。

這個(gè)方法很長(zhǎng),本文主要分析流程主干,也就是 createBean() 抽象方法

protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
 		@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
        
        ......
 		
 		// Check if bean definition exists in this factory.
 		BeanFactory parentBeanFactory = getParentBeanFactory();
 		if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
 			// Not found -> check parent.
 			String nameToLookup = originalBeanName(name);
 			if (parentBeanFactory instanceof AbstractBeanFactory) {
 				return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
 						nameToLookup, requiredType, args, typeCheckOnly);
 			}
 			else if (args != null) {
 				// Delegation to parent with explicit args.
 				return (T) parentBeanFactory.getBean(nameToLookup, args);
 			}
 			else if (requiredType != null) {
 				// No args -> delegate to standard getBean method.
 				return parentBeanFactory.getBean(nameToLookup, requiredType);
 			}
 			else {
 				return (T) parentBeanFactory.getBean(nameToLookup);
 			}
 		}

 		if (!typeCheckOnly) {
 			markBeanAsCreated(beanName);
 		}

 		try {
 			final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
 			checkMergedBeanDefinition(mbd, beanName, args);

 			// Guarantee initialization of beans that the current bean depends on.
 			String[] dependsOn = mbd.getDependsOn();
 			if (dependsOn != null) {
 				for (String dep : dependsOn) {
 					if (isDependent(beanName, dep)) {
 						throw new BeanCreationException(mbd.getResourceDescription(), beanName,
 								"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
 					}
 					registerDependentBean(dep, beanName);
 					try {
 						getBean(dep);
 					}
 					catch (NoSuchBeanDefinitionException ex) {
 						throw new BeanCreationException(mbd.getResourceDescription(), beanName,
 								"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
 					}
 				}
 			}

 			// Create bean instance.
 			if (mbd.isSingleton()) {
 				sharedInstance = getSingleton(beanName, () -> {
 					try {
 						return createBean(beanName, mbd, args);
 					}
 					catch (BeansException ex) {
 						// Explicitly remove instance from singleton cache: It might have been put there
 						// eagerly by the creation process, to allow for circular reference resolution.
 						// Also remove any beans that received a temporary reference to the bean.
 						destroySingleton(beanName);
 						throw ex;
 					}
 				});
 				bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
 			}

 			else if (mbd.isPrototype()) {
 				// It's a prototype -> create a new instance.
 				Object prototypeInstance = null;
 				try {
 					beforePrototypeCreation(beanName);
 					prototypeInstance = createBean(beanName, mbd, args);
 				}
 				finally {
 					afterPrototypeCreation(beanName);
 				}
 				bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
 			}

 			else {
 				String scopeName = mbd.getScope();
 				final Scope scope = this.scopes.get(scopeName);
 				if (scope == null) {
 					throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
 				}
 				try {
 					Object scopedInstance = scope.get(beanName, () -> {
 						beforePrototypeCreation(beanName);
 						try {
 							return createBean(beanName, mbd, args);
 						}
 						finally {
 							afterPrototypeCreation(beanName);
 						}
 					});
 					bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
 				}
 				catch (IllegalStateException ex) {
 					throw new BeanCreationException(beanName,
 							"Scope '" + scopeName + "' is not active for the current thread; consider " +
 							"defining a scoped proxy for this bean if you intend to refer to it from a singleton",
 							ex);
 				}
 			}
 		}
 		catch (BeansException ex) {
 			cleanupAfterBeanCreationFailure(beanName);
 			throw ex;
 		}
 	}

 	......
 	
 	return (T) bean;
 }

AbstractAutowireCapableBeanFactory#createBean() 方法中會(huì)調(diào)用 doCreateBean() 方法去創(chuàng)建 Bean 對(duì)象

protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
 		throws BeanCreationException {

 	if (logger.isTraceEnabled()) {
 		logger.trace("Creating instance of bean '" + beanName + "'");
 	}
 	RootBeanDefinition mbdToUse = mbd;

 	// Make sure bean class is actually resolved at this point, and
 	// clone the bean definition in case of a dynamically resolved Class
 	// which cannot be stored in the shared merged bean definition.
 	Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
 	if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
 		mbdToUse = new RootBeanDefinition(mbd);
 		mbdToUse.setBeanClass(resolvedClass);
 	}

 	// Prepare method overrides.
 	try {
 		mbdToUse.prepareMethodOverrides();
 	}
 	catch (BeanDefinitionValidationException ex) {
 		throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
 				beanName, "Validation of method overrides failed", ex);
 	}

 	try {
 		// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
 		Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
 		if (bean != null) {
 			return bean;
 		}
 	}
 	catch (Throwable ex) {
 		throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
 				"BeanPostProcessor before instantiation of bean failed", ex);
 	}

 	try {
 		Object beanInstance = doCreateBean(beanName, mbdToUse, args);
 		if (logger.isTraceEnabled()) {
 			logger.trace("Finished creating instance of bean '" + beanName + "'");
 		}
 		return beanInstance;
 	}
 	catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
 		// A previously detected exception with proper bean creation context already,
 		// or illegal singleton state to be communicated up to DefaultSingletonBeanRegistry.
 		throw ex;
 	}
 	catch (Throwable ex) {
 		throw new BeanCreationException(
 				mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
 	}
 }

AbstractAutowireCapableBeanFactory#doCreateBean() 方法中主要完成了以下工作,此處為了解決循環(huán)引用的問題,允許未創(chuàng)建完成的 Bean 對(duì)象提前暴露出來,主要是通過 Map 集合 earlySingletonObjects 緩存實(shí)現(xiàn)的

  • createBeanInstance() 實(shí)例化 Bean 對(duì)象
  • initializeBean() 初始化 Bean 對(duì)象
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
		throws BeanCreationException {

	// Instantiate the bean.
	BeanWrapper instanceWrapper = null;
	if (mbd.isSingleton()) {
		instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
	}
	if (instanceWrapper == null) {
		instanceWrapper = createBeanInstance(beanName, mbd, args);
	}
	final Object bean = instanceWrapper.getWrappedInstance();
	Class<?> beanType = instanceWrapper.getWrappedClass();
	if (beanType != NullBean.class) {
		mbd.resolvedTargetType = beanType;
	}

	......

	// Eagerly cache singletons to be able to resolve circular references
	// even when triggered by lifecycle interfaces like BeanFactoryAware.
	boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
			isSingletonCurrentlyInCreation(beanName));
	if (earlySingletonExposure) {
		if (logger.isTraceEnabled()) {
			logger.trace("Eagerly caching bean '" + beanName +
					"' to allow for resolving potential circular references");
		}
		addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
	}

	// Initialize the bean instance.
	Object exposedObject = bean;
	try {
		populateBean(beanName, mbd, instanceWrapper);
		exposedObject = initializeBean(beanName, exposedObject, mbd);
	}
	catch (Throwable ex) {
		if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
			throw (BeanCreationException) ex;
		}
		else {
			throw new BeanCreationException(
					mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
		}
	}

	if (earlySingletonExposure) {
		Object earlySingletonReference = getSingleton(beanName, false);
		if (earlySingletonReference != null) {
			if (exposedObject == bean) {
				exposedObject = earlySingletonReference;
			}
			else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
				String[] dependentBeans = getDependentBeans(beanName);
				Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
				for (String dependentBean : dependentBeans) {
					if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
						actualDependentBeans.add(dependentBean);
					}
				}
				if (!actualDependentBeans.isEmpty()) {
					throw new BeanCurrentlyInCreationException(beanName,
							"Bean with name '" + beanName + "' has been injected into other beans [" +
							StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
							"] in its raw version as part of a circular reference, but has eventually been " +
							"wrapped. This means that said other beans do not use the final version of the " +
							"bean. This is often the result of over-eager type matching - consider using " +
							"'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
				}
			}
		}
	}

	// Register bean as disposable.
	try {
		registerDisposableBeanIfNecessary(beanName, bean, mbd);
	}
	catch (BeanDefinitionValidationException ex) {
		throw new BeanCreationException(
				mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
	}

	return exposedObject;
}

AbstractAutowireCapableBeanFactory#initializeBean() 方法會(huì)調(diào)用 invokeAwareMethods() 方法檢查對(duì)象實(shí)現(xiàn)的接口,如果其實(shí)現(xiàn)了特定接口,則接口方法將被調(diào)用。

此處異步任務(wù)的后置處理器 AsyncAnnotationBeanPostProcessor#setBeanFactory() 方法將被調(diào)用

protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
	if (System.getSecurityManager() != null) {
		AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
			invokeAwareMethods(beanName, bean);
			return null;
		}, getAccessControlContext());
	}
	else {
		invokeAwareMethods(beanName, bean);
	}

	Object wrappedBean = bean;
	if (mbd == null || !mbd.isSynthetic()) {
		wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
	}

	try {
		invokeInitMethods(beanName, wrappedBean, mbd);
	}
	catch (Throwable ex) {
		throw new BeanCreationException(
				(mbd != null ? mbd.getResourceDescription() : null),
				beanName, "Invocation of init method failed", ex);
	}
	if (mbd == null || !mbd.isSynthetic()) {
		wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
	}

	return wrappedBean;
}

private void invokeAwareMethods(final String beanName, final Object bean) {
	if (bean instanceof Aware) {
		if (bean instanceof BeanNameAware) {
			((BeanNameAware) bean).setBeanName(beanName);
		}
		if (bean instanceof BeanClassLoaderAware) {
			ClassLoader bcl = getBeanClassLoader();
			if (bcl != null) {
				((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);
			}
		}
		if (bean instanceof BeanFactoryAware) {
			((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
		}
	}
}

AsyncAnnotationBeanPostProcessor#setBeanFactory() 方法可以看到其創(chuàng)建了異步任務(wù)切面 AsyncAnnotationAdvisor,該切面中包含了增強(qiáng)攔截器AnnotationAsyncExecutionInterceptor 和切入點(diǎn)AnnotationMatchingPointcut,將在后續(xù)創(chuàng)建 @Async 標(biāo)注的 bean 時(shí)用于創(chuàng)建代理對(duì)象

后續(xù)@Async 異步任務(wù)代理對(duì)象的生成及其生效原理不再繼續(xù)分析,讀者根據(jù)流程圖理解即可

 public void setBeanFactory(BeanFactory beanFactory) {
 	super.setBeanFactory(beanFactory);

 	AsyncAnnotationAdvisor advisor = new AsyncAnnotationAdvisor(this.executor, this.exceptionHandler);
 	if (this.asyncAnnotationType != null) {
 		advisor.setAsyncAnnotationType(this.asyncAnnotationType);
 	}
 	advisor.setBeanFactory(beanFactory);
 	this.advisor = advisor;
 }

總結(jié)

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • SpringBoot Controller Post接口單元測(cè)試示例

    SpringBoot Controller Post接口單元測(cè)試示例

    今天小編就為大家分享一篇關(guān)于SpringBoot Controller Post接口單元測(cè)試示例,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧
    2018-12-12
  • java遞歸生成樹型結(jié)構(gòu)方式

    java遞歸生成樹型結(jié)構(gòu)方式

    文章介紹了如何使用Java遞歸生成樹形結(jié)構(gòu),包括獲取數(shù)據(jù)、生成樹形結(jié)構(gòu)、查詢子節(jié)點(diǎn)等步驟,作者分享了自己的經(jīng)驗(yàn),希望能對(duì)大家有所幫助
    2024-12-12
  • Java CyclicBarrier源碼層分析與應(yīng)用

    Java CyclicBarrier源碼層分析與應(yīng)用

    這篇文章主要介紹了Java CyclicBarrier的源碼層分析與應(yīng)用,CyclicBarrier也叫同步屏障,可以讓一組線程達(dá)到一個(gè)屏障時(shí)被阻塞,直到最后一個(gè)線程達(dá)到屏障,感興趣的的朋友可以參考下
    2023-12-12
  • Java?任務(wù)調(diào)度框架?Quartz實(shí)操

    Java?任務(wù)調(diào)度框架?Quartz實(shí)操

    這篇文章主要介紹了Java?任務(wù)調(diào)度框架?Quartz,Quartz是OpenSymphony開源組織在Job?scheduling領(lǐng)域又一個(gè)開源項(xiàng)目,完全由Java開發(fā),可以用來執(zhí)行定時(shí)任務(wù),類似于java.util.Timer。,下面我們來學(xué)習(xí)一下關(guān)于?Quartz更多的詳細(xì)內(nèi)容,需要的朋友可以參考一下
    2021-12-12
  • Java的延遲隊(duì)列之DelayQueue解讀

    Java的延遲隊(duì)列之DelayQueue解讀

    這篇文章主要介紹了Java的延遲隊(duì)列之DelayQueue解讀,DelayQueue的底層存儲(chǔ)是一個(gè)PriorityQueue,PriorityQueue是一個(gè)可排序的Queue,其中的元素必須實(shí)現(xiàn)Comparable接口的compareTo方法,需要的朋友可以參考下
    2023-12-12
  • 使用Java程序模擬實(shí)現(xiàn)新冠病毒傳染效果

    使用Java程序模擬實(shí)現(xiàn)新冠病毒傳染效果

    這篇文章主要介紹了用Java程序模擬實(shí)現(xiàn)新冠病毒傳染效果,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-08-08
  • Java基礎(chǔ)強(qiáng)化訓(xùn)練輸入錯(cuò)誤即結(jié)束進(jìn)程

    Java基礎(chǔ)強(qiáng)化訓(xùn)練輸入錯(cuò)誤即結(jié)束進(jìn)程

    本文主要介紹了Java編程的基礎(chǔ)知識(shí)強(qiáng)化應(yīng)用,文中實(shí)例涉及到了許多基礎(chǔ)知識(shí),new對(duì)象,控制臺(tái)輸入,if語句等。很實(shí)用,需要的朋友可以參考下
    2017-09-09
  • Java判斷中英文符號(hào)、標(biāo)點(diǎn)的實(shí)現(xiàn)

    Java判斷中英文符號(hào)、標(biāo)點(diǎn)的實(shí)現(xiàn)

    本篇文章主要介紹了Java判斷中英文符號(hào)、標(biāo)點(diǎn)的實(shí)現(xiàn),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-10-10
  • springBoot熱部署、請(qǐng)求轉(zhuǎn)發(fā)與重定向步驟詳解

    springBoot熱部署、請(qǐng)求轉(zhuǎn)發(fā)與重定向步驟詳解

    這篇文章主要介紹了springBoot熱部署、請(qǐng)求轉(zhuǎn)發(fā)與重定向,本文通過示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-06-06
  • Java設(shè)計(jì)模式中的建造者模式詳解

    Java設(shè)計(jì)模式中的建造者模式詳解

    這篇文章主要介紹了Java設(shè)計(jì)模式中的建造者模式詳解,建造者模式使我們?nèi)粘9ぷ髦斜容^常見的一種設(shè)計(jì)模式,和工廠模式一樣屬于創(chuàng)建型設(shè)計(jì)模式,用于解耦對(duì)象創(chuàng)建和對(duì)象使用的邏輯,需要的朋友可以參考下
    2023-12-12

最新評(píng)論