您的位置 首页 > 德语词汇

starter是什麼意思,手把手带你开发starter,点对点带你讲解原理

大家好,今天来为大家解答starter是什麼意思这个问题的一些问题点,包括手把手带你开发starter,点对点带你讲解原理也一样很多人还不知道,因此呢,今天就来为大家分析分析,现在让我们一起来看看吧!如果解决了您的问题,还望您关注下本站哦,谢谢~

starter是什麼意思,手把手带你开发starter,点对点带你讲解原理

___________\n/____|(_)|_\\||\n|(________________||_)|______||_\n\\___\\|'_\\|'__||'_\\/_`|_</_\\/_\\|__|\n____)||_)|||||||(_|||_)|(_)|(_)||_\n|_____/|.__/|_||_|_||_|\\__,|____/\\___/\\___/\\__|\n||__/|\n|_||___/为什么要用Starter?现在我们就来回忆一下,在还没有Spring-boot框架的时候,我们使用Spring开发项目,如果需要某一个框架,例如mybatis,我们的步骤一般都是:到maven仓库去找需要引入的mybatisjar包,选取合适的版本(易发生冲突)到maven仓库去找mybatis-spring整合的jar包,选取合适的版本(易发生冲突)在spring的applicationContext.xml文件中配置dataSource和mybatis相关信息假如所有工作都到位,一般可以一气呵成;但很多时候都会花一堆时间解决jar冲突,配置项缺失,导致怎么都启动不起来等等,各种问题。

所以在2012年10月,一个叫MikeYoungstrom的人在SpringJira中创建了一个功能请求,要求在SpringFramework中支持无容器Web应用程序体系结构,提出了在主容器引导Spring容器内配置Web容器服务;这件事情对SpringBoot的诞生应该说是起到了一定的推动作用。

所以SpringBoot设计的目标就是简化繁琐配置,快速建立Spring应用。

在使用spring-boot-starter,会发现,有的项目名称是XX-spring-boot-starter,有的是spring-boot-starter-XX,这个项目的名称有什么讲究呢?从springboot官方文档摘录:

这段话的大概意思就是,麻烦大家遵守这个命名规范:

Srping官方命名格式为:spring-boot-starter-{name}

非Spring官方建议命名格式:{name}-spring-boot-starter

下面我就以记录日志的一个组件为示例来讲述开发一个starter的过程。

首先新建一个maven工程,名称定义为jd-log-spring-boot-starter

<?xmlversion="1.0"encoding="UTF-8"?>\n<projectxmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"\nxsi:schemaLocation="http://maven.apache.org/POM/4.0.0http://maven.apache.org/xsd/maven-4.0.0.xsd">\n<modelVersion>4.0.0</modelVersion>\n<parent>\n<groupId>org.springframework.boot</groupId>\n<artifactId>spring-boot-starter-parent</artifactId>\n<version>2.5.13</version>\n<relativePath/><!--lookupparentfromrepository-->\n</parent>\n<groupId>com.jd</groupId>\n<artifactId>jd-log-spring-boot-starter</artifactId>\n<version>1.0-SNAPSHOT</version>\n<name>jd-log-spring-boot-starter</name>\n<url>http://www.example.com</url>\n<properties>\n<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n<maven.compiler.source>1.8</maven.compiler.source>\n<maven.compiler.target>1.8</maven.compiler.target>\n</properties>\n\n\n<dependencies>\n<!--提供了自动装配功能-->\n<dependency>\n<groupId>org.springframework.boot</groupId>\n<artifactId>spring-boot-autoconfigure</artifactId>\n</dependency>\n<!--在编译时会自动收集配置类的条件,写到一个META-INF/spring-autoconfigure-metadata.json中-->\n<dependency>\n<groupId>org.springframework.boot</groupId>\n<artifactId>spring-boot-configuration-processor</artifactId>\n</dependency>\n<!--记录日志会用到切面,所以需要引入-->\n<dependency>\n<groupId>org.springframework.boot</groupId>\n<artifactId>spring-boot-starter-aop</artifactId>\n</dependency>\n<dependency>\n<groupId>org.projectlombok</groupId>\n<artifactId>lombok</artifactId>\n</dependency>\n</dependencies>\n<build>\n<plugins>\n<plugin>\n<groupId>org.apache.maven.plugins</groupId>\n<artifactId>maven-source-plugin</artifactId>\n<version>2.2.1</version>\n<executions>\n<execution>\n<id>attach-sources</id>\n<goals>\n<goal>jar-no-fork</goal>\n</goals>\n</execution>\n</executions>\n</plugin>\n</plugins>\n</build>\n</project>\n

这边稍微解释一下这几个依赖:

spring-boot-autoconfigure:提供自动化装配功能,是为了SpringBoot应用在各个模块提供自动化配置的作用;即加入对应pom,就会有对应配置其作用;所以我们想要自动装配功能,就需要引入这个依赖。

spring-boot-configuration-processor:将自定义的配置类生成配置元数据,所以在引用自定义STARTER的工程的YML文件中,给自定义配置初始化时,会有属性名的提示;确保在使用@ConfigurationProperties注解时,可以优雅的读取配置信息,引入该依赖后,IDEA不会出现“springbootconfigurationannotationprocessornotconfigured”的错误;编译之后会在META-INF下生成一个spring-configuration-metadata.json文件,大概内容就是定义的配置的元数据;效果如下截图。

spring-boot-starter-aop:这个就不用解释了,因为示例是记录日志,我们用到切面的功能,所以需要引入。

/**\n*@authorkongxiangdong2\n*@Title:LogProperties\n*@ProjectNamejd-log-spring-boot-starter\n*@Description:TODO\n*@date2022/9/110:04\n*/\n@ConfigurationProperties(prefix="jd")\n@Data\npublicclassLogProperties{\n\n\n/**\n*是否开启日志\n*/\nprivatebooleanenable;\n\n\n/**\n*平台:不同服务使用的区分,默认取spring.application.name\n*/\n@Value("${spring.application.name:#{null}}")\nprivateStringplatform;\n

@ConfigurationProperties:该注解和@Value注解作用类似,用于获取配置文件中属性定义并绑定到JavaBean或者属性中;换句话来说就是将配置文件中的配置封装到JAVA实体对象,方便使用和管理。

这边我们定义两个属性,一个是是否开启日志的开关,一个是标识平台的名称。

/**\n*@authorkongxiangdong2\n*@Title:JdLogAutoConfiguration\n*@ProjectNamejd-log-spring-boot-starter\n*@Description:TODO\n*@date2022/9/110:06\n*/\n@Configuration\n@ComponentScan("com.jd")\n@ConditionalOnProperty(prefix="jd",name="enable",havingValue="true",matchIfMissing=false)\n@EnableConfigurationProperties({LogProperties.class})\npublicclassJdLogAutoConfiguration{\n\n\n//\n}

这个类最关键了,它是整个starter最重要的类,它就是将配置自动装载进spring-boot的;具体是怎么实现的,下面在讲解原理的时候会再详细说说,这里先完成示例。

@Configuration:这个就是声明这个类是一个配置类

@ConditionalOnProperty:作用是可以指定prefix.name配置文件中的属性值来判定configuration是否被注入到Spring,就拿上面代码的来说,会根据配置文件中是否配置jd.enable来判断是否需要加载JdLogAutoConfiguration类,如果配置文件中不存在或者配置的是等于false都不会进行加载,如果配置成true则会加载;指定了havingValue,要把配置项的值与havingValue对比,一致则加载Bean;配置文件缺少配置,但配置了matchIfMissing=true,加载Bean,否则不加载。

在这里稍微扩展一下经常使用的Condition

PropertyConditions环境变量条件注解(含配置文件)

prefix前缀name名称havingValue用于匹配配置项值matchIfMissing没找指定配置项时的默认值

ResourceConditions资源条件注解

WebApplicationConditionsweb条件注解

@ConditionalOnNotWebApplication

WebApplicationConditionsweb条件注解

@EnableConfigurationProperties使@ConfigurationProperties注解的类生效。

在resources/META-INF/目录新建spring.factories文件,配置内容如下;

org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.jd.JdLogAutoConfiguration

好了,至此自定义Starter大体框架已经好了,下面就是我们记录日志的功能。

/**\n*@authorkongxiangdong2\n*@Title:Jdlog\n*@ProjectNamejd-log-spring-boot-starter\n*@Description:TODO\n*@date2022/9/110:04\n*/\n@Target(ElementType.METHOD)\n@Retention(RetentionPolicy.RUNTIME)\npublic@interfaceJdlog{\n}

定义切面执行逻辑,这边就简单的打印一下配置文件的属性值+目标执行方法+耗时。

importcom.jd.annotation.Jdlog;\nimportcom.jd.config.LogProperties;\nimportlombok.AllArgsConstructor;\nimportlombok.extern.slf4j.Slf4j;\nimportorg.aspectj.lang.ProceedingJoinPoint;\nimportorg.aspectj.lang.annotation.Around;\nimportorg.aspectj.lang.annotation.Aspect;\nimportorg.aspectj.lang.annotation.Pointcut;\nimportorg.springframework.stereotype.Component;\n\n\n/**\n*@authorkongxiangdong2\n*@Title:LogAspectjProcess\n*@ProjectNamejd-log-spring-boot-starter\n*@Description:TODO\n*@date2022/9/111:12\n*/\n@Aspect\n@Component\n@Slf4j\n@AllArgsConstructor\npublicclassLogAspectjProcess{\n\n\nLogPropertieslogProperties;\n\n\n/**\n*定义切点\n*/\n@Pointcut("@annotation(com.jd.annotation.Jdlog)")\npublicvoidpointCut(){}\n\n\n/**\n*环绕通知\n*\n*@paramthisJoinPoint\n*@paramjdlog\n*@return\n*/\n@Around("pointCut()&&@annotation(jdlog)")\npublicObjectaround(ProceedingJoinPointthisJoinPoint,Jdlogjdlog){\n\n\n//执行方法名称\nStringtaskName=thisJoinPoint.getSignature()\n.toString().substring(\nthisJoinPoint.getSignature()\n.toString().indexOf(""),\nthisJoinPoint.getSignature().toString().indexOf("("));\ntaskName=taskName.trim();\nlongtime=System.currentTimeMillis();\nObjectresult=null;\ntry{\nresult=thisJoinPoint.proceed();\n}catch(Throwablethrowable){\nthrowable.printStackTrace();\n}\nlog.info("{}--method:{}run:{}ms",logProperties.getPlatform(),taskName,\n(System.currentTimeMillis()-time));\nreturnresult;\n\n\n

整体项目结构就是这样子

然后就可以在其他项目中引入使用了;下面以一个简单的spring-bootweb项目做个测试,在pom中引入下面的依赖配置。

<dependency>\n<groupId>com.jd</groupId>\n<artifactId>jd-log-spring-boot-starter</artifactId>\n<version>1.0-SNAPSHOT</version>\n</dependency>

增加一个http访问的方法,标注上@Jdlog注解

jd:\nenable:true\nplatform:"测试项目"

启动测试,访问地址http://localhost:8080/test/method1,控制台打印如下:

咋样,自定义的Starter是不是特别的简单啊,快动手试试吧!

上面我们讲的都是怎么去开发一个starter,但是到底为什么要这样,spring-boot是如何去实现的?是不是还不知道?那下面我们就来说说;

我们上面已经看到一个starter,只需要引入到pom文件中,再配置一下(其实都可以不配置)jd.enable=true,就可以直接使用记录日志的功能了,Spring-boot是怎么做到的?

在开始的时候说过,Spring-boot的好处就是可以自动装配。那下面我就来说说自动装配的原理。

相比于传统Spring应用,我们搭建一个SpringBoot应用,我们只需要引入一个注解(前提:引入springBooty依赖)@SpringBootApplication,就可以直接运行;所以我们就从这个注解开始入手,看看这个注解到底做了写什么?

点开@SpringBootApplication注解可以看到包含了@SpringBootConfiguration,@EnableAutoConfiguration,@ComponentScan三个注解。

前面的四个注解就不用过多叙述了,是定义注解最基本的,关键在于后面的三个注解:@SpringBootConfiguration,@EnableAutoConfiguration,@ComponentScan,其实也就是说在启动类上如果不使用@SpringBootApplication这个复合注解,直接使用者三个注解一样可以达到相同的效果。

@SpringBootConfiguration注解:我们再次点进去看这个注解,其实它就是一个@Configuration注解。

@ComponentScan注解:配置包扫描定义的扫描路径,把符合扫描规则的类装配到spring容器

@EnableAutoConfiguration打开自动装配(自动配置着重来看该注解)

加上这个注解就是为了让当前类作为一个配置类交由Spring的IOC容器进行管理,因为前面我们说了,SpringBoot本质上还是Spring,所以原属于Spring的注解@Configuration在SpringBoot中也可以直接应用

配置包扫描定义的扫描路径,把符合扫描规则的类装配到spring容器

用于定义Spring的扫描路径,等价于在xml文件中配置<context:component-scan>,假如不配置扫描路径,那么Spring就会默认扫描当前类所在的包及其子包中的所有标注了@Component,@Service,@Controller等注解的类。

我们再次点击@EnableAutoConfiguration进入查看,它是一个由@AutoConfigurationPackage和@Import注解组成的复合注解;

首先我们先来看@Import这个注解,这个是比较关键的一个注解;

在说这个注解之前我们先举个例子,假如我们有一个类Demo,它是一个不在启动配置类目录之下的,也就意味着它不会被扫描到,Spring也无法感知到它的存在,那么如果需要能将它被扫描到,是不是我们可以通过加@Import注解来导入Demo类,类似如下代码

@Configuration\n@Import(Demo.class)\npublicclassMyConfiguration{\n}

所以,我们可以知道@Import注解其实就是为了去导入一个类。所以这里@Import({AutoConfigurationImportSelector.class})就是为了导入AutoConfigurationImportSelector类,那我们继续来看这个类,AutoConfigurationImportSelector实现的是DeferredImportSelector接口,这是一个延迟导入的类;再细看会有一个方法比较显眼,根据注解元数据来选择导入组件,当注解元数据空,直接返回一个空数组;否则就调用getAutoConfigurationEntry,方法中会使用AutoConfigurationEntry的getConfigurations(),configurations是一个List<String>,那么我们看下AutoConfigurationEntry是怎么生成的。

进入到getAutoConfigurationEntry方法中可以看到主要是getCandidateConfigurations来获取候选的Bean,并将其存为一个集合;后续的方法都是在去重,校验等一系列的操作。

我们继续往getCandidateConfigurations方法里看,最终通过SpringFactoriesLoader.loadFactoryNames来获取最终的configurations,并且可以通过断言发现会使用到META-INF/spring.factories文件,那么我们再进入SpringFactoriesLoader.loadFactoryNames()中来看下最终的实现。

SpringFactoriesLoader.loadFactoryNames()方法会读取META-INF/spring.factories文件下的内容到Map中,再结合传入的factoryType=EnableAutoConfiguration.class,因此会拿到org.springframework.boot.autoconfigure.EnableAutoConfiguration为key对应的各个XXAutoConfiguration的值,然后springboot在结合各个starter中的代码完成对于XXAutoConfiguration中的Bean的加载动作。

这边再扩展一下这个内容,通过SpringFactoriesLoader来读取配置文件spring.factories中的配置文件的这种方式是一种SPI的思想。

进入这个注解看,其实它就是导入了Registrar这个类

再进入这个类查看,它其实是一个内部类,看代码的大概意思就是读取到我们在最外层的@SpringBootApplication注解中配置的扫描路径(没有配置则默认当前包下),然后把扫描路径下面的Bean注册到容器中;

好了,现在我们大概来理一下整个自动装配的流程:

到这里是不是已经可以很了然对我们之前开发starter中的定义了啊,赶紧试试吧

starter是什麼意思和手把手带你开发starter,点对点带你讲解原理的问题分享结束啦,以上的文章解决了您的问题吗?欢迎您下次再来哦!

本站涵盖的内容、图片、视频等数据,部分未能与原作者取得联系。若涉及版权问题,请及时通知我们并提供相关证明材料,我们将及时予以删除!谢谢大家的理解与支持!

Copyright © 2023