Java 圖解Spring啟動(dòng)時(shí)的后置處理器工作流程是怎樣的
探究Spring的后置處理器
本次我們主要探究invokeBeanFactoryPostProcessors();后面的代碼下次再做解析;
入口代碼refresh()
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(); // ...... applicationContext.refresh();
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
// 啟動(dòng)前的準(zhǔn)備工作:記錄啟動(dòng)時(shí)間,活動(dòng)標(biāo)記為啟動(dòng)以及環(huán)境屬性變量集合的初始化
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
//還是一些準(zhǔn)備工作,添加了兩個(gè)后置處理器:ApplicationContextAwareProcessor,ApplicationListenerDetector
//還設(shè)置了 忽略自動(dòng)裝配 和 允許自動(dòng)裝配 的接口
//對(duì)環(huán)境,系統(tǒng)環(huán)境,系統(tǒng)屬性三個(gè)Bean如果不存在某個(gè)bean的時(shí)候,spring就自動(dòng)生成singleton bean(Not bd)
//還設(shè)置了bean表達(dá)式解析器 等
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
// 空方法
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
//執(zhí)行自定義的BeanFactoryProcessor和內(nèi)置的BeanFactoryProcessor
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();
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}
流程圖

prepareRefresh剖析
該方法主要做啟動(dòng)前的準(zhǔn)備工作:記錄啟動(dòng)時(shí)間,活動(dòng)標(biāo)記為啟動(dòng)以及環(huán)境屬性變量集合的初始化;
protected void prepareRefresh() {
// Switch to active.
this.startupDate = System.currentTimeMillis();
this.closed.set(false);
this.active.set(true);
// Initialize any placeholder property sources in the context environment.
// 空方法
initPropertySources();
// Validate that all properties marked as required are resolvable:
// see ConfigurablePropertyResolver#setRequiredProperties
getEnvironment().validateRequiredProperties();
// Store pre-refresh ApplicationListeners...
if (this.earlyApplicationListeners == null) {
this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);
}
else {
// Reset local application listeners to pre-refresh state.
this.applicationListeners.clear();
this.applicationListeners.addAll(this.earlyApplicationListeners);
}
// Allow for the collection of early ApplicationEvents,
// to be published once the multicaster is available...
this.earlyApplicationEvents = new LinkedHashSet<>();
}
obtainFreshBeanFactory刨析
主要是獲取context上下文中的bean工廠;
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
// CAS保證同步
refreshBeanFactory();
// 返回beanFactory- DefaultListableBeanFactory.class
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
return beanFactory;
}
prepareBeanFactory刨析
做一些準(zhǔn)備工作,添加了兩個(gè)后置處理器ApplicationContextAwareProcessor和ApplicationListenerDetector;
設(shè)置了bean表達(dá)式解析器等;
通過(guò)工廠的接口可以設(shè)置了忽略自動(dòng)裝配,和允許自動(dòng)裝配;
對(duì)環(huán)境、系統(tǒng)環(huán)境、系統(tǒng)屬性三個(gè)Bean如果不存在某個(gè)bean的時(shí)候,spring就自動(dòng)生成singletonBean(Not bd);
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// Tell the internal bean factory to use the context's class loader etc.
beanFactory.setBeanClassLoader(getClassLoader());
//設(shè)置bean表達(dá)式解析器
beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
//屬性編輯器支持
beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
// Configure the bean factory with context callbacks.
//添加一個(gè)后置處理器:ApplicationContextAwareProcessor,此后置處理處理器實(shí)現(xiàn)了BeanPostProcessor接口
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
//以下接口,忽略自動(dòng)裝配
beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
// .....
// BeanFactory interface not registered as resolvable type in a plain factory.
// MessageSource registered (and found for autowiring) as a bean.
//以下接口,允許自動(dòng)裝配,第一個(gè)參數(shù)是自動(dòng)裝配的類(lèi)型,,第二個(gè)字段是自動(dòng)裝配的值
// 這個(gè)接口僅會(huì)將注入的參數(shù)XXX.class注入為指定的值,但不影響XXX.class創(chuàng)建Bean對(duì)象;
beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
beanFactory.registerResolvableDependency(ResourceLoader.class, this);
// Register default environment beans.
// 環(huán)境,系統(tǒng)環(huán)境,系統(tǒng)屬性 因此通常情況下,這三個(gè)Bean是沒(méi)有bd的
//如果沒(méi)有注冊(cè)過(guò)bean名稱(chēng)為XXX,spring就自己創(chuàng)建一個(gè)名稱(chēng)為XXX的singleton bean
if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
}
if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
}
if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
}
}
invokeBeanFactoryPostProcessors剖析
執(zhí)行自定義的BeanFactoryProcessor和內(nèi)置的BeanFactoryProcessor;
getBeanFactoryPostProcessors()方法是我們手動(dòng)通過(guò)執(zhí)行addBeanFactoryPostProcessor(XX)設(shè)置自定義的后置處理器。如果初始化執(zhí)行到這,沒(méi)有手動(dòng)增加后置處理器的話,那么此時(shí)List<BeanFactoryPostProcessor>的size()為empty;
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
// getBeanFactoryPostProcessors是spring允許我們手動(dòng)添加BeanFactoryPostProcessor
// 即:annotationConfigApplicationContext.addBeanFactoryPostProcessor(XXX);
// 未手動(dòng)添加的話,getBeanFactoryPostProcessors()為empty
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
// Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime
// (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)
if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
}
我們通過(guò)委托PostProcessorRegistrationDelegate去調(diào)用invokeBeanFactoryPostProcessors()方法,從而去掃描并執(zhí)行BeanFactoryProcessor和BeanDefinitionRegistryPostProcessor;
我們通過(guò)繼承關(guān)系看,BeanDefinitionRegistryPostProcessor實(shí)際上是繼承BeanFactoryProcessor接口的;

BeanDefinitionRegistryPostProcessor:主要掃描類(lèi)解析類(lèi);BeanFactoryProcessor:主要給配置類(lèi)進(jìn)行增強(qiáng)代理;
這里面需要看我們的BeanFactory的類(lèi)型;初始時(shí)BeanFactory的類(lèi)型是DefaultListableBeanFactory;因此,該bean工廠是實(shí)現(xiàn)BeanDefinitionRegistry;

該方法的具體流程如下(按初始化進(jìn)入到這里描述):
- 循環(huán)遍歷手動(dòng)添加的后置處理器(并不排序);
- 若該bfp是bdrp則直接執(zhí)行
bdrp. postProcessBeanDefinitionRegistry(); - 取出內(nèi)置的bdrp,分為實(shí)現(xiàn)了
PriorityOrdered,Ordered和都沒(méi)有實(shí)現(xiàn)的三類(lèi);
初始這里只有一個(gè),就是我們?cè)诔跏蓟痳eader()時(shí),注冊(cè)了一個(gè)ConfigurationClassPostProcessor.class;

public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor,
PriorityOrdered, ResourceLoaderAware, BeanClassLoaderAware, EnvironmentAware {}
將上面三類(lèi)直接執(zhí)行bdrp. postProcessBeanDefinitionRegistry();
然后將手動(dòng)加入和內(nèi)置的bdrp執(zhí)行bfp.postProcessBeanFactory();
上面的已經(jīng)執(zhí)行完了:
- 手動(dòng)添加的后置處理器的
bdrf. postProcessBeanDefinitionRegistry()和bfp.postProcessBeanFactory(); - 內(nèi)置的
bdrp. postProcessBeanDefinitionRegistry()
取出內(nèi)置的bfp,分為實(shí)現(xiàn)了PriorityOrdered, Ordered和都沒(méi)有實(shí)現(xiàn)的三類(lèi);
目前這里內(nèi)置的有兩個(gè)。但其中config上面已經(jīng)執(zhí)行過(guò)了,此處只執(zhí)行下方的一個(gè);

將上面三類(lèi)直接執(zhí)行bfp. postProcessBeanDefinitionRegistry();
清除緩存中的bd,因?yàn)楹筇幚砥骺赡苡行薷牧嗽荚獢?shù)據(jù),例如替換值中的占位符;
public static void invokeBeanFactoryPostProcessors(
ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
// Invoke BeanDefinitionRegistryPostProcessors first, if any.
Set<String> processedBeans = new HashSet<>();
// 如果不是BeanDefinitionRegistry 則直接執(zhí)行beanFactoryPostProcessors
// 剛啟動(dòng)時(shí)傳入的beanFactory是DefaultListableBeanFactory,他是實(shí)現(xiàn)了BeanDefinitionRegistry 因此會(huì)走這里
if (beanFactory instanceof BeanDefinitionRegistry) {
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
// bf后置處理器集合(手動(dòng)添加與bdr后置處理器集合【下面的那個(gè)集合】):因?yàn)閎drp屬于bfp
List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
// bdr后置處理器集合(手動(dòng)添加與spring自己的)
List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();
// 循環(huán)傳進(jìn)來(lái)的beanFactoryPostProcessors,剛啟動(dòng)時(shí)未手動(dòng)增加的情況下beanFactoryPostProcessors肯定沒(méi)有數(shù)據(jù)
// 因?yàn)閎eanFactoryPostProcessors是獲得手動(dòng)添加的,而不是spring掃描的
// 只有手動(dòng)調(diào)用annotationConfigApplicationContext.addBeanFactoryPostProcessor(XXX)才會(huì)有數(shù)據(jù)
// 執(zhí)行手動(dòng)添加的beanFactoryPostProcessors, 如果是BeanDefinitionRegistryPostProcessor,則執(zhí)行其postProcessBeanDefinitionRegistry再加到list中
for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
BeanDefinitionRegistryPostProcessor registryProcessor =
(BeanDefinitionRegistryPostProcessor) postProcessor;
registryProcessor.postProcessBeanDefinitionRegistry(registry);
registryProcessors.add(registryProcessor);
}
else {
regularPostProcessors.add(postProcessor);
}
}
//一個(gè)臨時(shí)變量,用來(lái)裝載BeanDefinitionRegistryPostProcessor為了排序
//BeanDefinitionRegistry繼承了PostProcessorBeanFactoryPostProcessor
List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();
// 獲得實(shí)現(xiàn)BeanDefinitionRegistryPostProcessor接口的類(lèi)
// 就是ConfigurationClassPostProcessor(Spring自己添加的-在reader()時(shí)增加的)
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
//獲得ConfigurationClassPostProcessor類(lèi),并且放到currentRegistryProcessors
//ConfigurationClassPostProcessor是很重要的一個(gè)類(lèi),它實(shí)現(xiàn)了BeanDefinitionRegistryPostProcessor接口
//BeanDefinitionRegistryPostProcessor接口又實(shí)現(xiàn)了BeanFactoryPostProcessor接口
//ConfigurationClassPostProcessor是極其重要的類(lèi)
//里面執(zhí)行了掃描Bean,Import,ImportResouce等各種操作
//用來(lái)處理配置類(lèi)(有兩種情況 一種是傳統(tǒng)意義上的配置類(lèi),一種是普通的bean)的各種邏輯
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
//把name放到processedBeans,后續(xù)會(huì)根據(jù)這個(gè)集合來(lái)判斷處理器是否已經(jīng)被執(zhí)行過(guò)了
processedBeans.add(ppName);
}
}
//處理排序
sortPostProcessors(currentRegistryProcessors, beanFactory);
//合并Processors,為什么要合并,因?yàn)閞egistryProcessors是裝載BeanDefinitionRegistryPostProcessor的
//一開(kāi)始的時(shí)候,spring只會(huì)執(zhí)行BeanDefinitionRegistryPostProcessor獨(dú)有的方法
//而不會(huì)執(zhí)行BeanDefinitionRegistryPostProcessor父類(lèi)的方法,即BeanFactoryProcessor的方法
//所以這里需要把處理器放入一個(gè)集合中,后續(xù)統(tǒng)一執(zhí)行父類(lèi)的方法
registryProcessors.addAll(currentRegistryProcessors);
//可以理解為執(zhí)行ConfigurationClassPostProcessor的postProcessBeanDefinitionRegistry方法
//Spring熱插播的體現(xiàn),像ConfigurationClassPostProcessor就相當(dāng)于一個(gè)組件,Spring很多事情就是交給組件去管理
//將spring提供的RegistryProcessors(就是這個(gè)ConfigurationClassPostProcessor)執(zhí)行其postProcessBeanDefinitionRegistry
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
//清空臨時(shí)變量
currentRegistryProcessors.clear();
// 再次根據(jù)BeanDefinitionRegistryPostProcessor獲得BeanName,看這個(gè)BeanName是否已經(jīng)被執(zhí)行過(guò)了,有沒(méi)有實(shí)現(xiàn)Ordered接口
// 如果沒(méi)有被執(zhí)行過(guò),也實(shí)現(xiàn)了Ordered接口的話,把對(duì)象推送到currentRegistryProcessors,名稱(chēng)推送到processedBeans
// 如果沒(méi)有實(shí)現(xiàn)Ordered接口的話,這里不把數(shù)據(jù)加到currentRegistryProcessors,processedBeans中,后續(xù)再做處理
// 這里才可以獲得我們定義的實(shí)現(xiàn)了BeanDefinitionRegistryPostProcessor的Bean
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
//處理排序
sortPostProcessors(currentRegistryProcessors, beanFactory);
//合并Processors
registryProcessors.addAll(currentRegistryProcessors);
//執(zhí)行有Ordered的BeanDefinitionRegistryPostProcessor
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
//清空臨時(shí)變量
currentRegistryProcessors.clear();
// Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.
// 下面的代碼就是執(zhí)行沒(méi)有實(shí)現(xiàn)PriorityOrdered接口也沒(méi)有Ordered的BeanDefinitionRegistryPostProcessor
boolean reiterate = true;
while (reiterate) {
reiterate = false;
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (!processedBeans.contains(ppName)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
reiterate = true;
}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear();
}
// Now, invoke the postProcessBeanFactory callback of all processors handled so far.
//registryProcessors集合裝載BeanDefinitionRegistryPostProcessor
//上面的代碼是執(zhí)行bfr后置處理器子類(lèi)獨(dú)有的方法,這里需要再把bfr后置處理器父類(lèi)的方法也執(zhí)行一次
invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
//regularPostProcessors裝載BeanFactoryPostProcessor,執(zhí)行BeanFactoryPostProcessor的方法
//但是regularPostProcessors一般情況下,是不會(huì)有數(shù)據(jù)的,只有在外面手動(dòng)添加BeanFactoryPostProcessor,才會(huì)有數(shù)據(jù)
invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
}
else {
// Invoke factory processors registered with the context instance.
// 若bfp沒(méi)有繼承bdrp則直接執(zhí)行手動(dòng)增加bf后置處理器的后置處理器
invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
}
// Do not initialize FactoryBeans here: We need to leave all regular beans
// uninitialized to let the bean factory post-processors apply to them!
// 找到BeanFactoryPostProcessor實(shí)現(xiàn)類(lèi)的BeanName數(shù)組
// 處理Spring自己的bf后置處理器
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);
// Separate between BeanFactoryPostProcessors that implement PriorityOrdered,
// Ordered, and the rest.
// PriorityOrdered的bf后置處理器集合
List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
// Ordered的bf后置處理器集合
List<String> orderedPostProcessorNames = new ArrayList<>();
// 無(wú)PriorityOrdered無(wú)Ordered的bf后置處理器集合
List<String> nonOrderedPostProcessorNames = new ArrayList<>();
//循環(huán)BeanName數(shù)組
for (String ppName : postProcessorNames) {
//如果這個(gè)Bean被執(zhí)行過(guò)了,跳過(guò)
if (processedBeans.contains(ppName)) {
// skip - already processed in first phase above
}
//如果實(shí)現(xiàn)了PriorityOrdered接口,加入到priorityOrderedPostProcessors
else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
}
//如果實(shí)現(xiàn)了Ordered接口,加入到orderedPostProcessorNames
else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
orderedPostProcessorNames.add(ppName);
}
//如果既沒(méi)有實(shí)現(xiàn)PriorityOrdered,也沒(méi)有實(shí)現(xiàn)Ordered。加入到nonOrderedPostProcessorNames
else {
nonOrderedPostProcessorNames.add(ppName);
}
}
// First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered.
//排序處理priorityOrderedPostProcessors,即實(shí)現(xiàn)了PriorityOrdered接口的BeanFactoryPostProcessor
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
//執(zhí)行priorityOrderedPostProcessors
invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);
// Next, invoke the BeanFactoryPostProcessors that implement Ordered.
//執(zhí)行實(shí)現(xiàn)了Ordered接口的BeanFactoryPostProcessor
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.
// 執(zhí)行既沒(méi)有實(shí)現(xiàn)PriorityOrdered接口,也沒(méi)有實(shí)現(xiàn)Ordered接口的BeanFactoryPostProcessor
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...
// 清除了allBeanNamesByType&singletonBeanNamesByType()
// 清除緩存中的bd,因?yàn)楹筇幚砥骺赡苡行薷牧嗽荚獢?shù)據(jù),例如替換值中的占位符
beanFactory.clearMetadataCache();
}
到此這篇關(guān)于Java 圖解Spring啟動(dòng)時(shí)的后置處理器工作流程是怎樣的的文章就介紹到這了,更多相關(guān)Java Spring 后置處理器內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
理解Java當(dāng)中的回調(diào)機(jī)制(翻譯)
今天我要和大家分享一些東西,舉例來(lái)說(shuō)這個(gè)在JavaScript中用的很多。我要講講回調(diào)(callbacks)。你知道什么時(shí)候用,怎么用這個(gè)嗎?你真的理解了它在java環(huán)境中的用法了嗎?當(dāng)我也問(wèn)我自己這些問(wèn)題,這也是我開(kāi)始研究這些的原因2014-10-10
關(guān)于SpringBoot自定義條件注解與自動(dòng)配置
這篇文章主要介紹了關(guān)于SpringBoot自定義條件注解與自動(dòng)配置,Spring Boot的核心功能就是為整合第三方框架提供自動(dòng)配置,而本文則帶著大家實(shí)現(xiàn)了自己的自動(dòng)配置和Starter,需要的朋友可以參考下2023-07-07
基于Java SWFTools實(shí)現(xiàn)把pdf轉(zhuǎn)成swf
這篇文章主要介紹了基于Java SWFTools實(shí)現(xiàn)把pdf轉(zhuǎn)成swf,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-11-11
基于Spring p標(biāo)簽和c標(biāo)簽注入方式
這篇文章主要介紹了Spring p標(biāo)簽和c標(biāo)簽注入方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-09-09
如何用java給文件加密的簡(jiǎn)單實(shí)現(xiàn)
文件加密,簡(jiǎn)單來(lái)說(shuō)就是把文件讀取出來(lái),把讀取出來(lái)的字節(jié)碼數(shù)組進(jìn)行遍歷,把每一個(gè)碼值和一個(gè)秘鑰(隨便一個(gè)數(shù))進(jìn)行異或運(yùn)算,將運(yùn)算后的結(jié)果全部寫(xiě)入到文件里,這篇文章主要介紹了如何用java給文件加密的簡(jiǎn)單實(shí)現(xiàn),需要的朋友可以參考下2023-12-12
基于SpringBoot實(shí)現(xiàn)自動(dòng)裝配返回屬性的設(shè)計(jì)思路
這篇文章主要介紹了基于SpringBoot實(shí)現(xiàn)自動(dòng)裝配返回屬性,這里涉及到的技術(shù)知識(shí)點(diǎn)有注解解析器,為什么用ResponseBodyAdvice這里解析?不在Filter,Interceptors,本文結(jié)合示例代碼給大家介紹的非常詳細(xì),需要的朋友參考下吧2022-03-03
詳解Java中用于查找對(duì)象哈希碼值的hashCode()函數(shù)
Java中入HashMap等一些鍵值對(duì)應(yīng)的結(jié)構(gòu),基本上都可以用hashCode()來(lái)查找值,接下來(lái)我們就來(lái)詳解Java中用于查找對(duì)象哈希碼值的hashCode()函數(shù):2016-05-05
SpringBoot如何根據(jù)用戶(hù)系統(tǒng)時(shí)區(qū)動(dòng)態(tài)展示時(shí)間
這篇文章主要介紹了SpringBoot如何根據(jù)用戶(hù)系統(tǒng)時(shí)區(qū)動(dòng)態(tài)展示時(shí)間,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-01-01
SpringBoot 在測(cè)試時(shí)如何指定包的掃描范圍
這篇文章主要介紹了SpringBoot 在測(cè)試時(shí)如何指定包的掃描范圍,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-11-11

