SpringBoot自動配置


1.什么是springboot自動配置:Auto-Configuration

自動配置值得是基於引入依賴的jar包,對springboot應用進行自動配置。自動配置為springboot框架的“開箱即用”特點提供了基礎支撐

demo:在springboot中使用mongodb

引入 implementation 'org.springframework.boot:spring-boot-starter-data-mongodb'

配置mongo服務器

data:
  mongodb:
    collectionName: table-v2
    database: test
    uri: "mongodb://FID:password@\
                                                         hotname/?\
                                                         replicaSet=MGORPST_3004&ssl=true&sslInvalidHostNameAllowed=true"
 

直接使用mongoTemplate或者reactiveMongoTemplate
@Configuration
@RequiredArgsConstructor
@EnableConfigurationProperties(MongoCommonProperties.class)
@Slf4j
@Data
public class MongoConfig extends AbstractMongoClientConfiguration {
  private final MongoCommonProperties properties;

  @Value("${spring.data.mongodb.collectionName}")
  private String collectionName;

  @Value("${spring.data.mongodb.collectionName}-payload")
  private String payloadCollectionName;

  @Value("${spring.data.mongodb.maxLength}")
  private Integer maxLength;

  @Value("${spring.data.mongodb.useGridFs}")
  private boolean useGridFs;

  @Override
  public String getDatabaseName() {
    return properties.getDatabase();
  }

  private static MongoClient mongoClient = null;

  @Override
  public MongoClient mongoClient() {
    if (mongoClient == null) {
      String mongoUri = "";
      String password = "";
      if ("primary".equals(properties.getMongoType())) {
        mongoUri = properties.getUri();
        password = retrievePassword();
      } else {
        mongoUri = properties.getNyuri();
        password = new String(properties.getPassword());
        if (StringUtils.isEmpty(password)) {
          return null;
        }
      }
      ConnectionString connectionString =
          new ConnectionString(mongoUri.replace("password", password));
      MongoClientSettings mongoClientSettings =
          MongoClientSettings.builder().applyConnectionString(connectionString).build();
      mongoClient = MongoClients.create(mongoClientSettings);
    }
    return mongoClient;
  }

  @Primary
  @Bean(name = "mongoTemplate")
  public MongoTemplate getMongoTemplate() {
    if (mongoClient
        != null) { // close mongo client before recreate, because this will lead memory leak
      mongoClient.close();
      mongoClient = null;
    }
    log.info("mongo DB: {}", properties.getDatabase());
    MongoDatabaseFactory mongoDbFactory =
        new SimpleMongoClientDatabaseFactory(mongoClient(), properties.getDatabase());
    return new MongoTemplate(mongoDbFactory, getIndexEnabledMongoConverter(mongoDbFactory));
  }

  private static MongoConverter getIndexEnabledMongoConverter(MongoDatabaseFactory factory) {

    DbRefResolver dbRefResolver = new DefaultDbRefResolver(factory);
    MongoCustomConversions conversions = new MongoCustomConversions(Collections.emptyList());

    MongoMappingContext mappingContext = new MongoMappingContext();
    mappingContext.setSimpleTypeHolder(conversions.getSimpleTypeHolder());
    mappingContext.afterPropertiesSet();
    // This is enable auto index
    mappingContext.setAutoIndexCreation(true);

    MappingMongoConverter converter = new MappingMongoConverter(dbRefResolver, mappingContext);
    converter.setCustomConversions(conversions);
    converter.setCodecRegistryProvider(factory);
    converter.afterPropertiesSet();

    return converter;
  }

  /**
   * Retrieve password from CyberArk
   *
   * @return
   */
  public String retrievePassword() {
    StringBuilder stringBuilder = new StringBuilder();
    try {
      URL pass = new URL(properties.getPasswordURL());
      URLConnection yc = pass.openConnection();
      String inputLine;
      try (BufferedReader in = new BufferedReader(new InputStreamReader(yc.getInputStream())); ) {
        while ((inputLine = in.readLine()) != null) {
          stringBuilder.append(inputLine);
        }
      }
    } catch (IOException e) {
      log.error("Failed to retrieve password from {}", properties.getPasswordURL(), e);
    }
    return stringBuilder.toString();
  }

  @Bean
  public GridFsTemplate gridFsTemplate(
      MongoDatabaseFactory mongoDatabaseFactory, MappingMongoConverter mappingMongoConverter)
      throws Exception {
    return new GridFsTemplate(mongoDatabaseFactory, mappingMongoConverter);
  }

  @Override
  public boolean autoIndexCreation() {
    return true;
  }
}
View Code
 
         

 

 

 

直接用以上三步就可以在springboot中使用mongo,整個過程springboot自動完成mongo配置,將相關對象注入到IOC容器中 (面試問IOC時候可以從這個角度回答

2.默認自動配置類

Springboot通過自動配置可以自動加載一些需要的配置信息,引入了一個依賴:spring-boot-autoconfigure,其中定義了大量自動配置類

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</dependency>

 

2.自動配置實現原理

@EnableAutoConfiguration:開啟SpringBoot的自動配置,並且根據你引入的依賴來生效對應的默認配置(在springboot中不需要手動添加這個注解)

@Conditional :可以標注在類上面,表示該類下面的所有@Bean都會啟用配置,也可以標注在方法上面,只是對該方法啟用配置。

@ConditionalOnBean(僅僅在當前上下文中存在某個對象時,才會實例化一個Bean)
@ConditionalOnClass(某個class位於類路徑上,才會實例化一個Bean)
@ConditionalOnExpression(當表達式為true的時候,才會實例化一個Bean)
@ConditionalOnMissingBean(僅僅在當前上下文中不存在某個對象時,才會實例化一個Bean)
@ConditionalOnMissingClass(某個class類路徑上不存在的時候,才會實例化一個Bean)
@ConditionalOnNotWebApplication(不是web應用)

示例代碼:

Config類:

package com.fql.example.project.autoconfig.config;

import com.fql.example.project.autoconfig.service.TestService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**https://blog.csdn.net/wolf2s/article/details/122260211
 * Created by Administrator on 2022/1/15 0015.
 */
@Configuration
@Slf4j
public class TestStartServiceConfig {
    @Bean
    @ConditionalOnBean(TestService.class)           //--1
    //@ConditionalOnMissingBean(TestService.class)  //--2
    public TestService getTestService(){
        log.info("this is a testStartService");
        return new TestService();
    }

}

Service類:

package com.fql.example.project.autoconfig.service;

/**
 * Created by Administrator on 2022/1/16 0016.
 */
public class TestService {
}

Application類:

package com.fql.example.project;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.servlet.DispatcherServlet;

@SpringBootApplication
public class ProjectApplication {

    public static void main(String[] args) {
        SpringApplication.run(ProjectApplication.class, args);
    }

}

 

TestStartServiceConfig中設置為@ConditionalOnBean(TestService.class)輸出如下:

2022-01-17 10:36:38.421 INFO 1084 --- [ main] c.f.example.project.ProjectApplication : Starting ProjectApplication using Java 1.8.0_221 on PC-20190113KYFH with PID 1084 (D:\java\fqldemo\project\target\classes started by Administrator in D:\java\fqldemo\project)
2022-01-17 10:36:38.428 INFO 1084 --- [ main] c.f.example.project.ProjectApplication : No active profile set, falling back to default profiles: default
2022-01-17 10:36:39.946 INFO 1084 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
2022-01-17 10:36:39.957 INFO 1084 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2022-01-17 10:36:39.957 INFO 1084 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.56]
2022-01-17 10:36:40.070 INFO 1084 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2022-01-17 10:36:40.070 INFO 1084 --- [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 1567 ms
2022-01-17 10:36:40.483 INFO 1084 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
2022-01-17 10:36:40.497 INFO 1084 --- [ main] c.f.example.project.ProjectApplication : Started ProjectApplication in 2.649 seconds (JVM running for 3.319)

從控制台輸出可以發現沒有看到TestStartServiceConfig中打印log.info("this is a testStartService");這是因為TestStartService沒有實例化,如果我們把TestService改為

@Service
public class TestService {
}
那么輸出如下:

2022-01-17 10:39:01.381 INFO 8436 --- [ main] c.f.example.project.ProjectApplication : Starting ProjectApplication using Java 1.8.0_221 on PC-20190113KYFH with PID 8436 (D:\java\fqldemo\project\target\classes started by Administrator in D:\java\fqldemo\project)
2022-01-17 10:39:01.386 INFO 8436 --- [ main] c.f.example.project.ProjectApplication : No active profile set, falling back to default profiles: default
2022-01-17 10:39:02.956 INFO 8436 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
2022-01-17 10:39:02.967 INFO 8436 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2022-01-17 10:39:02.967 INFO 8436 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.56]
2022-01-17 10:39:03.085 INFO 8436 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2022-01-17 10:39:03.085 INFO 8436 --- [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 1618 ms
2022-01-17 10:39:03.154 INFO 8436 --- [ main] c.f.e.p.a.config.TestStartServiceConfig : this is a testStartService
2022-01-17 10:39:03.465 INFO 8436 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
2022-01-17 10:39:03.475 INFO 8436 --- [ main] c.f.example.project.ProjectApplication : Started ProjectApplication in 2.669 seconds (JVM running for 3.348)

 

TestStartServiceConfig中設置為@ConditionalOnMissingBean(TestService.class)輸出如下

2022-01-17 10:39:01.381 INFO 8436 --- [ main] c.f.example.project.ProjectApplication : Starting ProjectApplication using Java 1.8.0_221 on PC-20190113KYFH with PID 8436 (D:\java\fqldemo\project\target\classes started by Administrator in D:\java\fqldemo\project)
2022-01-17 10:39:01.386 INFO 8436 --- [ main] c.f.example.project.ProjectApplication : No active profile set, falling back to default profiles: default
2022-01-17 10:39:02.956 INFO 8436 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
2022-01-17 10:39:02.967 INFO 8436 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2022-01-17 10:39:02.967 INFO 8436 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.56]
2022-01-17 10:39:03.085 INFO 8436 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2022-01-17 10:39:03.085 INFO 8436 --- [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 1618 ms
2022-01-17 10:39:03.154 INFO 8436 --- [ main] c.f.e.p.a.config.TestStartServiceConfig : this is a testStartService
2022-01-17 10:39:03.465 INFO 8436 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
2022-01-17 10:39:03.475 INFO 8436 --- [ main] c.f.example.project.ProjectApplication : Started ProjectApplication in 2.669 seconds (JVM running for 3.348)

 

當然在這種情況下如果,把改為

@Service
public class TestService {
}

,則 this is a testStartService不會打印,具體輸出如下

2022-01-17 10:41:05.079 INFO 8632 --- [ main] c.f.example.project.ProjectApplication : Starting ProjectApplication using Java 1.8.0_221 on PC-20190113KYFH with PID 8632 (D:\java\fqldemo\project\target\classes started by Administrator in D:\java\fqldemo\project)
2022-01-17 10:41:05.083 INFO 8632 --- [ main] c.f.example.project.ProjectApplication : No active profile set, falling back to default profiles: default
2022-01-17 10:41:06.732 INFO 8632 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
2022-01-17 10:41:06.744 INFO 8632 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2022-01-17 10:41:06.744 INFO 8632 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.56]
2022-01-17 10:41:06.917 INFO 8632 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2022-01-17 10:41:06.917 INFO 8632 --- [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 1747 ms
2022-01-17 10:41:07.290 INFO 8632 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
2022-01-17 10:41:07.300 INFO 8632 --- [ main] c.f.example.project.ProjectApplication : Started ProjectApplication in 2.797 seconds (JVM running for 3.472)

 

補充:

@ConfigurationProperties

使用了@ConfigurationProperties配置之后,可以進一步簡化@Value()的使用,最后的結果會變成這個簡單

@Configuration
@Data
@Immutable
@ConfigurationProperties(prefix = "spring.kafka")
public class KafkaTopicConfig {

private String errorTopic;
private String successTopic;
}
等價於
@Configuration
@Data
@Immutable
public class KafkaTopicConfig {
  
@Value("${spring.profiles.errorTopic}")
  private String errorTopic;
@Value("${spring.profiles.successTopic}")
  private String successTopic;
}

 

參考:

https://blog.csdn.net/m0_46628950/article/details/125469964


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM