亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

SpringBoot外部化配置使用Plus版的方法示例

 更新時(shí)間:2020年05月27日 09:25:53   作者:早知今日  
這篇文章主要介紹了SpringBoot外部化配置使用Plus版的方法示例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

PS: 之前寫過一篇關(guān)于 SpringBoo 中使用配置文件的一些姿勢(shì),不過嘛,有句話(我)說的好:曾見小橋流水,未睹觀音坐蓮!所以再寫一篇增強(qiáng)版,以便記錄。

序言

上一篇博客記錄,主要集中在具體的配置內(nèi)容,也就是使用 @ConfigurationProperties 這個(gè)注解來進(jìn)行配置與結(jié)構(gòu)化對(duì)象的綁定,雖然也順帶說了下 @Value 的使用以及其區(qū)別。

在這篇記錄中,打算從總覽,鳥瞰的俯視視角,來從整體上對(duì) SpringBoot ,乃至 Spring Framework 對(duì)于外部化配置文件處理,以及配置參數(shù)的綁定操作,是如果處理的、怎么設(shè)計(jì)的。

這里其實(shí)主要說的是 SpringBoot ,雖然 @Value 屬于 Spring Framework 的注解,不過在 SpringBoot 中也被頻繁使用。

SpringBoot 版本: 2.2.6.RELEASE

SpringBoot啟動(dòng)流程簡(jiǎn)介

在 SpringBoot 的啟動(dòng)過程中,大體上分為三步

第一步: prepareEnvironment ,準(zhǔn)備 SpringBoot 執(zhí)行時(shí)所有的配置。

第二步: prepareContext ,根據(jù)啟動(dòng)時(shí)的傳入的配置類,創(chuàng)建其 BeanDefinition 。

第三步: refreshContext ,真正啟動(dòng)上下文。

在這上面三步中,第一步結(jié)束后,我們所需要的或者配置文件配置的內(nèi)容,大部分已經(jīng)被加載進(jìn)來,然后在第三步中進(jìn)行配置的注入或者綁定操作。

至于為什么是大部分,后面會(huì)有解釋。

將配置從配置文件加載到Environment中,使用的是事件通知的方式。

本篇博客記錄僅僅聚焦第一步中如何讀取配置文件的分析,順帶介紹下第三步的注入和綁定。

受限于技術(shù)水平,僅能達(dá)到這個(gè)程度

外部化配置方式

如果有看到 SpringBoot 官網(wǎng)關(guān)于外部化配置的說明,就會(huì)驚訝的發(fā)現(xiàn),原來 SpringBoot 有那么多的配置來源。

SpringBoot 關(guān)于外部化配置特性的文檔說明,直達(dá) 地址 。

而實(shí)際使用中,通??赡軙?huì)使用的比較多的是通過以下這些 方式

commandLine

通過在啟動(dòng)jar時(shí),加上 -DconfigKey=configValue 或者 --configKey=configValue 的方式,來進(jìn)行配置,多個(gè)配置項(xiàng)用空格分隔。

這種使用場(chǎng)景也多,只是一般用于一些配置內(nèi)容很少且比較關(guān)鍵的配置,比如說可以決定運(yùn)行環(huán)境的配置。

不易進(jìn)行比較多的或者配置內(nèi)容比較冗長(zhǎng)的配置,容易出錯(cuò),且不便于維護(hù)管理。

application

這種是 SpringBoot 提供的,用于簡(jiǎn)便配置的一種方式,只要我們將應(yīng)用程序所用到的配置,直接寫到 application.properties 中,并將文件放置于以下四個(gè)位置即可 。

  1. 位于 jar 同目錄的 config 目錄下的 application.properties
  2. 位于 jar 同目錄的 application.properties
  3. classpath 下的 config 內(nèi) application.properties
  4. classpath 下的 application.properties

以上配置文件類型也都可以使用yml

默認(rèn)情況下,這種方式是 SpringBoot 約定好的一種方式,文件名必須為 application ,文件內(nèi)容格式可以為 Yaml 或者 Properties ,也許支持 XML ,因?yàn)榭丛创a是支持的,沒有實(shí)踐。

好處就是簡(jiǎn)單,省心省事,我們只需關(guān)注文件本身的內(nèi)容就可,其他的無需關(guān)心,這也是 SpringBoot 要追求的結(jié)果。

缺點(diǎn)也很明顯,如果配置內(nèi)容比較冗長(zhǎng),為了便于管理維護(hù),增加可讀性,必須要對(duì)配置文件進(jìn)行切分,通過功能等維度進(jìn)行分類分組,使用多個(gè)配置文件來進(jìn)行存放配置數(shù)據(jù)。

SpringBoot 也想到了這些問題,因此提供了下面兩個(gè)比較方便的使用方式,來應(yīng)對(duì)這種情況

profiles

profiles 本身是也是一個(gè)配置項(xiàng),它提供一種方式將部分應(yīng)用程序配置進(jìn)行隔離,并且使得它僅在具體某一個(gè)環(huán)境中可用。

具體實(shí)踐中常用的主要是針對(duì)不同的環(huán)境,有開發(fā)環(huán)境用到的特有配置值,有測(cè)試環(huán)境特有的配置,有生產(chǎn)環(huán)境特有的配置,包括有些 Bean 根據(jù)環(huán)境選擇決定是否進(jìn)行實(shí)例化,這些都是通過 profiles 來實(shí)現(xiàn)的。不過這里只關(guān)注配置這一塊內(nèi)容。

它的使用方式通常是 spring.profiles.active=dev,dev1 或者 spring.profiles.include=db1,db2

這里可以看到有兩種不同的用法,這兩種方式是有區(qū)別的。

如果在 application.properties 中定義了一個(gè) spring.profiles.active=dev ,而后在啟動(dòng)時(shí)通過 命令行又寫了個(gè) --spring.profiles.active=test ,那么最終使用的是 test ,而不是 dev 。

如果同樣的場(chǎng)景下,使用 spring.profiles.include 來替換 spring.profiles.active ,那么結(jié)果會(huì)是 dev 和 test 都會(huì)存在,而不是替換的行為 。

這就是兩個(gè)之間的差別,這種差別也使得他們使用的場(chǎng)景并不一樣, active 更適合那些需要互斥的環(huán)境,而 include 則是多個(gè)并存的配置。

僅僅配置了 profiles 是沒有意義的,必須要有相應(yīng)的配置文件配合一起使用,而且這些配置文件的命名要符合一定的規(guī)則,否則配置文件不會(huì)被加載進(jìn) Environment 的。

profiles 文件的命名規(guī)則為 application-*.properties ,同樣的, application.properties 能放置的位置它也可以,不能的,它也不可以。

propery source

注解 @PropertySource 可以寫在配置類上,并且指定要讀取的配置文件路徑,這個(gè)路徑可以是絕對(duì)路徑,也可以是相對(duì)路徑。

它可以有以下幾種配置

  • @PropertySource("/config.properties")
  • @PropertySource("config.properties")
  • @PropertySource("file:/usr/local/config.properties")
  • @PropertySource("file:./config.properties")
  • @PropertySource("${pathPrefix}/config.properties")

其中1和2兩種方式是一樣的,都是從 classpath 去開始查找的

3和4是使用文件系統(tǒng)的絕對(duì)和相對(duì)路徑的方式,這里絕對(duì)路徑比較好理解 ,相對(duì)路徑則是從項(xiàng)目的根目錄作為相對(duì)目錄的

5是結(jié)合 SpEL 的表達(dá)式來使用的,可以直接從環(huán)境中獲取配置好的路徑。

以上幾種方式在實(shí)際開發(fā)中遇到和 SpringBoot 相關(guān)的配置,基本都能應(yīng)付過來了。

不過對(duì)于上面配置的一些原理性的內(nèi)容,還沒有提到 ,下面會(huì)簡(jiǎn)單說一下 SpringBoot 關(guān)于配置更詳細(xì)的處理,以及配置的優(yōu)先級(jí)的問題。

原理淺入淺出

帶著問題去找原因,比較有目的性和針對(duì)性,效果也相對(duì)好一些。

所以這里描述幾個(gè)會(huì)引起疑問的現(xiàn)象

默認(rèn)情況下自動(dòng)加載的配置文件命名必須要是 application

在使用 application.properties 時(shí),可以同時(shí)在四個(gè)位置放置配置,配置的優(yōu)先級(jí)就是上面羅列時(shí)顯示的優(yōu)先級(jí)。同樣的配置,優(yōu)先級(jí)高的生效,優(yōu)先級(jí)低的忽略。

profiles 引入的配置,也準(zhǔn)守同樣的優(yōu)先級(jí)規(guī)則

命令行配置具有最高優(yōu)先級(jí)

有些配置不能使用 @PropertySource 的方式進(jìn)行注入,比如日志的配置。

如果一個(gè)配置類使用了 @ConfigurationProperties ,然后字段使用了 @Value , @ConfigurationProperties 先被處理, @Value 后被處理。

源碼簡(jiǎn)讀

SpringBoot 讀取 application.properties 配置

查看 org.springframework.boot.context.config.ConfigFileApplicationListener 的源碼

public class ConfigFileApplicationListener implements EnvironmentPostProcessor, SmartApplicationListener, Ordered {
 // Note the order is from least to most specific (last one wins)
 // 默認(rèn)檢索配置文件的路徑,優(yōu)先級(jí)越來越高,
 // 可以通過 spring.config.location重新指定,要早于當(dāng)前類執(zhí)行時(shí)配置好
 private static final String DEFAULT_SEARCH_LOCATIONS = "classpath:/,classpath:/config/,file:./,file:./config/";
 // 默認(rèn)的配置名,可以通過命令行配置--spring.config.name=xxx來重新指定
 // 不通過命令行也可以通過其他方式,環(huán)境變量這些。
 private static final String DEFAULT_NAMES = "application";
 
 private class Loader {
 // 找到配置的路徑
 private Set<String> getSearchLocations() {
  if (this.environment.containsProperty(CONFIG_LOCATION_PROPERTY)) {
  return getSearchLocations(CONFIG_LOCATION_PROPERTY);
  }
  Set<String> locations = getSearchLocations(CONFIG_ADDITIONAL_LOCATION_PROPERTY);
  locations.addAll(
  asResolvedSet(ConfigFileApplicationListener.this.searchLocations, DEFAULT_SEARCH_LOCATIONS));
  return locations;
 }
 // 解析成Set
 private Set<String> asResolvedSet(String value, String fallback) {
 List<String> list = Arrays.asList(StringUtils.trimArrayElements(StringUtils.commaDelimitedListToStringArray(
 (value != null) ? this.environment.resolvePlaceholders(value) : fallback)));
 // 這里會(huì)做一個(gè)反轉(zhuǎn),也就是配置的路徑中,放在后面的優(yōu)先級(jí)越高
  Collections.reverse(list);
 return new LinkedHashSet<>(list);
 }
 private Set<String> getSearchNames() {
 if (this.environment.containsProperty(CONFIG_NAME_PROPERTY)) {
 String property = this.environment.getProperty(CONFIG_NAME_PROPERTY);
 return asResolvedSet(property, null);
 }
 return asResolvedSet(ConfigFileApplicationListener.this.names, DEFAULT_NAMES);
 }
 } 
}

命令行的配置具有最高優(yōu)先級(jí)

protected void configurePropertySources(ConfigurableEnvironment environment, String[] args) {
 MutablePropertySources sources = environment.getPropertySources();
 if (this.defaultProperties != null && !this.defaultProperties.isEmpty()) {
 sources.addLast(new MapPropertySource("defaultProperties", this.defaultProperties));
 }
 // 支持從命令行添加屬性以及存在參數(shù)時(shí)
 if (this.addCommandLineProperties && args.length > 0) {
 String name = CommandLinePropertySource.COMMAND_LINE_PROPERTY_SOURCE_NAME;
 // 這里是看下是不是存在同名的配置了
 if (sources.contains(name)) {
  PropertySource<?> source = sources.get(name);
  CompositePropertySource composite = new CompositePropertySource(name);
  composite.addPropertySource(
  new SimpleCommandLinePropertySource("springApplicationCommandLineArgs", args));
  composite.addPropertySource(source);
  sources.replace(name, composite);
 }
 else {
  // 直接添加,并且是添加到第一個(gè)位置,具有最高優(yōu)先級(jí)
  sources.addFirst(new SimpleCommandLinePropertySource(args));
 }
 }
}

@PropertySource 是在 refreshContext 階段,執(zhí)行 BeanDefinitionRegistryPostProcessor 時(shí)處理的

// org.springframework.context.annotation.ConfigurationClassParser#processPropertySource
private void processPropertySource(AnnotationAttributes propertySource) throws IOException {
 String name = propertySource.getString("name");
 if (!StringUtils.hasLength(name)) {
 name = null;
 }
 String encoding = propertySource.getString("encoding");
 if (!StringUtils.hasLength(encoding)) {
 encoding = null;
 }
 // 獲取配置的文件路徑
 String[] locations = propertySource.getStringArray("value");
 Assert.isTrue(locations.length > 0, "At least one @PropertySource(value) location is required");
 boolean ignoreResourceNotFound = propertySource.getBoolean("ignoreResourceNotFound");
 // 指定的讀取配置文件的工廠
 Class<? extends PropertySourceFactory> factoryClass = propertySource.getClass("factory");
 // 沒有就用默認(rèn)的 
 PropertySourceFactory factory = (factoryClass == PropertySourceFactory.class ?
  DEFAULT_PROPERTY_SOURCE_FACTORY : BeanUtils.instantiateClass(factoryClass));
 // 循環(huán)加載
 for (String location : locations) {
 try {
  // 會(huì)解析存在占位符的情況
  String resolvedLocation = this.environment.resolveRequiredPlaceholders(location);
  // 使用DefaultResourceLoader來加載資源
  Resource resource = this.resourceLoader.getResource(resolvedLocation);
  // 創(chuàng)建PropertySource對(duì)象
  addPropertySource(factory.createPropertySource(name, new EncodedResource(resource, encoding)));
 }
 catch (IllegalArgumentException | FileNotFoundException | UnknownHostException ex) {
  // Placeholders not resolvable or resource not found when trying to open it
  if (ignoreResourceNotFound) {
  if (logger.isInfoEnabled()) {
   logger.info("Properties location [" + location + "] not resolvable: " + ex.getMessage());
  }
  }
  else {
  throw ex;
  }
 }
 }
}

因?yàn)閳?zhí)行時(shí)機(jī)的問題,有些配置不能使用 @PropertySource ,因?yàn)檫@個(gè)時(shí)候?qū)τ行┡渲脕碚f,如果使用這種配置方式,黃花菜都涼了。同時(shí)這個(gè)注解要配合 @Configuration 注解一起使用才能生效,使用 @Component 是不行的。

處理 @ConfigurationProperty 的處理器是一個(gè) BeanPostProcessor ,處理 @Value 的也是一個(gè) BeanPostProcessor ,不過他倆的優(yōu)先級(jí)并不一樣,

// @ConfigurationProperty
public class ConfigurationPropertiesBindingPostProcessor
 implements BeanPostProcessor, PriorityOrdered, ApplicationContextAware, InitializingBean {
 @Override
 public int getOrder() {
 return Ordered.HIGHEST_PRECEDENCE + 1;
 }

}
// @Value
public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter
 implements MergedBeanDefinitionPostProcessor, PriorityOrdered, BeanFactoryAware {
 private int order = Ordered.LOWEST_PRECEDENCE - 2;
 @Override
 public int getOrder() {
 return this.order;
 }
}

從上面可以看出處理 @ConfigurationProperty 的 BeanPostProcessor 優(yōu)先級(jí)很高,而 @Value 的 BeanPostProcessor 優(yōu)先級(jí)很低。

使用 @Value 注入時(shí),要求配置的 key 必須存在于 Environment 中的,否則會(huì)終止啟動(dòng),而 @ConfigurationProperties 則不會(huì)。

@Value 可以支持 SpEL 表達(dá)式,也支持占位符的方式。

自定義配置讀取

org.springframework.boot.context.config.ConfigFileApplicationListener 是一個(gè)監(jiān)聽器,同時(shí)也是一個(gè) EnvironmentPostProcessor ,在有 ApplicationEnvironmentPreparedEvent 事件觸發(fā)時(shí),會(huì)去處理所有的 EnvironmentPostProcessor 的實(shí)現(xiàn)類,同時(shí)這些個(gè)實(shí)現(xiàn)也是使用 SpringFactoriesLoader 的方式來加載的。

對(duì)于配置文件的讀取,就是使用的這種方式。

@Override
public void onApplicationEvent(ApplicationEvent event) {
 if (event instanceof ApplicationEnvironmentPreparedEvent) {
 onApplicationEnvironmentPreparedEvent((ApplicationEnvironmentPreparedEvent) event);
 }
 if (event instanceof ApplicationPreparedEvent) {
 onApplicationPreparedEvent(event);
 }
}
private void onApplicationEnvironmentPreparedEvent(ApplicationEnvironmentPreparedEvent event) {
 List<EnvironmentPostProcessor> postProcessors = loadPostProcessors();
 postProcessors.add(this);
 AnnotationAwareOrderComparator.sort(postProcessors);
 for (EnvironmentPostProcessor postProcessor : postProcessors) {
 postProcessor.postProcessEnvironment(event.getEnvironment(), event.getSpringApplication());
 }
}

有了這個(gè)擴(kuò)展點(diǎn)后,我們就能自己定義讀取任何配置,從任何地方。

只要實(shí)現(xiàn)了 EnvironmentPostProcessor 接口,并且在 META-INF/spring.factories 中配置一下

org.springframework.boot.env.EnvironmentPostProcessor=com.example.configuration.ConfigurationFileLoader

附一個(gè)自己寫的例子

public class ConfigurationFileLoader implements EnvironmentPostProcessor {

 private static final String DEFAULT_SEARCH_LOCATIONS = "classpath:/,classpath:/config/,file:./,file:./config/";
 private static final String DEFAULT_NAMES = "download";
 private static final String DEFAULT_FILE_EXTENSION = ".yml";


 @Override
 public void postProcessEnvironment (ConfigurableEnvironment environment,
     SpringApplication application) {

 List<String> list = Arrays.asList(StringUtils.trimArrayElements(
  StringUtils.commaDelimitedListToStringArray(DEFAULT_SEARCH_LOCATIONS)));
 Collections.reverse(list);
 Set<String> reversedLocationSet = new LinkedHashSet(list);
 ResourceLoader defaultResourceLoader = new DefaultResourceLoader();
 YamlPropertiesFactoryBean yamlPropertiesFactoryBean = new YamlPropertiesFactoryBean();
 List<Properties> loadedProperties = new ArrayList<>(2);
 reversedLocationSet.forEach(location->{
  Resource resource = defaultResourceLoader.getResource(location + DEFAULT_NAMES+DEFAULT_FILE_EXTENSION);
  if (resource == null || !resource.exists()) {
  return;
  }
  yamlPropertiesFactoryBean.setResources(resource);
  Properties properties = yamlPropertiesFactoryBean.getObject();
  loadedProperties.add(properties);
 });

 Properties filteredProperties = new Properties();
 Set<Object> addedKeys = new LinkedHashSet<>();
 for (Properties propertySource : loadedProperties) {
  for (Object key : propertySource.keySet()) {
  String stringKey = (String) key;
  if (addedKeys.add(key)) {
   filteredProperties.setProperty(stringKey, propertySource.getProperty(stringKey));
  }

  }
 }
 PropertiesPropertySource propertySources = new PropertiesPropertySource(DEFAULT_NAMES, filteredProperties);
 environment.getPropertySources().addLast(propertySources);
 }
}

基本上都是 參考 ConfigFileApplicationListener 寫的 ,不過這里實(shí)現(xiàn)的功能,其實(shí)可以通過 @PropertySource 來 解決,只是當(dāng)時(shí)不知道。

使用 @PropertySource 的話,這么寫 @PropertySource("file:./download.properties") 即可。

個(gè)人猜測(cè) SpringBoot 從配置中心加載配置就是使用的這個(gè)方式,不過由于沒有實(shí)際看過相關(guān)源碼確認(rèn),不敢說一定是的 ,但是應(yīng)該是八九不離十 的 。

總結(jié)

這篇記錄寫的有點(diǎn)亂,一個(gè)是涉及到東西感覺也不少,還有就是本身有些地方不怎么了解,花費(fèi)的時(shí)間不夠。

不過對(duì) SpringBoot 的外部化配置來說,就是將各個(gè)途徑加載進(jìn)來的配置,統(tǒng)一收歸 Environment 的 MutablePropertySources 字段,這個(gè)字段是一個(gè) ArrayList ,保持添加進(jìn)來時(shí)的順序,因此查找也是按照這個(gè)順序查找,查找時(shí)查到即返回,不會(huì)完全遍歷所有的配置,除非遇到不存在的。

整個(gè)設(shè)計(jì)思想就是使用集中所有的配置,進(jìn)行優(yōu)先級(jí)排序,最后在有需要獲取配置的地方,從 Environment 對(duì)象中查找配置項(xiàng)。

對(duì)一般使用來說,關(guān)注點(diǎn)就是配置文件的位置,配置文件的名,以及優(yōu)先級(jí),這三個(gè)方面比較關(guān)心。

這篇記錄也基本能解答這幾個(gè)疑問,完成了寫這篇記錄的初衷。

到此這篇關(guān)于SpringBoot外部化配置使用Plus版的方法示例的文章就介紹到這了,更多相關(guān)SpringBoot外部化配置Plus版內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • java?Stream流常見操作方法(反射,類加載器,類加載,反射)

    java?Stream流常見操作方法(反射,類加載器,類加載,反射)

    這篇文章主要介紹了java?Stream流常見操作方法(反射,類加載器,類加載,反射),文章圍繞主題展開詳細(xì)的內(nèi)容介紹,展開詳細(xì)的內(nèi)容介紹,具有一定參考價(jià)值,感興趣的小伙伴可以參考一下
    2022-06-06
  • 使用idea遠(yuǎn)程調(diào)試jar包的配置過程

    使用idea遠(yuǎn)程調(diào)試jar包的配置過程

    這篇文章主要介紹了使用idea遠(yuǎn)程調(diào)試jar包的配置過程,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-09-09
  • IDEA無法創(chuàng)建JDK1.8版本的Springboot項(xiàng)目問題解決(2種方法)

    IDEA無法創(chuàng)建JDK1.8版本的Springboot項(xiàng)目問題解決(2種方法)

    本文主要介紹了IDEA無法創(chuàng)建JDK1.8版本的Springboot項(xiàng)目問題解決,包含兩種解決方案,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2024-07-07
  • Spring?boot異步任務(wù)原理全面分析

    Spring?boot異步任務(wù)原理全面分析

    這篇文章主要介紹了Spring?boot異步任務(wù)原理,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-11-11
  • Java ObjectMapper使用詳解

    Java ObjectMapper使用詳解

    ObjectMapper類是Jackson的主要類,它可以幫助我們快速的進(jìn)行各個(gè)類型和Json類型的相互轉(zhuǎn)換,本文給大家介紹Java ObjectMapper的相關(guān)知識(shí),感興趣的朋友跟隨小編一起看看吧
    2024-07-07
  • Java對(duì)象簡(jiǎn)單實(shí)用案例之計(jì)算器實(shí)現(xiàn)代碼

    Java對(duì)象簡(jiǎn)單實(shí)用案例之計(jì)算器實(shí)現(xiàn)代碼

    這篇文章主要為大家詳細(xì)介紹了Java對(duì)象簡(jiǎn)單實(shí)用案例之計(jì)算器實(shí)現(xiàn)代碼
    2016-11-11
  • 使用java + selenium + OpenCV破解網(wǎng)易易盾滑動(dòng)驗(yàn)證碼的示例

    使用java + selenium + OpenCV破解網(wǎng)易易盾滑動(dòng)驗(yàn)證碼的示例

    這篇文章主要介紹了使用java + selenium + OpenCV破解網(wǎng)易易盾滑動(dòng)驗(yàn)證碼,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-02-02
  • Java構(gòu)造函數(shù)與普通函數(shù)用法詳解

    Java構(gòu)造函數(shù)與普通函數(shù)用法詳解

    本篇文章給大家詳細(xì)講述了Java構(gòu)造函數(shù)與普通函數(shù)用法以及相關(guān)知識(shí)點(diǎn),對(duì)此有興趣的朋友可以參考學(xué)習(xí)下。
    2018-03-03
  • @RunWith(SpringJUnit4ClassRunner.class)報(bào)錯(cuò)問題及解決

    @RunWith(SpringJUnit4ClassRunner.class)報(bào)錯(cuò)問題及解決

    這篇文章主要介紹了@RunWith(SpringJUnit4ClassRunner.class)報(bào)錯(cuò)問題及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-04-04
  • SpringCloud的Config配置中心詳解

    SpringCloud的Config配置中心詳解

    這篇文章主要介紹了SpringCloud的Config配置中心詳解,SpringCloud Config為微服務(wù)架構(gòu)中的微服務(wù)提供集中化的外部配置支持,配置服務(wù)器為各個(gè)不同微服務(wù)應(yīng)用的所有環(huán)境提供了一個(gè)中心化的外部配置,需要的朋友可以參考下
    2023-07-07

最新評(píng)論