zoukankan      html  css  js  c++  java
  • Spring Boot . 3 -- Spring Boot Auto_configuration 是如何实现的?

        配置是Spring 框架的重要核心之一,所以Spring 应用能够正常的跑起来肯定是需要配置的,但是使用的Spring Boot 后很多配置没有做,那么AUTO-CONFIGURATION 到底是怎么发生的呢?发生的顺序和步骤是怎样的?怎么实现的呢? 

        在应用中使用Spring Boot的时候,spring-boot-autoconfigure这个jar包会被引入进来,这个Jar包里面包含了一些配置类。这个包里的所有都在应用的claspath上,都有可能在自动配置执行的过程中被用到,从而简化应用的配置工作。这个jar的内容大致是下面这个样子:

       

        箭头指向的基本在ReadingList应用中都有用到,这些配置类通过注解的方式使用,在运行期通过一系列的条件判断进行Bean的加载和配置。在这些配置完成后,一个可用的应用运行环境就准备好了。实现这些配置类的基础是Spring 4.0 提供的Condition 接口,通过实现Condition 接口的matches 方法来进行动态的判定。先来看看Condition 接口怎么用。

        1. Spring 4.0 开始提供的 Condition 接口。

        举个例子。需要在应用中建立一个操作数据库的DBService 类,这个类中要用到JdbcTemplate的实例。那么实例化JdbcTemplate前,首先要保证JdbcTemplate 在应用的classpath上,那怎么判断classpath上是不是有JdbcTemplate?用Condition 接口怎么实现这个判断呢?

    import org.springframework.context.annotation.Condition;
    import org.springframework.context.annotation.ConditionContext;
    import org.springframework.core.type.AnnotatedTypeMetadata;
    
    public class JdbcTemplateCondition implements Condition {
        @Override
        public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
            try {
                context.getClassLoader().loadClass("org.springframework.jdbc.core.JdbcTemplate");
                return true;
            } catch (Exception e) {
                return false;
            }
        }
    }

         这个判断实现完成,如何使用这个判断条件呢?

    @Conditional(JdbcTemplateCondition.class)
    public DBService dbService() {
        @AutoWire
        JdbcTemplate jdbcTemplate;
        
        // TODO 
    }

         DBService 在实例化以前首先要判断 JdbcTemplateCondition,返回true才会继续进行实例化,否则当前的类会被忽略,不进行实例化。

    2、Spring Boot 实现的Conditional** 形式的注解。

         Spring Boot 实现了一系列的Conditional Annotation。这些基本上是可以见名知意的。下面就是一部分常见的条件注解(Conditional Annotation)。

         没有不要去看所有的条件注解的具体实现,但是为了能够比较明晰的解释Auto-Configuration 的工作过程,将 DataSourceAutoConfiguration 的具体实现写一下,加深下自动配置的理解,也可以学习使用 @Conditional 注解和 接口Condition 的使用。

    @Configuration
    @ConditionalOnClass({DataSource.class, EmbeddedDatabaseType.class})
    @EnableConfigurationProperties({DataSourceProperties.class})
    @Import({Registrar.class, DataSourcePoolMetadataProvidersConfiguration.class})
    public class DataSourceAutoConfiguration {
       ... ... 
    }

        1、第一个注解 @Configuration 这个和xml 配置Bean 是同样的效果,这个就不详细解释了。

        2、第二个注解 @ConditionalOnClass 的意思:在classpath 在上有相应的类的话 返回True,否则返回false。

        3、第三个注解 @EnableConfigurationProperties({DataSourceProperties.class})  允许使用application.properties 文件配置 DataSource 的参数。

        4、第四个注解 @Import 将其参数中的类引入并初始化为一个Bean。

        真正要关注的是第二个注解 ConditionalOnClass,这个注解判断 DataSource 和 EmbededDataBaseType 两个类是否在classpath 上。如果此条件判定为真,开始后续的判定。继而判断当前是否有DataSource 实例,是否是嵌入式的数据,是否有嵌入式的Tomcat 等等。。一些列运行时判定最终决定是否生成配置一个可用的数据源。

    3、ReadingList 工程中 Auto-Configuration 工作的过程。

         (1)因为H2在classpath上,因此一个嵌入式的H2 数据库被实例化,这个Bean 是 javax.sql.DataSource 类型的,所以 一个JPA 的接口需要实例化。

         (2)因为 Hibernate Entity Manager 在classpath上,因此启用Hibernate的话,需要auto-configuration 需要实例化 LocalContainerManagerFactory Bean 和 JPAVendorAdapter。

         (3)因为 JPA 在 classpath 上,所以repository 的实例也会被自动创建。

         (4)因为Spring MVC 在classpath上, Spring 的DispatcherServlet 会被实例化。

         (5)因为是web 应用,因此一个资源的handler 会被注册,来处理 resource 目录下的静态资源。

         (6)因为Tomcat 在classpath 上,一个内置的Tomcat 容器会被启动承载和提供服务。

    4、其实不知道也不影响用Spring Boot 实现业务嘛。

         这一篇不写也罢。

         举个用Condition 的例子:

    import org.springframework.boot.context.properties.ConfigurationProperties;
    import org.springframework.context.annotation.Condition;
    import org.springframework.context.annotation.ConditionContext;
    import org.springframework.core.type.AnnotatedTypeMetadata;
    
    // 如果在applicaton.properties 文件中 见env.test=1 那么对应的类会被加载 @ConfigurationProperties("env.test") public class TestEnableCondition implements Condition { public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) { String test = conditionContext.getEnvironment().getProperty("env.test"); int isTest; try { isTest = Integer.valueOf(test); } catch (Exception e) { isTest = 0; } return isTest==1; } }
    @Conditional(TestEnableCondition.class)
    @Controller
    @RequestMapping(value = "/{param}")
    public class TestController {
       ... ... 
    }
  • 相关阅读:
    常用验证函数isset()/empty()/is_numeric()函数
    jquery select取option的value值发生变化事件
    (转)浅谈HTML5与css3画饼图!
    文本框输入值文字消失常用的两种方法
    简洁的滚动代码(上下滚动)
    (转)PHP的语言结构和函数的区别
    兼容ie7的导航下拉菜单
    jquery中each()函数
    tomcat源码导入eclipse
    weblogic linux环境下新建domain
  • 原文地址:https://www.cnblogs.com/tju-gsp/p/6275021.html
Copyright © 2011-2022 走看看