摘要:構(gòu)建完實(shí)例后,將它設(shè)置為的父認(rèn)證管理器并將該傳入構(gòu)造器構(gòu)建實(shí)例。,目前為止已經(jīng)被初始化,接下去需要設(shè)置對(duì)象添加至的列表中打開類結(jié)構(gòu),和一樣,它也實(shí)現(xiàn)了接口,同樣繼承自。最后返回的是的默認(rèn)實(shí)現(xiàn)。
最近在整合微服務(wù)OAuth 2認(rèn)證過程中,它是基于Spring Security之上,而本人對(duì)Spring Security架構(gòu)原理并不太熟悉,導(dǎo)致很多配置搞不太清楚,遂咬牙啃完了Spring Security核心源碼,花了差不多一星期,總體上來說,其代碼確實(shí)比較晦澀,之前在學(xué)習(xí)Apache Shiro框架之前也曾經(jīng)在相關(guān)論壇里了解過,相比Spring Security,Apache Shiro真的是相當(dāng)輕量,代碼研讀起來容易很多,而Spring Security類繼承結(jié)構(gòu)復(fù)雜,大量使用了其所謂Builder和Configuer模式,其代碼跟蹤過程很痛苦,遂記錄下,分享給有需要的人,由于本人能力有限,在文章中有不對(duì)之處,還請(qǐng)各位執(zhí)教,在此謝謝各位了。
本人研讀的Spring Security版本為:5.1.4.RELEASE
Spring Security在3.2版本之后支持Java Configuration,即:通過Java編碼形式配置Spring Security,可不再依賴XML文件配置,本文采用Java Configuration方式。
在Spring Security官方文檔中有一個(gè)最簡配置例子:
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.*; import org.springframework.security.config.annotation.authentication.builders.*; import org.springframework.security.config.annotation.web.configuration.*; @Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { auth .inMemoryAuthentication() .withUser("user").password("password").roles("USER"); } }
我們先不要看其它內(nèi)容,先關(guān)注注解@EnableWebSecurity,它是初始化Spring Security的入口,打開其源碼如下:
@Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME) @Target(value = { java.lang.annotation.ElementType.TYPE }) @Documented @Import({ WebSecurityConfiguration.class, SpringWebMvcImportSelector.class, OAuth2ImportSelector.class }) @EnableGlobalAuthentication @Configuration public @interface EnableWebSecurity { /** * Controls debugging support for Spring Security. Default is false. * @return if true, enables debug support with Spring Security */ boolean debug() default false; }
該注解類通過@Configuration和@Import配合使用引入了一個(gè)配置類(WebSecurityConfiguration)和兩個(gè)ImportSelector(SpringWebMvcImportSelector,OAuth2ImportSelector),我們重點(diǎn)關(guān)注下WebSecurityConfiguration,它是Spring Security的核心,正是它構(gòu)建初始化了所有的Bean實(shí)例和相關(guān)配置,下面我們?cè)敿?xì)分析下。
打開WebSecurityConfiguration源碼,發(fā)現(xiàn)它被@Configuration標(biāo)記,說明它是配置類,
@Configuration public class WebSecurityConfiguration implements ImportAware, BeanClassLoaderAware
該類中最重要的工作就是實(shí)例并注冊(cè)FilterChainProxy,也就是我們?cè)谝郧癤ML文件中配置的過濾器:
springSecurityFilterChain org.springframework.web.filter.DelegatingFilterProxy springSecurityFilterChain /*
該過濾器負(fù)責(zé)攔截請(qǐng)求,并把請(qǐng)求通過一定的匹配規(guī)則(通過RequestMatcher匹配實(shí)現(xiàn))路由(或者Delegate)到具體的SecurityFilterChain,源碼如下:
/** * Creates the Spring Security Filter Chain * @return the {@link Filter} that represents the security filter chain * @throws Exception */ @Bean(name = AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME) public Filter springSecurityFilterChain() throws Exception { boolean hasConfigurers = webSecurityConfigurers != null && !webSecurityConfigurers.isEmpty(); if (!hasConfigurers) { WebSecurityConfigurerAdapter adapter = objectObjectPostProcessor .postProcess(new WebSecurityConfigurerAdapter() { }); webSecurity.apply(adapter); } return webSecurity.build(); }
@Bean注解name屬性值AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME就是XML中定義的springSecurityFilterChain。
從源碼中知道過濾器通過最后的webSecurity.build()創(chuàng)建,webSecurity的類型為:WebSecurity,它在setFilterChainProxySecurityConfigurer方法中優(yōu)先被創(chuàng)建了:
/** * Sets the {@code} * instances used to create the web configuration. * * @param objectPostProcessor the {@link ObjectPostProcessor} used to create a * {@link WebSecurity} instance * @param webSecurityConfigurers the * {@code } instances used to * create the web configuration * @throws Exception */ @Autowired(required = false) public void setFilterChainProxySecurityConfigurer( ObjectPostProcessor
從代碼中可以看到,它是直接被new出來的:
webSecurity = objectPostProcessor .postProcess(new WebSecurity(objectPostProcessor));
setFilterChainProxySecurityConfigurer方法參數(shù)中需要被注入兩個(gè)對(duì)象:objectPostProcessor和webSecurityConfigurers,objectPostProcessor是在ObjectPostProcessorConfiguration配置類中注冊(cè)的,而webSecurityConfigurers則是使用了@Value注解方式,注解內(nèi)容為:#{@autowiredWebSecurityConfigurersIgnoreParents.getWebSecurityConfigurers()},通過源碼了解,autowiredWebSecurityConfigurersIgnoreParents是在本類中被注冊(cè):
@Bean public static AutowiredWebSecurityConfigurersIgnoreParents autowiredWebSecurityConfigurersIgnoreParents( ConfigurableListableBeanFactory beanFactory) { return new AutowiredWebSecurityConfigurersIgnoreParents(beanFactory); }
在AutowiredWebSecurityConfigurersIgnoreParents中定義了方法:getWebSecurityConfigurers:
@SuppressWarnings({ "rawtypes", "unchecked" }) public List> getWebSecurityConfigurers() { List > webSecurityConfigurers = new ArrayList >(); Map beansOfType = beanFactory .getBeansOfType(WebSecurityConfigurer.class); for (Entry entry : beansOfType.entrySet()) { webSecurityConfigurers.add(entry.getValue()); } return webSecurityConfigurers; }
它通過BeanFactory獲取了類型為WebSecurityConfigurer的Bean實(shí)例列表?;氐?b>WebSecurityConfiguration類中的setFilterChainProxySecurityConfigurer方法,它把WebSecurityConfigurer列表設(shè)置到了WebSecurity中,源碼如下:
for (SecurityConfigurerwebSecurityConfigurer : webSecurityConfigurers) { webSecurity.apply(webSecurityConfigurer); }
通過apply方法,apply方法其實(shí)就是webSecurityConfigurer放入webSecurity維護(hù)的configurers屬性中,configurers是個(gè)LinkedHashMap,源碼如下:
/** * Applies a {@link SecurityConfigurer} to this {@link SecurityBuilder} overriding any * {@link SecurityConfigurer} of the exact same class. Note that object hierarchies * are not considered. * * @param configurer * @return the {@link SecurityConfigurerAdapter} for further customizations * @throws Exception */ public> C apply(C configurer) throws Exception { add(configurer); return configurer; }
其中代碼add(configurer)就是將這些webSecurityConfigurer添加到webSecurity的configurers屬性中。
現(xiàn)在webSecurity的初始化工作已經(jīng)完成,現(xiàn)在回到springSecurityFilterChain方法中,它首先檢查當(dāng)前是否配置了webSecurityConfigurer,如果沒有的會(huì)默認(rèn)設(shè)置一個(gè),并且調(diào)用上面提到的apply方法,源碼如下:
boolean hasConfigurers = webSecurityConfigurers != null && !webSecurityConfigurers.isEmpty(); if (!hasConfigurers) { WebSecurityConfigurerAdapter adapter = objectObjectPostProcessor .postProcess(new WebSecurityConfigurerAdapter() { }); webSecurity.apply(adapter); }
如果已經(jīng)存在配置了webSecurityConfigurer,則調(diào)用webSecurity.build()進(jìn)行構(gòu)建。
在進(jìn)入build方法之前,首先簡單介紹下WebSecurity的繼承結(jié)構(gòu),
它實(shí)現(xiàn)了SecurityBuilder接口,繼承自AbstractConfiguredSecurityBuilder,AbstractConfiguredSecurityBuilder繼承自AbstractSecurityBuilder,AbstractSecurityBuilder實(shí)現(xiàn)了SecurityBuilder,其中AbstractConfiguredSecurityBuilder實(shí)現(xiàn)了通過自定義SecurityConfigurer類來配置SecurityBuilder,上面提到的apply(SecurityConfigurer configurer)就是在該類中實(shí)現(xiàn)的,它把configurer保存在它維護(hù)的LinkedHashMap
調(diào)用webSecurity.build()后,首先調(diào)用的父類AbstractSecurityBuilder中的build方法:
public final O build() throws Exception { if (this.building.compareAndSet(false, true)) { this.object = doBuild(); return this.object; } throw new AlreadyBuiltException("This object has already been built"); }
然后調(diào)用doBuild(),doBuild()在子類中實(shí)現(xiàn),AbstractConfiguredSecurityBuilder實(shí)現(xiàn)了該方法:
@Override protected final O doBuild() throws Exception { synchronized (configurers) { buildState = BuildState.INITIALIZING; beforeInit(); init(); buildState = BuildState.CONFIGURING; beforeConfigure(); configure(); buildState = BuildState.BUILDING; O result = performBuild(); buildState = BuildState.BUILT; return result; } }
在這里重點(diǎn)關(guān)注init()、configure()和performBuild(),下面逐個(gè)分析它們的作用。
init()方法在AbstractConfiguredSecurityBuilder實(shí)現(xiàn):
private void init() throws Exception { Collection> configurers = getConfigurers(); for (SecurityConfigurer configurer : configurers) { configurer.init((B) this); } for (SecurityConfigurer configurer : configurersAddedInInitializing) { configurer.init((B) this); } }
它的工作是迭代調(diào)用所有配置的SecurityConfigrer的init方法,在這里其實(shí)是它的子類WebSecurityConfigurer,因?yàn)橹矮@取時(shí)指定的類型就是WebSecurityConfigurer,在上文中提到AutowiredWebSecurityConfigurersIgnoreParents.getWebSecurityConfigurers()中:
MapbeansOfType = beanFactory.getBeansOfType(WebSecurityConfigurer.class);
而實(shí)現(xiàn)了WebSecurityConfigurer接口的就是WebSecurityConfigurerAdapter,WebSecurityConfigurerAdapter.init()源碼如下:
public void init(final WebSecurity web) throws Exception { final HttpSecurity http = getHttp(); web.addSecurityFilterChainBuilder(http).postBuildAction(new Runnable() { public void run() { FilterSecurityInterceptor securityInterceptor = http .getSharedObject(FilterSecurityInterceptor.class); web.securityInterceptor(securityInterceptor); } }); }
它只要完成兩件重要的事情:
初始化HttpSecurity對(duì)象;
設(shè)置HttpSecurity對(duì)象添加至WebSecurity的securityFilterChainBuilders列表中;
初始化HttpSecurity對(duì)象在getHttp()方法中實(shí)現(xiàn):
protected final HttpSecurity getHttp() throws Exception { if (http != null) { return http; } DefaultAuthenticationEventPublisher eventPublisher = objectPostProcessor .postProcess(new DefaultAuthenticationEventPublisher()); localConfigureAuthenticationBldr.authenticationEventPublisher(eventPublisher); AuthenticationManager authenticationManager = authenticationManager(); authenticationBuilder.parentAuthenticationManager(authenticationManager); authenticationBuilder.authenticationEventPublisher(eventPublisher); Map, Object> sharedObjects = createSharedObjects(); http = new HttpSecurity(objectPostProcessor, authenticationBuilder, sharedObjects); if (!disableDefaults) { // @formatter:off http .csrf().and() .addFilter(new WebAsyncManagerIntegrationFilter()) .exceptionHandling().and() .headers().and() .sessionManagement().and() .securityContext().and() .requestCache().and() .anonymous().and() .servletApi().and() .apply(new DefaultLoginPageConfigurer<>()).and() .logout(); // @formatter:on ClassLoader classLoader = this.context.getClassLoader(); List defaultHttpConfigurers = SpringFactoriesLoader.loadFactories(AbstractHttpConfigurer.class, classLoader); for (AbstractHttpConfigurer configurer : defaultHttpConfigurers) { http.apply(configurer); } } configure(http); return http; }
從代碼中可以了解,HttpSecurity是直接被new出來的,在創(chuàng)建HttpSecurity之前,首先初始化了AuthenticationManagerBuilder對(duì)象,這里有段代碼很重要就是: AuthenticationManager authenticationManager = authenticationManager();,它創(chuàng)建AuthenticationManager實(shí)例,打開authenticationManager()方法:
protected AuthenticationManager authenticationManager() throws Exception { if (!authenticationManagerInitialized) { configure(localConfigureAuthenticationBldr); if (disableLocalConfigureAuthenticationBldr) { authenticationManager = authenticationConfiguration .getAuthenticationManager(); } else { authenticationManager = localConfigureAuthenticationBldr.build(); } authenticationManagerInitialized = true; } return authenticationManager; }
在初始化時(shí),它會(huì)調(diào)用configure(localConfigureAuthenticationBldr);,默認(rèn)的實(shí)現(xiàn)是:
protected void configure(AuthenticationManagerBuilder auth) throws Exception { this.disableLocalConfigureAuthenticationBldr = true; }
【1、個(gè)性化配置入口之configure(AuthenticationManagerBuilder auth)】
我們可以通過繼承WebSecurityConfigurerAdapter并重寫該方法來個(gè)性化配置AuthenticationManager。
構(gòu)建完authenticationManager 實(shí)例后,將它設(shè)置為authenticationBuilder的父認(rèn)證管理器:
authenticationBuilder.parentAuthenticationManager(authenticationManager);
并將該authenticationBuilder傳入HttpSecurity構(gòu)造器構(gòu)建HttpSecurity實(shí)例。
構(gòu)建完HttpSecurity實(shí)例后,默認(rèn)情況下會(huì)添加默認(rèn)的攔截其配置:
http .csrf().and() .addFilter(new WebAsyncManagerIntegrationFilter()) .exceptionHandling().and() .headers().and() .sessionManagement().and() .securityContext().and() .requestCache().and() .anonymous().and() .servletApi().and() .apply(new DefaultLoginPageConfigurer<>()).and() .logout();
最后調(diào)用configure(http);,這又是一個(gè)可個(gè)性化的配置入口,它的默認(rèn)實(shí)現(xiàn)是:
protected void configure(HttpSecurity http) throws Exception { logger.debug("Using default configure(HttpSecurity). If subclassed this will potentially override subclass configure(HttpSecurity)."); http .authorizeRequests() .anyRequest().authenticated() .and() .formLogin().and() .httpBasic(); }
默認(rèn)的配置是攔截所有的請(qǐng)求需要認(rèn)證之后才能訪問,如果沒有認(rèn)證,會(huì)自動(dòng)生成一個(gè)認(rèn)證表單要求輸入用戶名和密碼。
【2、個(gè)性化配置入口之configure(HttpSecurity http)】
我們可以通過繼承WebSecurityConfigurerAdapter并重寫該方法來個(gè)性化配置HttpSecurity。
OK,目前為止HttpSecurity已經(jīng)被初始化,接下去需要設(shè)置HttpSecurity對(duì)象添加至WebSecurity的securityFilterChainBuilders列表中:
web.addSecurityFilterChainBuilder(http).postBuildAction(new Runnable() { public void run() { FilterSecurityInterceptor securityInterceptor = http .getSharedObject(FilterSecurityInterceptor.class); web.securityInterceptor(securityInterceptor); } });
打開HttpSecurity類結(jié)構(gòu),和WebSecurity一樣,它也實(shí)現(xiàn)了SecurityBuilder接口,同樣繼承自AbstractConfiguredSecurityBuilder。
當(dāng)所有的WebSecurityConfigurer的init方法被調(diào)用之后,webSecurity.init()工作就結(jié)束了。
接下去調(diào)用了webSecurity.configure(),該方法同樣是在AbstractConfiguredSecurityBuilder中實(shí)現(xiàn)的:
private void configure() throws Exception { Collection> configurers = getConfigurers(); for (SecurityConfigurer configurer : configurers) { configurer.configure((B) this); } }
它的主要工作是迭代調(diào)用所有WebSecurityConfigurer的configurer方法,參數(shù)是WebSeucrity本身,這又是另外一個(gè)重要的個(gè)性化入口:
【3、個(gè)性化配置入口之configure(WebSecurity web)】
我們可以通過繼承WebSecurityConfigurerAdapter并重寫該方法來個(gè)性化配置WebSecurity。
自此,三個(gè)重要的個(gè)性化入口都已經(jīng)被調(diào)用,即在實(shí)現(xiàn)WebSecurityConfigurerAdapter經(jīng)常需要重寫的:
1、configure(AuthenticationManagerBuilder auth); 2、configure(WebSecurity web); 3、configure(HttpSecurity http);
回到webSecurity構(gòu)建過程,接下去重要的的調(diào)用:
O result = performBuild();
該方法在WebSecurityConfigurerAdapter中實(shí)現(xiàn),返回的就是過濾器FilterChainProxy,源碼如下:
@Override protected Filter performBuild() throws Exception { Assert.state( !securityFilterChainBuilders.isEmpty(), () -> "At least one SecurityBuilder extends SecurityFilterChain> needs to be specified. " + "Typically this done by adding a @Configuration that extends WebSecurityConfigurerAdapter. " + "More advanced users can invoke " + WebSecurity.class.getSimpleName() + ".addSecurityFilterChainBuilder directly"); int chainSize = ignoredRequests.size() + securityFilterChainBuilders.size(); ListsecurityFilterChains = new ArrayList<>( chainSize); for (RequestMatcher ignoredRequest : ignoredRequests) { securityFilterChains.add(new DefaultSecurityFilterChain(ignoredRequest)); } for (SecurityBuilder extends SecurityFilterChain> securityFilterChainBuilder : securityFilterChainBuilders) { securityFilterChains.add(securityFilterChainBuilder.build()); } FilterChainProxy filterChainProxy = new FilterChainProxy(securityFilterChains); if (httpFirewall != null) { filterChainProxy.setFirewall(httpFirewall); } filterChainProxy.afterPropertiesSet(); Filter result = filterChainProxy; if (debugEnabled) { logger.warn(" " + "******************************************************************** " + "********** Security debugging is enabled. ************* " + "********** This may include sensitive information. ************* " + "********** Do not use in a production system! ************* " + "******************************************************************** "); result = new DebugFilter(filterChainProxy); } postBuildAction.run(); return result; }
首先計(jì)算出chainSize,也就是ignoredRequests.size() + securityFilterChainBuilders.size();,如果你不配置ignoredRequests,那就是securityFilterChainBuilders.size(),也就是HttpSecurity的個(gè)數(shù),其本質(zhì)上就是你一共配置幾個(gè)WebSecurityConfigurerAdapter,因?yàn)槊總€(gè)WebSecurityConfigurerAdapter對(duì)應(yīng)一個(gè)HttpSecurity,而所謂的ignoredRequests就是FilterChainProxy的請(qǐng)求,默認(rèn)是沒有的,如果你需要條跳過某些請(qǐng)求不需要認(rèn)證或授權(quán),可以如下配置:
@Override public void configure(WebSecurity web) throws Exception { web.ignoring().antMatchers("/statics/**"); }
在上面配置中,所有以/statics開頭請(qǐng)求都將被FilterChainProxy忽略。
計(jì)算完chainSize后,就會(huì)創(chuàng)建List
for (SecurityBuilder extends SecurityFilterChain> securityFilterChainBuilder : securityFilterChainBuilders) { securityFilterChains.add(securityFilterChainBuilder.build()); }
調(diào)用HtppSecurity的build()構(gòu)建其實(shí)和調(diào)用WebSecurity的build()構(gòu)建類類似,父類中方法一次被執(zhí)行,最后執(zhí)行本身的performBuild()方法,其源碼如下:
@Override protected DefaultSecurityFilterChain performBuild() throws Exception { Collections.sort(filters, comparator); return new DefaultSecurityFilterChain(requestMatcher, filters); }
構(gòu)建SecurityFilterChain主要是完成RequestMatcher和對(duì)應(yīng)的過濾器列表,我們都知道在Spring Security中,過濾器執(zhí)行按順序順序的,這個(gè)排序就是在performBuild()中完成的,也就是:
Collections.sort(filters, comparator);
它通過一個(gè)比較器實(shí)現(xiàn)了過濾器的排序,這個(gè)比較器就是FilterComparator,有興趣的朋友可以自己去了解詳情。
最后返回的是SecurityFilterChain的默認(rèn)實(shí)現(xiàn)DefaultSecurityFilterChain。
構(gòu)建完所有SecurityFilterChain后,創(chuàng)建最為重要的FilterChainProxy實(shí)例,
FilterChainProxy filterChainProxy = new FilterChainProxy(securityFilterChains);
構(gòu)造器中傳入SecurityFilterChain列表,如果開啟了Debug模式,還會(huì)被包裝成DebugFilter類型,共開發(fā)調(diào)試使用,默認(rèn)是關(guān)閉的,可以通過過下面方式開啟Debug模式:
@Override public void configure(WebSecurity web) throws Exception { web.debug(true); }
至此Spring Security 初始化完成,我們通過繼承WebSecurityConfigurerAdapter來代達(dá)到個(gè)性化配置目的,文中提到了三個(gè)重要的個(gè)性化入口,并且WebSecurityConfigurerAdapter是可以配置多個(gè)的,其對(duì)應(yīng)的接口就是會(huì)存在多個(gè)SecurityFilterChain實(shí)例,但是它們?nèi)巳匀辉谕粋€(gè)FilterChainProxy中,通過RequestMatcher來匹配并傳入到對(duì)應(yīng)的SecurityFilterChain中執(zhí)行請(qǐng)求。
(全文完)
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/74483.html
摘要:使用詳解由于公司新的后臺(tái)項(xiàng)目獨(dú)立,和其他服務(wù)沒有關(guān)系,所以考慮單獨(dú)實(shí)現(xiàn)自己的用戶登錄模塊。表單登錄具體流程如下圖本文參考地址 spring security使用詳解 由于公司新的后臺(tái)項(xiàng)目獨(dú)立,和其他服務(wù)沒有關(guān)系,所以考慮單獨(dú)實(shí)現(xiàn)自己的用戶登錄模塊。 所以,我將對(duì)spring security基于 springboot 框架的使用方式總結(jié)如下: (1)當(dāng)我們?cè)趐om文件中,添加...
摘要:使用詳解由于公司新的后臺(tái)項(xiàng)目獨(dú)立,和其他服務(wù)沒有關(guān)系,所以考慮單獨(dú)實(shí)現(xiàn)自己的用戶登錄模塊。表單登錄具體流程如下圖本文參考地址 spring security使用詳解 由于公司新的后臺(tái)項(xiàng)目獨(dú)立,和其他服務(wù)沒有關(guān)系,所以考慮單獨(dú)實(shí)現(xiàn)自己的用戶登錄模塊。 所以,我將對(duì)spring security基于 springboot 框架的使用方式總結(jié)如下: (1)當(dāng)我們?cè)趐om文件中,添加...
摘要:下一代服務(wù)端開發(fā)下一代服務(wù)端開發(fā)第部門快速開始第章快速開始環(huán)境準(zhǔn)備,,快速上手實(shí)現(xiàn)一個(gè)第章企業(yè)級(jí)服務(wù)開發(fā)從到語言的缺點(diǎn)發(fā)展歷程的缺點(diǎn)為什么是產(chǎn)生的背景解決了哪些問題為什么是的發(fā)展歷程容器的配置地獄是什么從到下一代企業(yè)級(jí)服務(wù)開發(fā)在移動(dòng)開發(fā)領(lǐng)域 《 Kotlin + Spring Boot : 下一代 Java 服務(wù)端開發(fā) 》 Kotlin + Spring Boot : 下一代 Java...
摘要:根據(jù)自己維護(hù)的倉庫信息和客戶端傳遞過來的配置定位信息去查找配置信息。通過命令將找到的配置信息下載到的文件系統(tǒng)中。該配置內(nèi)容的優(yōu)先級(jí)高于包內(nèi)部的配置內(nèi)容,在包中重復(fù)的內(nèi)容將不會(huì)被加載。在中配置注冊(cè)中心地址。 構(gòu)建配置中心 創(chuàng)建一個(gè)基礎(chǔ)Spring Boot工程,命名為config-server,并在pom.xml中引入以下依賴: org.spri...
閱讀 2022·2021-11-24 09:39
閱讀 1884·2019-08-30 15:55
閱讀 2177·2019-08-30 15:53
閱讀 576·2019-08-29 13:16
閱讀 991·2019-08-26 12:20
閱讀 2390·2019-08-26 11:58
閱讀 3155·2019-08-26 10:19
閱讀 3314·2019-08-23 18:31