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

posted on 2022-01-17 10:41  colorfulworld  阅读(2005)  评论(0编辑  收藏  举报