Spring Boot:自定义starter

在学习Spring Boot的过程中,接触最多的就是starter。可以认为starter是一种服务——使得使用某个功能的开发者不需要关注各种依赖库的处理,不需要具体的配置信息,由Spring Boot自动通过classpath路径下的类发现需要的Bean,并织入bean。举个例子,spring-boot-starter-jdbc这个starter的存在,使得我们只需要在BookPubApplication下用 @Autowired引入DataSource的bean就可以,Spring Boot会自动创建DataSource的实例。
这里我们会用一个不太规范的starter展示Spring Boot的自动配置的运行原理。Spring Boot的自动配置、Command-line Runner一文中曾利用StartupRunner类在程序运行启动后首先查询数据库中书的数目,现在换个需求:在系统启动后打印各个实体的数量

How Do

  • 新建一个模块db-count-starter,然后修改db-count-starter模块下的pom文件,增加对应的库。
  1. <dependencies>

  2.    
    <dependency>

  3.        
    <groupId>
    org.springframework.boot
    </groupId>

  4.        
    <artifactId>
    spring-boot
    </artifactId>

  5.        
    <!-- version继承父模块的-->

  6.    
    </dependency>

  7.    
    <dependency>

  8.        
    <groupId>
    org.springframework.data
    </groupId>

  9.        
    <artifactId>
    spring-data-commons
    </artifactId>

  10.        
    <version>
    1.9.3.RELEASE
    </version>

  11.    
    </dependency>

  12. </dependencies>

  • 新建包结构com/test/bookpubstarter/dbcount,然后新建DbCountRunner类,实现CommandLineRunner接口,在run方法中输出每个实体的数量。
  1. package
    com.test.bookpubstarter.dbcount;

  2. import
    org.slf4j.
    Logger
    ;

  3. import
    org.slf4j.
    LoggerFactory
    ;

  4. import
    org.springframework.boot.
    CommandLineRunner
    ;

  5. import
    org.springframework.data.repository.
    CrudRepository
    ;

  6. import
    java.util.
    Collection
    ;

  7. public
    class
    DbCountRunner
    implements
    CommandLineRunner
    {

  8.    
    protected
    final
    Logger
    logger =
    LoggerFactory
    .getLogger(
    DbCountRunner
    .
    class
    );

  9.    
    private
    Collection
    <
    CrudRepository
    > repositories;

  10.    
    public
    DbCountRunner
    (
    Collection
    <
    CrudRepository
    > repositories) {

  11.        
    this
    .repositories = repositories;

  12.    }

  13.    
    @Override

  14.    
    public
    void
    run(
    String
    ... strings)
    throws
    Exception
    {

  15.        repositories.forEach(crudRepository -> {

  16.            logger.info(
    String
    .format(
    "%s has %s entries"
    ,

  17.                    getRepositoryName(crudRepository.getClass()),

  18.                    crudRepository.count()));

  19.        });

  20.    }

  21.    
    private
    static
    String
    getRepositoryName(
    Class
    crudRepositoryClass) {

  22.        
    for
    (
    Class
    repositoryInterface : crudRepositoryClass.getInterfaces()) {

  23.            
    if
    (repositoryInterface.getName().startsWith(
    "com.test.bookpub.repository"
    )) {

  24.                
    return
    repositoryInterface.getSimpleName();

  25.            }

  26.        }

  27.        
    return
    "UnknownRepository"
    ;

  28.    }

  29. }

  • 增加自动配置文件DbCountAutoConfiguration
  1. package
    com.test.bookpubstarter.dbcount;

  2. import
    org.springframework.context.annotation.
    Bean
    ;

  3. import
    org.springframework.context.annotation.
    Configuration
    ;

  4. import
    org.springframework.data.repository.
    CrudRepository
    ;

  5. import
    java.util.
    Collection
    ;

  6. @Configuration

  7. public
    class
    DbCountAutoConfiguration
    {

  8.    
    @Bean

  9.    
    public
    DbCountRunner
    dbCountRunner(
    Collection
    <
    CrudRepository
    > repositories) {

  10.        
    return
    new
    DbCountRunner
    (repositories);

  11.    }

  12. }

  • 在src/main/resources目录下新建META-INF文件夹,然后新建spring.factories文件,这个文件用于告诉Spring Boot去找指定的自动配置文件,因此它的内容是
  1. org.springframework.boot.autoconfigure.
    EnableAutoConfiguration
    =

  2. com.test.bookpubstarter.dbcount.
    DbCountAutoConfiguration

  • 在之前的程序基础上,在顶层pom文件中增加starter的依赖
  1. <dependency>

  2.  
    <groupId>
    com.test
    </groupId>

  3.  
    <artifactId>
    db-count-starter
    </artifactId>

  4.  
    <version>
    0.0.1-SNAPSHOT
    </version>

  5. </dependency>

  • 把StartupRunner相关的注释掉,然后在main函数上右键Run BookPubApplication.main(…),可以看出我们编写的starter被主程序使用了。
Spring Boot:自定义starter

分析

正规的starter是一个独立的工程,然后在maven中新仓库注册发布,其他开发人员就可以使用你的starter了。
常见的starter会包括下面几个方面的内容:
  1. 自动配置文件,根据classpath是否存在指定的类来决定是否要执行该功能的自动配置。
  2. spring.factories,非常重要,指导Spring Boot找到指定的自动配置文件。
  3. endpoint:可以理解为一个admin,包含对服务的描述、界面、交互(业务信息的查询)
  4. health indicator:该starter提供的服务的健康指标
在应用程序启动过程中,Spring Boot使用SpringFactoriesLoader类加载器查找org.springframework.boot.autoconfigure.EnableAutoConfiguration关键字对应的Java配置文件。Spring Boot会遍历在各个jar包种META-INF目录下的spring.factories文件,构建成一个配置文件链表。除了EnableAutoConfiguration关键字对应的配置文件,还有其他类型的配置文件:
  • org.springframework.context.ApplicationContextInitializer
  • org.springframework.context.ApplicationListener
  • org.springframework.boot.SpringApplicationRunListener
  • org.springframework.boot.env.PropertySourceLoader
  • org.springframework.boot.autoconfigure.template.TemplateAvailabilityProvider
  • org.springframework.test.contex.TestExecutionListener
Spring Boot的starter在编译时不需要依赖Spring Boot的库。这个例子中依赖spring boot并不是因为自动配置要用spring boot,而仅仅是因为需要实现CommandLineRunner接口。

两个需要注意的点

  1. @ConditionalOnMissingBean的作用是:只有对应的ban在系统中都没有被创建,它修饰的初始化代码块才会执行,用户自己手动创建的bean优先
  2. Spring Boot starter如何找到自动配置文件(xxxxAutoConfiguration之类的文件)?
  • spring.factories:由Spring Boot触发探测classpath目录下的类,进行自动配置;
  • @Enable:有时需要由starter的用户触发*查找自动配置文件的过程。

本站所有文章均来自互联网,如有侵权,请联系站长删除。极客文库 » Spring Boot:自定义starter
分享到:
赞(0)

评论抢沙发

评论前必须登录!