spring boot学习笔记(二):自动配置原理

代码示例:https://git.oschina.net/null_584_3382/spring-boot-introduction

一、与mybatis集成

在介绍spring boot 自动配置原理之前,先看一个例子,spring boot集成mybatis,

测试用的数据库为mysql,所以引入mysql-connector-java依赖

引入myatis提供的mybatis-spring-boot-starter

最后引入druid连接池依赖

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
    </dependency>

    <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
        <version>1.1.1</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/com.alibaba/druid -->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid</artifactId>
        <version>RELEASE</version>
    </dependency>
</dependencies>

按照mvc逻辑,首先是controller,很普通的代码

@RestController
public class Controller {

    @Autowired
    DemoMapper demoMapper;

    @RequestMapping("/fetchByName")
    public Object fetchByName(@RequestParam("name") String name){
        return demoMapper.fetchByName(name);
    }
}

因为只是一个例子,所以省略server层,直接使用dao层

@Mapper
public interface DemoMapper {
    @Select("select * from userinfo where name=#{name}")
     UserInfo fetchByName(String name);
}

嗯,代码都是很普通的,但是datasource是在哪里配置的呢?

关键就在配置文件

spring:
  datasource:
    url: jdbc:mysql://${url}:3306/bootintro
    username: root
    password: ${password}
    driver-class-name: com.mysql.jdbc.Driver
    type: com.alibaba.druid.pool.DruidDataSource

好了,所有关键代码都在这里了(哦,还有Application类和domain类,省略了),运行一下(当然,你还要配置自己的数据库)

二、怎么做到的

没错,前面说过,spring boot为我们提供了自动配置,那自动配置的怎么做到的。

***AutoConfiguration类

spring boot中有很多类的名字为***AutoConfiguration,这些类都是一些spring的配置类(头上有@Configuration),就是这些类提供了一些默认配置,如果你使用spring基于java的配置,其实也是做了同样的事情,只不过springboot帮我们做!!

@EnableAutoConfiguration

恩,你肯定会接着问,那么spring boot怎么知道有哪些类是所谓的"***AutoConfiguration"。@EnableAutoConfiguration,就是这个注解开启了自动配置,这个注解包括:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(EnableAutoConfigurationImportSelector.class)

其中主要的是EnableAutoConfigurationImportSelector这个类,就是用来选择哪些是需要自动配置的。这个类的核心代码:

@Override
public String[] selectImports(AnnotationMetadata metadata) {
   if (!isEnabled(metadata)) {
      return NO_IMPORTS;
   }
   try {
      AnnotationAttributes attributes = getAttributes(metadata);
      List<String> configurations = getCandidateConfigurations(metadata,
            attributes);
      configurations = removeDuplicates(configurations);
      Set<String> exclusions = getExclusions(metadata, attributes);
      configurations.removeAll(exclusions);
      configurations = sort(configurations);
      recordWithConditionEvaluationReport(configurations, exclusions);
      return configurations.toArray(new String[configurations.size()]);
   }
   catch (IOException ex) {
      throw new IllegalStateException(ex);
   }
}

其中的最关键的是getCandidateConfigurations()这个方法中的:

List<String> configurations = SpringFactoriesLoader.loadFactoryNames(
      getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());

追踪进去看就可以发现,这类就是在所有的classpath下查找META-INF/spring.factories这个文件,从这个文件中提出key为org.springframework.boot.autoconfigure.EnableAutoConfiguration的值,而这些值就是一些自动配置类

例如,mybatis提供的META-INF/spring.factories内容:

# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration

多说2句:

  1. 基本所有的@EnableXXX 都有一个对应的类来控制自动配置加载
  2. 只有当你希望@EnableAutoConfiguration自动帮你加载的时候才使用配置META-INF/spring.factories这个文件来自动配置,因此其他的Enable大多要自己去实现ImportSelect,例如开启事务的注解@EnableTransactionManagement的加载自动配置类就比较直接。
    @Override
    protected String[] selectImports(AdviceMode adviceMode) {
       switch (adviceMode) {
          case PROXY:
             return new String[] {AutoProxyRegistrar.class.getName(), ProxyTransactionManagementConfiguration.class.getName()};
          case ASPECTJ:
             return new String[] {TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME};
          default:
             return null;
       }
    }

全部都加载吗

非也,仔细看某个***AutoConfig,举个例子,例如自动配置http编码的CharacterEncodingFilter的自动配置类HttpEncodingAutoConfiguration:

@Configuration
@EnableConfigurationProperties(HttpEncodingProperties.class)
@ConditionalOnWebApplication
@ConditionalOnClass(CharacterEncodingFilter.class)
@ConditionalOnProperty(prefix = "spring.http.encoding", value = "enabled", matchIfMissing = true)
public class HttpEncodingAutoConfiguration {

   private final HttpEncodingProperties properties;

   public HttpEncodingAutoConfiguration(HttpEncodingProperties properties) {
      this.properties = properties;
   }

   @Bean
   @ConditionalOnMissingBean(CharacterEncodingFilter.class)
   public CharacterEncodingFilter characterEncodingFilter() {
      CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
      filter.setEncoding(this.properties.getCharset().name());
      filter.setForceRequestEncoding(this.properties.shouldForce(Type.REQUEST));
      filter.setForceResponseEncoding(this.properties.shouldForce(Type.RESPONSE));
      return filter;
   }
    ...
    ...
}

其中,注解中包括许多@Confitionalxxx的,就是这些注解来控制该自动配置是否生效,根据这些注解名字大概都能知道是什么意思,例如@ConditionalOnWebApplication,这个肯定就是只有在web工程中才满足,@ConditionalOnClass只有存在CharacterEncodingFilter.class这个类的时候才有效。

怎么通过配置修改的

spring boot中的大多数自定义配置都可以通过修改配置来完成,例如,还是上面的那个例子,其中有个注解@EnableConfigurationProperties(HttpEncodingProperties.class),而HttpEncodingProperties类就是读取配置文件信息,因此,通过修改配置信息,自动配置类生效的时候就会按照配置信息来自动配置。例如,DataSourceAutoConfiguration,加载配置文件的类为

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

    ...

   /**
    * Fully qualified name of the JDBC driver. Auto-detected based on the URL by default.
    */
   private String driverClassName;

   /**
    * JDBC url of the database.
    */
   private String url;

   /**
    * Login user of the database.
    */
   private String username;

   /**
    * Login password of the database.
    */
   private String password;

   ...
}

可以知道,在spring boot的配置文件中查找配置属性,根据配置属性来填充该类的属性值

多说2句

  1. @ConfigurationProperties(prefix = "spring.datasource") 的意思就是会在配置文件中查找spring.datasource为前缀的,然后把对应属性自动注入该类中,例如 配置文件中的spring.datasource.name 的值就会注入到该类的name属性中,其他同理
  2. spring boot默认会加载application.yml(或者application.properties),并且会从4个位置去搜索该类
  • A /config subdirectory of the current directory.
  • The current directory
  • A classpath /config package
  • The classpath root

代码示例:https://git.oschina.net/null_584_3382/spring-boot-introduction

转载于:https://my.oschina.net/u/3039671/blog/787195

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值