So funktioniert die automatische Konfiguration von Spring Boot

Tiefes Eintauchen in die Welt der Spring Boot @ Conditional-Annotation mit gut entwickelten Beispielen für Implementierungen von Mongo und MySQL- Datenbankzugriffsklassen .


In meinem Beitrag „ Warum Spring Boot? "Die Erstellung einer Spring Boot-Anwendung wurde überprüft, anhand derer Sie kaum verstehen können, was sich hinter den Kulissen abspielt. Vielleicht möchten Sie die Magie der automatischen Konfiguration von Spring Boot verstehen.


Zuvor sollten Sie sich mit @ Bedingten Anmerkungen zu Spring vertraut machen , von denen alle Magie der automatischen Konfiguration von Spring Boot abhängt.


@ Bedingte Funktionen erkunden


Bei der Entwicklung von Anwendungen, die auf Spring basieren, müssen Sie möglicherweise Bean-Komponenten bedingt registrieren.


Sie können beispielsweise eine DataSource-Bean registrieren, die beim lokalen Start der Anwendung auf die DEV-Datenbank verweist, und auf eine andere PRODUCTION-Datenbank verweisen, wenn Sie in einer Produktionsumgebung arbeiten.


Sie können die Datenbankverbindungseinstellungen in die Eigenschaftendatei übertragen und die Datei verwenden, die der Umgebung entspricht. Sie müssen jedoch die Konfiguration ändern, wenn Sie eine andere Umgebung angeben und eine Anwendung erstellen müssen.


Spring 3.1 Profiles (). . , , .


@Configuration
public class AppConfig
{
     @Bean
     @Profile("DEV")
     public DataSource devDataSource() {
        ...
     }

     @Bean
     @Profile("PROD")
     public DataSource prodDataSource() {
        ...
     }
}

, System Property -Dspring.profiles.active = DEV.


, . bean-, , .


bean- Spring, Spring 4 @Conditional. @Conditional, , .


, , :


  • classpath
  • Spring bean ApplicationContext
  • /

, , .


, Spring's @Conditional.


, UserDAO . UserDAO, JdbcUserDAO, MySQL, MongoUserDAO, MongoDB.


JdbcUserDAO MongoUserDAO System Property, , dbType.


: java -jar myapp.jar -DdbType = MySQL, JdbcUserDAO. , : java -jar myapp.jar -DdbType = MONGO, MongoUserDAO.


JdbcUserDAO MongoUserDAO UserDAO :


public interface UserDAO
{
    List<String> getAllUserNames();
}
public class JdbcUserDAO implements UserDAO
{
    @Override
    public List<String> getAllUserNames()
    {
          System.out.println("**** Getting usernames from RDBMS *****");
          return Arrays.asList("Siva","Prasad","Reddy");
    }
}
public class MongoUserDAO implements UserDAO
{
    @Override
    public List<String> getAllUserNames()
    {
          System.out.println("**** Getting usernames from MongoDB *****");
          return Arrays.asList("Bond","James","Bond");
    }
}

Condition MySQLDatabaseTypeCondition, , System Property dbType «MYSQL» :


public class MySQLDatabaseTypeCondition implements Condition
{
    @Override
    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata metadata)
    {
        String enabledDBType = System.getProperty("dbType");
        return (enabledDBType != null && enabledDBType.equalsIgnoreCase("MYSQL"));
    }
}

Condition MongoDBDatabaseTypeCondition, , System Property dbType «MONGODB» :


public class MongoDBDatabaseTypeCondition implements Condition
{
    @Override
    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata metadata)
    {
        String enabledDBType = System.getProperty("dbType");
        return (enabledDBType != null && enabledDBType.equalsIgnoreCase("MONGODB"));
    }
}

bean- JdbcUserDAO MongoUserDAO, @Conditional :


@Configuration
public class AppConfig
{
    @Bean
    @Conditional(MySQLDatabaseTypeCondition.class)
    public UserDAO jdbcUserDAO(){
        return new JdbcUserDAO();
    }

    @Bean
    @Conditional(MongoDBDatabaseTypeCondition.class)
    public UserDAO mongoUserDAO(){
        return new MongoUserDAO();
    }
}

: java -jar myapp.jar -DdbType = MYSQL, bean- JdbcUserDAO.


System property: -DdbType = MONGODB, bean- MongoUserDAO.


, System Property.


, bean- MongoUserDAO , classpath Java MongoDB "com.mongodb.Server", , bean- JdbcUserDAO.


Condition MongoDB "com.mongodb.Server" :


public class MongoDriverPresentsCondition implements Condition
{
    @Override
    public boolean matches(ConditionContext conditionContext,AnnotatedTypeMetadata metadata)
    {
        try {
            Class.forName("com.mongodb.Server");
            return true;
        } catch (ClassNotFoundException e) {
            return false;
        }
    }
}

public class MongoDriverNotPresentsCondition implements Condition
{
    @Override
    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata metadata)
    {
        try {
            Class.forName("com.mongodb.Server");
            return false;
        } catch (ClassNotFoundException e) {
            return true;
        }
    }
}

, bean- classpath.


bean- MongoUserDAO, Spring- UserDAO .


Condition, , - bean- , :


public class UserDAOBeanNotPresentsCondition implements Condition
{
    @Override
    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata metadata)
    {
         UserDAO userDAO = conditionContext.getBeanFactory().getBean(UserDAO.class);
         return (userDAO == null);
    }
}

bean- MongoUserDAO, app.dbType = MONGO?


Condition :


public class MongoDbTypePropertyCondition implements Condition
{
    @Override
    public boolean matches(ConditionContext conditionContext,
    AnnotatedTypeMetadata metadata)
    {
        String dbType = conditionContext.getEnvironment()
                            .getProperty("app.dbType");
        return "MONGO".equalsIgnoreCase(dbType);
    }
}

Condition. Condition . Condition MYSQL MongoDB DatabaseType :


@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Conditional(DatabaseTypeCondition.class)
public @interface DatabaseType
{
    String value();
}

DatabaseTypeCondition, DatabaseType :


public class DatabaseTypeCondition implements Condition
{
    @Override
    public boolean matches(ConditionContext conditionContext,
 AnnotatedTypeMetadata metadata)
    {
        Map<String, Object> attributes = metadata.getAnnotationAttributes(DatabaseType.class.getName());
        String type = (String) attributes.get("value");
        String enabledDBType = System.getProperty("dbType","MYSQL");
        return (enabledDBType != null && type != null && enabledDBType.equalsIgnoreCase(type));
    }
}

@DatabaseType :


@Configuration
@ComponentScan
public class AppConfig
{
    @Bean
    @DatabaseType("MYSQL")
    public UserDAO jdbcUserDAO(){
        return new JdbcUserDAO();
    }

    @Bean
    @DatabaseType("MONGO")
    public UserDAO mongoUserDAO(){
        return new MongoUserDAO();
    }
}

DatabaseType dbType , , .


, , , @Conditional.


Spring Boot @Conditional bean- .


Condition, SpringBoot org.springframework.boot.autoconfigure spring-boot-autoconfigure-{version}.jar.


Spring Boot @Conditional , .


?


, .


Spring Boot AutoConfiguration


Spring Boot — @EnableAutoConfiguration. , , @SpringBootApplication, , , :


@Configuration
@EnableAutoConfiguration
@ComponentScan
public class Application
{

}

@EnableAutoConfiguration Spring ApplicationContext , .


Spring Boot AutoConfiguration spring-boot-autoconfigure-{version}.jar, .


AutoConfiguration @Configuration, Spring, @EnableConfigurationProperties .


, org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration.


@Configuration
@ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class })
@EnableConfigurationProperties(DataSourceProperties.class)
@Import({ Registrar.class, DataSourcePoolMetadataProvidersConfiguration.class })
public class DataSourceAutoConfiguration 
{
    ...
    ...
    @Conditional(DataSourceAutoConfiguration.EmbeddedDataSourceCondition.class)
    @ConditionalOnMissingBean({ DataSource.class, XADataSource.class })
    @Import(EmbeddedDataSourceConfiguration.class)
    protected static class EmbeddedConfiguration {

    }

    @Configuration
    @ConditionalOnMissingBean(DataSourceInitializer.class)
    protected static class DataSourceInitializerConfiguration {
        @Bean
        public DataSourceInitializer dataSourceInitializer() {
        return new DataSourceInitializer();
        }
    }

    @Conditional(DataSourceAutoConfiguration.NonEmbeddedDataSourceCondition.class)
    @ConditionalOnMissingBean({ DataSource.class, XADataSource.class })
    protected static class NonEmbeddedConfiguration {
        @Autowired
        private DataSourceProperties properties;

        @Bean
        @ConfigurationProperties(prefix = DataSourceProperties.PREFIX)
        public DataSource dataSource() {
            DataSourceBuilder factory = DataSourceBuilder
                    .create(this.properties.getClassLoader())
                    .driverClassName(this.properties.getDriverClassName())
                    .url(this.properties.getUrl()).username(this.properties.getUsername())
                    .password(this.properties.getPassword());
            if (this.properties.getType() != null) {
                factory.type(this.properties.getType());
            }
            return factory.build();
        }
    }
    ...
    ...
    @Configuration
    @ConditionalOnProperty(prefix = "spring.datasource", name = "jmx-enabled")
    @ConditionalOnClass(name = "org.apache.tomcat.jdbc.pool.DataSourceProxy")
    @Conditional(DataSourceAutoConfiguration.DataSourceAvailableCondition.class)
    @ConditionalOnMissingBean(name = "dataSourceMBean")
    protected static class TomcatDataSourceJmxConfiguration {
        @Bean
        public Object dataSourceMBean(DataSource dataSource) {
        ....
        ....
        }
    }
    ...
    ...
}

DataSourceAutoConfiguration @ConditionalOnClass({DataSource.class,EmbeddedDatabaseType.class}), , bean- DataSourceAutoConfiguration , DataSource.class EmbeddedDatabaseType.class classpath.


@EnableConfigurationProperties(DataSourceProperties.class), application.properties DataSourceProperties.


@ConfigurationProperties(prefix = DataSourceProperties.PREFIX)
public class DataSourceProperties implements BeanClassLoaderAware, EnvironmentAware, InitializingBean {

    public static final String PREFIX = "spring.datasource";
    ...
    ...
    private String driverClassName;
    private String url;
    private String username;
    private String password;
    ...
    //setters and getters
}

, spring.datasource.*, DataSourceProperties.


spring.datasource.url=jdbc:mysql://localhost:3306/test
spring.datasource.username=root
spring.datasource.password=secret
spring.datasource.driver-class-name=com.mysql.jdbc.Driver

bean-, SpringBoot, @ConditionalOnMissingBean, @ConditionalOnClass @ConditionalOnProperty ..


bean- ApplicationContext, .


spring-boot-autoconfigure-{version}.jar, :


  • org.springframework.boot.autoconfigure.web.DispatcherServletAutoConfiguration
  • org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration
  • org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration
  • org.springframework.boot.autoconfigure.jackson.JacksonAutoConfigurationetc usw.

Ich hoffe, Sie haben jetzt ein Verständnis dafür, wie die automatische Konfiguration von Spring Boot mithilfe verschiedener Autokonfigurationsklassen zusammen mit @ Bedingten Funktionen funktioniert .


All Articles