Springboot Starter介绍以及实现自定义Starter

1 SpringBoot Starter介绍

在使用SpringBoot开发项目时,会发现比使用Spring框架方便省事,因为其主要核心思想就是依赖大于配置,简化了其他框架整合Spring框架时的各种繁琐的配置。在此基础之上,SpringBoot推出了SpringBoot Starter,即将单独的功能模块抽离成了一个独立的的功能,如你想开发一个Web后台网站,仅仅只需要在pom文件中引入spring-boot-starter-web相关的依赖。
Starter组件的核心功能就是引入相关jar及一些初始化的配置信息

Spring官方提供的starter命名规范spring-boot-starter-xxx.jar,第三方提供的starter命名规范xxx-spring-boot-starter.jar),比如mybatis-spring-boot-starter

2 Starter的生效原理

2.1 起步依赖

将具备某种功能的坐标打包在一起,可以简化导入依赖的过程,例如,当导入spring-boot-starter-web这个Starter时,会将和Web开发的相关jar包一起导入到项目中
Springboot Starter介绍以及实现自定义Starter_第1张图片

2.2自动配置原理

提完在项目中导入starter所依赖的jar包后,不得不提及starter的第二个核心功能,导入一些初始化的配置类信息,这个功能的实现离不开Springboot的自动装配原理,无需手动配置xml文件,由Spring框架自动管理Bean的整个生命周期,大大简化了开发步骤, 自动配置设计了几个关键的步骤:

  1. 基于Java代码的Bean配置
  2. 自动配置条件依赖
  3. Bean参数获取
  4. Bean的发现
  5. Bean的装载

接下来,就mybatis-spring-boot-starter这个starter的引入,基于上面5个步骤来讲解Starter的自动配置原理

2.2.1 基于Java代码的Bean配置

pom文件中添加mybatis-spring-boot-starter的依赖坐标后,将会导入相关的jar包,其中一个重要的的jar包为mybatis.spring.boot.autoconfigure,根据命名可知,该jar包涉及了mybatis的自动装配信息,如下图所示:

<dependency>
     <groupId>org.mybatis.spring.bootgroupId>
     <artifactId>mybatis-spring-boot-starterartifactId>
      <version>2.1.2version>
dependency>

Springboot Starter介绍以及实现自定义Starter_第2张图片
在该jar中,有一个非常关键的类 MybatisAutoConfiguration
Springboot Starter介绍以及实现自定义Starter_第3张图片

关键代码如下:

@Configuration
@ConditionalOnClass({SqlSessionFactory.class, SqlSessionFactoryBean.class})
@ConditionalOnSingleCandidate(DataSource.class)  
@EnableConfigurationProperties({MybatisProperties.class})
@AutoConfigureAfter({DataSourceAutoConfiguration.class, MybatisLanguageDriverAutoConfiguration.class})
public class MybatisAutoConfiguration implements InitializingBean
{


    @Bean
    @ConditionalOnMissingBean
    public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception
    {
      //忽略业务代码
    }
    
    @Bean
    @ConditionalOnMissingBean
    public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory)
     {
      //忽略业务代码
     }
}

@Configuration 与 @Bean 注解的使用,可以创建一个基于java的配置类,相当于原生的xml配置文件。根据MybatisAutoConfiguration,自动创建了一个SqlSessionFactory session工厂和一个操作Sql的SqlSessionTemplate的template工具类,交给Spring容器自动管理

2.2.2 自动配置条件依赖

根据MybatisAutoConfiguration 上标注的其他注解可知,完成Mybatis配置类的装配是有多个依赖条件的
@ConditionalOnClass({SqlSessionFactory.class, SqlSessionFactoryBean.class})
@ConditionalOnSingleCandidate(DataSource.class)
依赖1,完成自动装配首先类路径上必须存在SqlSessionFactory和SqlSessionFactoryBean两个类,同时DataSource的单例Bean也必须先行加载到Spring容器中。
同时也可根据 生成SqlSessionFactory SqlSessionTemplate 的方法参数可知必须依赖SqlSessionFactory、DataSource
Springboot Starter介绍以及实现自定义Starter_第4张图片

2.2.3 Bean参数获取

要完成mybatis的自动配置,需要在配置文件中提供数据源相关的参数,例如数据库驱动URL,数据库用户名及密码等。根据@AutoConfigureAfter({DataSourceAutoConfiguration.class, MybatisLanguageDriverAutoConfiguration.class})可知,数据源信息是通过DataSourceAutoConfiguration配置类先行配置的,关键代码如下

package org.springframework.boot.autoconfigure.jdbc

@Configuration(
    proxyBeanMethods = false
)
@ConditionalOnClass({DataSource.class, EmbeddedDatabaseType.class})
@ConditionalOnMissingBean(
    type = {"io.r2dbc.spi.ConnectionFactory"}
)
@AutoConfigureBefore({SqlInitializationAutoConfiguration.class})
@EnableConfigurationProperties({DataSourceProperties.class})
@Import({DataSourcePoolMetadataProvidersConfiguration.class, InitializationSpecificCredentialsDataSourceInitializationConfiguration.class, SharedCredentialsDataSourceInitializationConfiguration.class})
public class DataSourceAutoConfiguration 

Bean参数的获取离不开@EnableConfigurationProperties({DataSourceProperties.class}) 注解的使用,意即引入数据源相关的配置属性,能将application.yml/application.properties配置文件中值加载到该属性配置类DataSourceProperties这个POJO对象上。【属性名和yml中配置的key保持一致】

//application.yml/application.properties 中配置数据源的前缀
@ConfigurationProperties(
    prefix = "spring.datasource"
)
public class DataSourceProperties implements BeanClassLoaderAware, InitializingBean {
    private ClassLoader classLoader;
    private boolean generateUniqueName = true;
    private String name;
    private Class<? extends DataSource> type;
    private String driverClassName;
    private String url;
    private String username;
    private String password;
    private String jndiName;
    //忽略get set方法
}
 ##数据源配置如下:
 spring:
   datasource:
     # 装载username 到DataSourceProperties 中的username 属性上
     username: XXX
     # 装载password到DataSourceProperties 中的password属性上
     password: XXX
     # 装载url到DataSourceProperties 中的url属性上
     url: xxxx

实现Bean参数获取的功能离不开两个重要的注解@ConfigurationProperties 能将application.yml/application.properties中配置的值封装映射到标注了该bean的相应属性上
@EnableConfigurationProperties 启用自动装配属性,使得@ConfigurationProperties注解生效,两者搭配使用,缺一不可

2.2.4 Bean的发现

SpringBoot默认扫描启动类所在包下的类以及子类的所有组件,但并没有包括依赖包中类,这里不得不思考下,依赖包中的bean是如何被发现和加载的,需要从SpringBoot项目的启动类上进行追踪,在启动类上我们会加上@SpringBootApplication注解
查看源码如下:

@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
    excludeFilters = {@Filter(
    type = FilterType.CUSTOM,
    classes = {TypeExcludeFilter.class}
), @Filter(
    type = FilterType.CUSTOM,
    classes = {AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication {
}

@EnableAutoConfiguration标识着开启了自动装配的功能

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration

@Import(AutoConfigurationImportSelector.class)引入自动加载选择器,其中有一个方法装载候选Bean

	protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
		List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
				getBeanClassLoader());
		Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you "
				+ "are using a custom packaging, make sure that file is correct.");
		return configurations;
	}

能將META-INF下的spring.factories文件配置的类通过类加载器装载到Spring 容器中。关于mybatis自动装配的类如下
Springboot Starter介绍以及实现自定义Starter_第5张图片
因此,Starter必不可少的一个文件就是spring.factories,它的存在将会帮助Spring框架发现需要配置的类

2.2.5 Bean的加载

在SpringBoot应用中,自动配置加载Bean是通过@Import注解这种方式,AutoConfigurationImportSelector类的selectinports方法返回一组从META-INF/spring.factories文件读取的全限定类名,通过反射并实例化这些Bean到Spring容器中

public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware,
		ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {

	private static final AutoConfigurationEntry EMPTY_ENTRY = new AutoConfigurationEntry();

	@Override
	public String[] selectImports(AnnotationMetadata annotationMetadata) {
		if (!isEnabled(annotationMetadata)) {
			return NO_IMPORTS;
		}
		AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);
		return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
	}

2.3 自动配置总结
  • 使用@Configuration和@Bean ,编写基于Java代码的配置类
  • @Conditional,设置自动配置条件依赖
  • @EnableConfigurationPropertie,@ConfigurationProperties:将yml/properties中的配置属性转成JavaBean
  • @EnableAutoConfiguration与@Import:实现Bean的发现与加载

3 自定义Starter

自定义hello-spring-boot-starter

3.1 pom文件导入相关依赖

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0modelVersion>
    <parent>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-parentartifactId>
        <version>2.6.8version>
        <relativePath/> 
    parent>
    <groupId>com.startergroupId>
    <artifactId>hello-spring-boot-starterartifactId>
    <version>0.0.1-SNAPSHOTversion>
    <name>hello-spring-boot-startername>
    <description>hello-starterdescription>
    <properties>
        <java.version>1.8java.version>
    properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starterartifactId>
        dependency>

        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-autoconfigureartifactId>
        dependency>
    dependencies>


project>
3.2定义HelloProperties
/**
 * @author starter
 * @projectName hello-spring-boot-starter
 * @date 2022/5/25 下午 02:26
 * @description 配置属性类,将配置文件中属性与该JavaBean的属性一一对应
 */
@ConfigurationProperties(prefix ="hello")
public class HelloProperties {

    private String name;
    private String school;
    private int age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSchool() {
        return school;
    }

    public void setSchool(String school) {
        this.school = school;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}
3.3定义需要自动管理的Bean
public class HelloService {


    private String name;
    private String school;
    private int age;

    public HelloService(String name, String school, int age) {
        this.name = name;
        this.school = school;
        this.age = age;
    }


    public void sayHello(){
        System.out.println("Hi i am "+name+",I study in "+school+" and i am "+age);
    }
}

3.4 编写自动配置类
@EnableConfigurationProperties(HelloProperties.class)
@Configuration
public class HelloServiceAutoConfiguration {

    private HelloProperties helloProperties;

    public HelloServiceAutoConfiguration(HelloProperties helloProperties){
        this.helloProperties=helloProperties;
    }

    /**
     * 当容器中没有HelloService的bean时,将会被扫描加载
     * @return
     */
    @Bean
    @ConditionalOnMissingBean
    public HelloService helloService(){
        return new HelloService(helloProperties.getName(),helloProperties.getSchool(),helloProperties.getAge());
    }
}

3.5 创建spring.factories文件

在resource下新建META-INF/spring.factories

org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.starter.config.HelloServiceAutoConfiguration

org.springframework.boot.autoconfigure.EnableAutoConfigurationkey一定,value根据类所在类全路径来确定
项目结构如下图所示:
Springboot Starter介绍以及实现自定义Starter_第6张图片

3.6 maven -install

将自定义的starter install到本地maven仓库
Springboot Starter介绍以及实现自定义Starter_第7张图片

4 测试

新建项目,pom文件中引入自定义starter的坐标


        <dependency>
            <groupId>com.starter</groupId>
            <artifactId>hello-spring-boot-starter</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>

application.properties中配置HelloProperties

hello.name=lyf
hello.school=XXXXSchool
hello.age=18

单元测试结果
Springboot Starter介绍以及实现自定义Starter_第8张图片

你可能感兴趣的:(java学习笔记,springboot,spring,boot,java,spring)