SpringBoot起飞系列-自定义starter(十)
一、前言
到现在,我们可以看出来,如果我们想用一些功能,基本上都是通过添加spring-boot-starter的方式来使用的,因为各种各样的功能都被封装成了starter,然后把相关服务注入到容器中去,那么如果我们想用一下自己的某些功能呢,那就也要编写一个自定义的starter,所以今天我们就来看看,怎么编写自己的starter,来实现在springboot中实现自己想要的一些功能。
二、原理
回想一下, 当我们使用一个官方的starter的时候,只需要将相应的starter依赖包添加到pom.xml中去就可以了,然后maven自动下载依赖包,并且springboot在启动后会自动配置相关的服务,然后注入的到容器中去。那么springboot是如何知道要去调用哪些方法,加载哪些配置,并注入哪些bean呢?
基本步骤如下:
1.首先,springboot在启动的时候会去找starter包下resources/META-INF/spring.factories文件,然后根据文件中配置的自动配置类运行,加载autoconfigure类。
2.根据@Conditional注解的条件,决定Bean是否要注入的容器中去。
3.然后我们一般用的就是这个Bean,来使用其中的一些功能。
三、编写自己的Starter
3.1 创建maven项目
首先我们创建一个maven项目,按照如下名字起名,其实starter说白了也只是一个jar:
一般的,官方的starter命名方式是spring-boot-start-xxx的形式,为了区分,我们自定义的starter用xxx-spring-boot-starter的命名方式。
1.添加springboot的依赖,因为要成为一个spring-boot-starter是需要依赖springboot的这套流程的,所以我们引入以下依赖:
- <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>
- <groupId>com.example.demo</groupId>
- <artifactId>person-spring-boot-starter</artifactId>
- <version>1.0-SNAPSHOT</version>
- <packaging>jar</packaging>
- <dependencies>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-autoconfigure</artifactId>
- <version>2.0.0.RELEASE</version>
- </dependency>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-configuration-processor</artifactId>
- <version>2.0.0.RELEASE</version>
- <optional>true</optional>
- </dependency>
- </dependencies>
- </project>
2.添加配置类PersonProperties,主要来从配置文件中读取配置绑定到这个类上:
- package com.example.demo;
- import org.springframework.boot.context.properties.ConfigurationProperties;
- @ConfigurationProperties(prefix = "spring.person")
- public class PersonProperties {
- private String name;
- private Integer age;
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public Integer getAge() {
- return age;
- }
- public void setAge(Integer age) {
- this.age = age;
- }
- }
3.添加我们的核心服务类,这里边是我们主要提供的功能,假设我们提供了一个sayHello方法,返回一段话:
- package com.example.demo;
- public class PersonService {
- private PersonProperties personProperties;
- public PersonService(PersonProperties personProperties) {
- this.personProperties = personProperties;
- }
- public String sayHello() {
- return "大家好,我叫: " + personProperties.getName() + ", 今年" + personProperties.getAge() + "岁";
- }
- }
4.添加自动配置类,这个类主要是给springboot来用的,springboot会用这个类来启动,激活我们的服务,注册都容器中去:
- @Configuration
- @EnableConfigurationProperties(PersonProperties.class)
- @ConditionalOnClass(PersonService.class)
- @ConditionalOnProperty(prefix = "spring.person", value = "enabled", matchIfMissing = true)
- public class PersonServiceAutoConfiguration {
- @Autowired
- private PersonProperties personProperties;
- @Bean
- public PersonService personService(){
- return new PersonService(personProperties);
- }
- }
解释一下代码中用到的几个注解:
- @ConditionalOnClass,当classpath下发现该类的情况下进行自动配置。
- @ConditionalOnMissingBean,当Spring Context中不存在该Bean时。
- @ConditionalOnProperty(prefix = "srping.person",value = "enabled",havingValue = "true"),当配置文件中spring.perons.enabled=true时。如果没有,使用matchIfMissing的值,也为true。
- @Bean,把返回的PersonService对象添加的spring容器中去,这样我们再使用的使用就可以直接装配了。
其他注解:
- @ConditionalOnBean:当容器中有指定的Bean的条件下
- @ConditionalOnClass:当类路径下有指定的类的条件下
- @ConditionalOnExpression:基于SpEL表达式作为判断条件
- @ConditionalOnJava:基于JVM版本作为判断条件
- @ConditionalOnJndi:在JNDI存在的条件下查找指定的位置
- @ConditionalOnMissingBean:当容器中没有指定Bean的情况下
- @ConditionalOnMissingClass:当类路径下没有指定的类的条件下
- @ConditionalOnNotWebApplication:当前项目不是Web项目的条件下
- @ConditionalOnProperty:指定的属性是否有指定的值
- @ConditionalOnResource:类路径下是否有指定的资源
- @ConditionalOnSingleCandidate:当指定的Bean在容器中只有一个,或者在有多个Bean的情况下,用来指定首选的Bean
- @ConditionalOnWebApplication:当前项目是Web项目的条件下
5. 在resources下添加spring.factories文件,目录结构如下/resources/META-INF/spring.factories,springboot会自动识别这个文件,加载运行我们的PersonServiceAutoConfiguration类。
6.编译运行,用maven install安装jar,默认会安装的maven的仓库里边,用于后来我们使用。
3.2 创建springboot项目测试
这一步简单就不说了,直接按模板创建一个springboot的web项目就行了,然后我们在pom.xml中添加我们刚才写好的person-spring-boot-starter:
- <dependency>
- <groupId>com.example.demo</groupId>
- <artifactId>person-spring-boot-starter</artifactId>
- <version>1.0-SNAPSHOT</version>
- </dependency>
配置文件中添加starter的配置项:
- spring.person.age=12
- spring.person.name=songlin
添加一个控制器测试:
- @RestController
- public class HelloController {
- @Autowired
- PersonService personService;
- @GetMapping("/hello")
- public String hello(){
- String s = personService.sayHello();
- return s;
- }
- }
访问http://localhost:8080/hello,显示如下:
四、总结
当我们想往springboot集成一个功能的时候,就可以用这种方式了,关于starter的写法,大家还可以参看源码,理解了源码我们就能写出更好用的starter了。springboot的基本入门系列就先到这了,往后我们就开始学习springboot集成高级功能了。
SpringBoot起飞系列-自定义starter(十)的更多相关文章
- SpringBoot起飞系列-Web开发(四)
一.前言 从今天你开始我们就开始进行我们的web开发,之前的一篇用SpringBoot起飞系列-使用idea搭建环境(二)已经说明了我们如何进行开发,当然这是搭建起步,接下来我们就开始进行详细的开发, ...
- SpringBoot起飞系列-国际化(六)
一.前言 国际化这个功能可能我们不常用,但是在有需要的地方还是必须要上的,今天我们就来看一下怎么在我们的web开发中配置国际化,让我们的网站可以根据语言来展示不同的形式.本文接续上一篇SpringBo ...
- SpringBoot起飞系列-配置文件(三)
一.SpringBoot中的配置文件 说起到配置文件,大家并不陌生,早在springboot之前,我们用ssh,ssm框架开发的时候整天都要接触配置文件,那时候的配置文件基本上都是.propertie ...
- SpringBoot起飞系列-入门(一)
一.SpringBoot简介 1.1 什么是SpringBoot 说到spring系列,可能大家都很熟悉,spring.springmvc,美之名曰:spring全家桶,那么springboot其实也 ...
- SpringBoot起飞系列-数据访问(九)
一.前言 前边我们已经学些了开发的基本流程,最重要的一步来了,怎么样和数据库交互才是最重要的,毕竟没有数据那就相当于什么也没做,本文我们来学习使用springboot整合jdbc.mybatis.jp ...
- SpringBoot起飞系列-配置嵌入式Servlet容器(八)
一.前言 springboot中默认使用的是tomcat容器,也叫做嵌入式的servlet容器.因为它和我们平常使用的tomcat容器不一样,这个tomcat直接嵌入到的springboot,平常我们 ...
- SpringBoot起飞系列-拦截器和统一错误处理(七)
一.前言 在前边部分我们已经学会了基本的web开发流程,在web开发中,我们通常会对请求做统一处理,比如未登录的用户要拦截掉相关请求,报错页面统一显示等等,这些都需要配置,可以大大简化我们的代码,实现 ...
- SpringBoot学习(2) - 自定义starter
自己开发一个spring boot starter的步骤1.新建一个项目(全部都基于maven),比如新建一个spring-boot-starter-redis的maven项目 pom.xml: &l ...
- SpringBoot起飞系列-日志使用(四)
一.SpringBoot中的日志组件 日志是一个系统中不可缺少的组件.在项目中,我们常用的日志组件有JUL.JCL.Jboss-logging.logback.log4j.log4j2.slf4j.. ...
随机推荐
- ros中同时订阅两个topic(2张图像)合并成一个topic(1张图像)
2019-12-06 15:42:39 先暂时做个资料保存 要同时用两个红外相机,但是没有做硬件上的 时间戳同步,就是笔记本上同时插着两个相机. 两个topic发布各自相机的图像,然后要有个节点同时订 ...
- SSO 断点登陆
1. 摘要 ( 注意:请仔细看下摘要,留心此文是否是您的菜,若浪费宝贵时间,深感歉意!!!) SSO这一概念由来已久,网络上对应不同场景的成熟SSO解决方案比比皆是,从简单到复杂,各式各样应有尽有!开 ...
- .NetCore 读取配置文件
1.创建config.json配置,并设置成始终复制 2.需要安装 nuget 包 Microsoft.Extensions.Configuration .Microsoft.Extensions.C ...
- 7.13 T2 Shit 题(shit)
[题目描述] 某一天,小
- Codeforces 940 E.Cashback (单调队列,dp)
Codeforces 940 E.Cashback 题意:一组数,要分为若干个区间,每个区间长度为ki(1<=ki<=n),并且对于每个区间删去前ki/c(向下取整)个小的数(即对区间升序 ...
- Java基础线程系列大纲
## Java 多线程之 线程创建 ## Java 多线程之 Sleep ## Java 多线程之 Join ## Java 多线程之 生命周期 ## Java 多线程之 wait, notify a ...
- POJ 3177 (Redundant Paths) —— (有重边,边双联通,无向图缩点)
做到这里以后,总算是觉得tarjan算法已经有点入门了. 这题的题意是,给出若干个点和若干条边连接他们,在这个无向图中,问至少增加多少条边可以使得这个图变成边双联通图(即任意两点间都有至少两条没有重复 ...
- CSS子元素在父元素中水平垂直居中的几种方法
1. 水平居中(margin: auto;)子父元素宽度固定,子元素上设置 margin: auto; 子元素不能设置浮动,否则居中失效. #div1{ width: 300px; height: 3 ...
- Redis 延迟指标监控
Redis 延迟监控框架 Redis 2.8.13 引入了Latency Monitoring的一个新功能,可以帮助我们检查和排查引起延迟的原因. Latecny Monitoring 由如下组成: ...
- break语句与continue语句
break:终止该层循环: continue:跳过该层循环 注: ①:若这两个语句离开应用范围,存在是没有意义的. ②:这个两个语句后面都不能有语句,因为执行不到. ③:continue语句是跳过本次 ...