当前位置:首页 > 经验 >

springboot的starter原理(springboot starter核心组件)

来源:原点资讯(www.yd166.com)时间:2022-10-29 11:58:07作者:YD166手机阅读>>

来自灵魂的一问:这两个文件有什么区别?

答:如果pom.xml中引入了spring-boot-configuration-processor包,则会自动生成spring-configuration-metadata.json。

如果需要手动修改里面的元数据,则可以在additional-spring-configuration-metadata.json中编辑,最终两个文件中的元数据会合并到一起。

MybatisProperties类是属性实体类:

@ConfigurationProperties(prefix = MybatisProperties.MYBATIS_PREFIX) public class MybatisProperties { public static final String MYBATIS_PREFIX = "mybatis"; private String configLocation; private String[] mapperLocations; private String typeAliasesPackage; private String typeHandlersPackage; private boolean checkConfigLocation = false; private ExecutorType executorType; private Properties configurationProperties; @NestedConfigurationProperty private Configuration configuration; public String getConfigLocation() { return this.configLocation; } public void setConfigLocation(String configLocation) { this.configLocation = configLocation; } @Deprecated public String getConfig() { return this.configLocation; } @Deprecated public void setConfig(String config) { this.configLocation = config; } public String[] getMapperLocations() { return this.mapperLocations; } public void setMapperLocations(String[] mapperLocations) { this.mapperLocations = mapperLocations; } public String getTypeHandlersPackage() { return this.typeHandlersPackage; } public void setTypeHandlersPackage(String typeHandlersPackage) { this.typeHandlersPackage = typeHandlersPackage; } public String getTypeAliasesPackage() { return this.typeAliasesPackage; } public void setTypeAliasesPackage(String typeAliasesPackage) { this.typeAliasesPackage = typeAliasesPackage; } public boolean isCheckConfigLocation() { return this.checkConfigLocation; } public void setCheckConfigLocation(boolean checkConfigLocation) { this.checkConfigLocation = checkConfigLocation; } public ExecutorType getExecutorType() { return this.executorType; } public void setExecutorType(ExecutorType executorType) { this.executorType = executorType; } public Properties getConfigurationProperties() { return configurationProperties; } public void setConfigurationProperties(Properties configurationProperties) { this.configurationProperties = configurationProperties; } public Configuration getConfiguration() { return configuration; } public void setConfiguration(Configuration configuration) { this.configuration = configuration; } public Resource[] resolveMapperLocations() { ResourcePatternResolver resourceResolver = new PathMatchingResourcePatternResolver(); List<Resource> resources = new ArrayList<Resource>(); if (this.mapperLocations != null) { for (String mapperLocation : this.mapperLocations) { try { Resource[] mappers = resourceResolver.getResources(mapperLocation); resources.addAll(Arrays.asList(mappers)); } catch (IOException e) { // ignore } } } return resources.toArray(new Resource[resources.size()]); } }

可以看到Mybatis初始化所需要的很多属性都在这里,相当于一个JavaBean。

下面重点看一下MybatisAutoConfiguration的代码:

@org.springframework.context.annotation.Configuration @ConditionalOnClass({ SqlSessionFactory.class, SqlSessionFactoryBean.class }) @ConditionalOnBean(DataSource.class) @EnableConfigurationProperties(MybatisProperties.class) @AutoConfigureAfter(DataSourceAutoConfiguration.class) public class MybatisAutoConfiguration { private static final Logger logger = LoggerFactory.getLogger(MybatisAutoConfiguration.class); private final MybatisProperties properties; private final Interceptor[] interceptors; private final ResourceLoader resourceLoader; private final DatabaseIdProvider databaseIdProvider; private final List<ConfigurationCustomizer> configurationCustomizers; public MybatisAutoConfiguration(MybatisProperties properties, ObjectProvider<Interceptor[]> interceptorsProvider, ResourceLoader resourceLoader, ObjectProvider<DatabaseIdProvider> databaseIdProvider, ObjectProvider<List<ConfigurationCustomizer>> configurationCustomizersProvider) { this.properties = properties; this.interceptors = interceptorsProvider.getIfAvailable(); this.resourceLoader = resourceLoader; this.databaseIdProvider = databaseIdProvider.getIfAvailable(); this.configurationCustomizers = configurationCustomizersProvider.getIfAvailable(); } @PostConstruct public void checkConfigFileexists() { if (this.properties.isCheckConfigLocation() && StringUtils.hasText(this.properties.getConfigLocation())) { Resource resource = this.resourceLoader.getResource(this.properties.getConfigLocation()); Assert.state(resource.exists(), "Cannot find config location: " resource " (please add config file or check your Mybatis configuration)"); } } @Bean @ConditionalOnMissingBean public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception { SqlSessionFactoryBean factory = new SqlSessionFactoryBean(); factory.setDataSource(dataSource); factory.setVfs(SpringBootVFS.class); if (StringUtils.hasText(this.properties.getConfigLocation())) { factory.setConfigLocation(this.resourceLoader.getResource(this.properties.getConfigLocation())); } Configuration configuration = this.properties.getConfiguration(); if (configuration == null && !StringUtils.hasText(this.properties.getConfigLocation())) { configuration = new Configuration(); } if (configuration != null && !CollectionUtils.isEmpty(this.configurationCustomizers)) { for (ConfigurationCustomizer customizer : this.configurationCustomizers) { customizer.customize(configuration); } } factory.setConfiguration(configuration); if (this.properties.getConfigurationProperties() != null) { factory.setConfigurationProperties(this.properties.getConfigurationProperties()); } if (!ObjectUtils.isEmpty(this.interceptors)) { factory.setPlugins(this.interceptors); } if (this.databaseIdProvider != null) { factory.setDatabaseIdProvider(this.databaseIdProvider); } if (StringUtils.hasLength(this.properties.getTypeAliasesPackage())) { factory.setTypeAliasesPackage(this.properties.getTypeAliasesPackage()); } if (StringUtils.hasLength(this.properties.getTypeHandlersPackage())) { factory.setTypeHandlersPackage(this.properties.getTypeHandlersPackage()); } if (!ObjectUtils.isEmpty(this.properties.resolveMapperLocations())) { factory.setMapperLocations(this.properties.resolveMapperLocations()); } return factory.getObject(); } @Bean @ConditionalOnMissingBean public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) { ExecutorType executorType = this.properties.getExecutorType(); if (executorType != null) { return new SqlSessionTemplate(sqlSessionFactory, executorType); } else { return new SqlSessionTemplate(sqlSessionFactory); } } public static class AutoConfiguredMapperScannerRegistrar implements BeanFactoryAware, ImportBeanDefinitionRegistrar, ResourceLoaderAware { private BeanFactory beanFactory; private ResourceLoader resourceLoader; @Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry); try { if (this.resourceLoader != null) { scanner.setResourceLoader(this.resourceLoader); } List<String> packages = AutoConfigurationPackages.get(this.beanFactory); if (logger.isDebugEnabled()) { for (String pkg : packages) { logger.debug("Using auto-configuration base package '{}'", pkg); } } scanner.setAnnotationClass(Mapper.class); scanner.registerFilters(); scanner.doScan(StringUtils.toStringArray(packages)); } catch (IllegalStateException ex) { logger.debug("Could not determine auto-configuration package, automatic mapper scanning disabled.", ex); } } @Override public void setBeanFactory(BeanFactory beanFactory) throws BeansException { this.beanFactory = beanFactory; } @Override public void setResourceLoader(ResourceLoader resourceLoader) { this.resourceLoader = resourceLoader; } } @org.springframework.context.annotation.Configuration @Import({ AutoConfiguredMapperScannerRegistrar.class }) @ConditionalOnMissingBean(MapperFactoryBean.class) public static class MapperScannerRegistrarNotFoundConfiguration { @PostConstruct public void afterPropertiesSet() { logger.debug("No {} found.", MapperFactoryBean.class.getName()); } } }

这个类就是一个Configuration(配置类),它里面定义很多bean,其中最重要的就是SqlSessionFactory的bean实例,该实例是Mybatis的核心功能,用它创建SqlSession,对数据库进行CRUD操作。

除此之外,MybatisAutoConfiguration类还包含了:

  • @ConditionalOnClass 配置了只有包含SqlSessionFactory.class和SqlSessionFactoryBean.class,该配置类才生效。
  • @ConditionalOnBean 配置了只有包含dataSource实例时,该配置类才生效。
  • @EnableConfigurationProperties 该注解会自动填充MybatisProperties实例中的属性。
  • AutoConfigureAfter 配置了该配置类在DataSourceAutoConfiguration类之后自动配置。

这些注解都是一些辅助功能,决定Configuration是否生效,当然这些注解不是必须的。

接下来,重点看看spring.factories文件有啥内容:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration

里面只有一行配置,即key为EnableAutoConfiguration,value为MybatisAutoConfiguration。

好了,介绍了这么多东西,现在我们来总结一下,

starter几个要素如下图所示:

springboot的starter原理,springboot starter核心组件(5)

那么,编写starter需要哪些步骤?

  • 1.需要定义一个名称为xxx-spring-boot-starter的空项目,里面不包含任何代码,可以有pom.xml和pom.properties文件。
  • 2.pom.xml文件中包含了名称为xxx-spring-boot-autoconfigure的项目。
  • 3.xxx-spring-boot-autoconfigure项目中包含了名称为xxxAutoConfiguration的类,该类可以定义一些bean实例。当然,Configuration类上可以打一些如:ConditionalOnClass、ConditionalOnBean、EnableConfigurationProperties等注解。
  • 4.需要在spring.factories文件中增加key为EnableAutoConfiguration,value为xxxAutoConfiguration。

我们试着按照这四步,自己编写一个starter看看能否成功,验证一下总结的内容是否正确。

3 如何定义自己的starter?3.1 先创建一个空项目

该项目名称为id-generate-starter,注意为了方便我把项目重命名了,原本应该是叫id-generate-spring-boot-starter的,如下图所示:

springboot的starter原理,springboot starter核心组件(6)

pom.xml文件定义如下:

<?xml version="1.0" encoding="UTF-8"?> <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 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <version>1.3.1</version> <groupId>com.sue</groupId> <artifactId>id-generate-spring-boot-starter</artifactId> <name>id-generate-spring-boot-starter</name> <dependencies> <dependency> <groupId>com.sue</groupId> <artifactId>id-generate-spring-boot-autoconfigure</artifactId> <version>1.3.1</version> </dependency> </dependencies> </project>

我们看到,它只引入了id-generate-spring-boot-autoconfigure。当然如果有需要这里还可以引入多个autoconfigure或者多个其他jar包或者。

3.2 创建id-generate-autoconfigure

同样为了方便我把项目重命名了,原本是叫id-generate-spring-boot-autoconfigure,如下图所示:

springboot的starter原理,springboot starter核心组件(7)

该项目当中包含:pom.xml、spring.factories、IdGenerateAutoConfiguration、IdGenerateService 和 IdProperties 这5个关键文件,下面我们逐一看看。

先从pom.xml

<?xml version="1.0" encoding="UTF-8"?> <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 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.4.RELEASE</version> </parent> <modelVersion>4.0.0</modelVersion> <version>1.3.1</version> <groupId>com.sue</groupId> <artifactId>id-generate-spring-boot-autoconfigure</artifactId> <name>id-generate-spring-boot-autoconfigure</name> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-autoconfigure</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> <optional>true</optional> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin> </plugins> </build> </project>

我们可以看到,这个文件比较简单就引入了:

  • spring-boot-starter:springboot的相关jar包。
  • spring-boot-autoconfigure:springboot自动配置相关jar包。
  • spring-boot-configuration-processor:springboot生成IDE提示功能相关jar包。

重点看看spring.factories文件:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.sue.IdGenerateAutoConfiguration

它里面只包含一行配置,其中key是EnableAutoConfiguration,value是IdGenerateAutoConfiguration。

再重点看一下IdGenerateAutoConfiguration

@ConditionalOnClass(IdProperties.class) @EnableConfigurationProperties(IdProperties.class) @Configuration public class IdGenerateAutoConfiguration { @Autowired private IdProperties properties; @Bean public IdGenerateService idGenerateService() { return new IdGenerateService(properties.getWorkId()); } }

该类是一个使用了@Configuration注解标记为了配置类,生效的条件是@ConditionalOnClass注解中检测到包含IdProperties.class。并且使用@EnableConfigurationProperties注解会自动注入IdProperties的实例。

此外,最关键的点是该类里面创建了idGenerateService的bean实例,这是自动配置的精髓。

再看看IdGenerateService

public class IdGenerateService { private Long workId; public IdGenerateService(Long workId) { this.workId = workId; } public Long generate() { return new Random().nextInt(100) this.workId; } }

我们可以看到它是一个普通的类,甚至都没有使用@Service注解,里面有个generate方法,根据workId的值和随机数动态生成id。

最后看看IdProperties

@ConfigurationProperties(prefix = IdProperties.PREFIX) public class IdProperties { public static final String PREFIX = "sue"; private Long workId; public Long getWorkId() { return workId; } public void setWorkId(Long workId) { this.workId = workId; } }

它是一个配置实体类,里面包含了相关的配置文件。使用@ConfigurationProperties注解,会自动把application.properties文件中以sue开通的,参数名称跟IdProperties中一样的参数值,自动注入到IdProperties对象中。

3.3 创建id-generate-test

这个项目主要用于测试。

springboot的starter原理,springboot starter核心组件(8)

栏目热文

mybatis作用及特点(mybatis优点有哪些)

mybatis作用及特点(mybatis优点有哪些)

a、MyBatis 把 sql 语句从 Java 源程序中独立出来,放在单独的 XML 文件中编写,给程序的维护带来了很...

2022-10-29 11:45:02查看全文 >>

mybatis工作原理分析(mybatis工作原理及项目操作配置)

mybatis工作原理分析(mybatis工作原理及项目操作配置)

前言:mybatis是最近几年比较流行的操作数据库框架了,平时都只知道怎么去配置,怎么去用它,那你们知道它是如何实现的吗...

2022-10-29 12:11:32查看全文 >>

mybatis简介(mybatis的详细讲解)

mybatis简介(mybatis的详细讲解)

一. mybatisMyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache so...

2022-10-29 11:28:39查看全文 >>

mybatis面试题(java面试必背八股文)

mybatis面试题(java面试必背八股文)

点击上方"java全栈技术"关注,每天学习一个java知识点1. #{}和${}的区别是什么?#{}是预编译处理,${}...

2022-10-29 11:56:17查看全文 >>

mybatis详细讲解(mybatis操作步骤)

mybatis详细讲解(mybatis操作步骤)

废话不多说,直接进入文章。我们在使用Mybatis的时候,会在xml中编写SQL语句。如图:那么,MyBatis底层是如...

2022-10-29 11:57:34查看全文 >>

mybatisplus 代码生成器(mybatisplus代码生成器模板)

mybatisplus 代码生成器(mybatisplus代码生成器模板)

简介: 代码生成器,也叫逆向工程,是根据数据库里的表结构,自动生成对应的实体类、映射文件和接口。代码生成器,也叫逆向工程...

2022-10-29 12:13:45查看全文 >>

springboot菜鸟教程(菜鸟教程spring boot)

springboot菜鸟教程(菜鸟教程spring boot)

- 一、SpringBoot的starter简介 -1.1 什么是starter(场景启动器)在SpringBoot出现...

2022-10-29 12:02:31查看全文 >>

mybatis详解(mybatis简单示例)

mybatis详解(mybatis简单示例)

MyBatis缓存框架与事务详解一、缓存的概念1.1什么是缓存 存在内存中的临时数据。 将用户经常查询的数据放在缓存(内...

2022-10-29 11:50:24查看全文 >>

简单的灯笼怎么叠(叠小灯笼方法)

简单的灯笼怎么叠(叠小灯笼方法)

过年啦,家家户户挂灯笼,今天教大家折一款樱花灯笼,颜值非常高,中间是一个樱花球,主要是做法超级简单。先剪一张圆形的纸,直...

2022-10-29 11:35:53查看全文 >>

一张纸叠灯笼(一张纸折灯笼大全)

一张纸叠灯笼(一张纸折灯笼大全)

树姐姐昨天发布的3款简单的灯笼很受到大家的欢迎,我好开心哦。离中秋越来越近了,今天树姐姐再给大家分享一款组合型的中式手提...

2022-10-29 12:02:02查看全文 >>

文档排行