八、自定义starter

AutoConfiguration:

1、这个场景需要使用到的依赖是什么?

没有特别依赖的配置

2、如何编写自动配置

@Configuration  //指定这个类是一个配置类
@ConditionalOnXXX //在指定条件成立的情况下自动配置类生效
@AutoConfigureAfter({YYY.class,ZZZ.class}) //指定自动配置类的顺序,在哪个自动配置类之后才配置
@Bean //给容器中添加组件,写成@Component也可

@ConfigurationPropertie // 结合相关xxxProperties类来绑定相关的配置
@EnableConfigurationProperties //让xxxProperties生效直接加入到容器中,可以直接使用@Autowired自动包装该xxxProperties类

//自动配置类要能加载
//将需要启动就加载的自动配置类,配置在META-INF/spring.factories (比如spring-boot-autoconfigure-1.5.14.RELEASE.jar包的类路径下的/META-INF/spring.factories文件)
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\

模式:

starter启动器只用来做依赖导入;可以是一个空jar文件,仅提供辅助性依赖管理,这些依赖可能用于自动装配或其它类库。所以建模块时建成普通manven即可。

autoconfigurer自动配置模块必需要依赖spring-boot-starter, 所以建模块时最好建成springboot项目。

starter和autoconfigurer分成两个项目, 是为了形成一个starter对应对多autoconfigurer的后期扩展,方便管理。以后别人引用时只需要引用starter,而不用关心autoconfigurer。

建议命名规则

  命名规则 定义名 举例  
官方starter spring-boot-starter-OfficalDefinition 名字在后面 spring-boot-starter-jdbc  
自定义starter MyDefinition-spring-boot-starter 名字在前面 starter叫mybatis-spring-boot-starter  
         

项目说明

1、my-spring-boot-starter-autoconfigurer  自动配置模块

2、my-spring-boot-starter 场景启动器starter模块 ,依赖my-spring-boot-starter-autoconfigurer

3、starter-demo 主项目 依赖my-spring-boot-starter

starter-demo-2019-6-12 15-17-11.snag

步骤

1、自动配置模块 my-spring-boot-starter-autoconfigurer

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>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.5.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>my-spring-boot-starter-autoconfigurer</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>my-spring-boot-starter-autoconfigurer</name>
<description>Demo project for Spring Boot</description> <properties>
<java.version>1.8</java.version>
</properties> <dependencies>
<!--autoconfigurer只需要依赖原生的spring-boot-starter-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency> <!-- 配置文件自动映射 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
</dependencies> </project>

Ticket.java

package com.example.simple.bean;

import java.io.Serializable;

public class Ticket implements Serializable {
public Integer id;
public String name;
private String type; public Ticket() {
} public Ticket(Integer id, String name, String type) {
this.id = id;
this.name = name;
this.type = type;
}
//get set toString ....
}

TicketProperties.java

package com.example.simple.bean;

import org.springframework.boot.context.properties.ConfigurationProperties;

//和application.properties或application.yml产生关联
@ConfigurationProperties(prefix = "com.ticket")
public class TicketProperties {
Integer id;//可以用 application.properties中com.ticket.id=xxx 的配置自动赋值
String name;//可以用 application.properties中com.ticket.name=xxx 的配置自动赋值
String type;//可以用 application.properties中com.ticket.type=xxx 的配置自动赋值 public Integer getId() {
return id;
} public void setId(Integer id) {
this.id = id;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public String getType() {
return type;
} public void setType(String type) {
this.type = type;
}
}

ITicketService.java

接口

package com.example.simple.service;

import com.example.simple.bean.Ticket;
import com.example.simple.bean.TicketProperties; public interface ITicketService {
public Ticket getDefaultTicket(String type); public TicketProperties getTicketProperties(); public void setTicketProperties(TicketProperties ticketProperties);
}

PianoTicketService.java

package com.example.simple.service;

import com.example.simple.bean.Ticket;
import com.example.simple.bean.TicketProperties; /**
* 为了在 TicketServiceAutoConfiguration 的@Bean注解的方法中使用以返回该对象到IOC容器中,
* 最终可以让其它依赖后的项目的Controller,Service等组件使用@Autowired自动装配该Bean
*/
public class PianoTicketService implements ITicketService {
TicketProperties ticketProperties; @Override
public Ticket getDefaultTicket(String type){//用于其它项目的Controller中
Ticket ticket = new Ticket(9999,ticketProperties.getName(),ticketProperties.getType());
return ticket;
} @Override
public TicketProperties getTicketProperties() { //get方法
return ticketProperties;
} @Override
public void setTicketProperties(TicketProperties ticketProperties) {//set方法
this.ticketProperties = ticketProperties;
} }

ViolinTicketService.java

package com.example.simple.service;

import com.example.simple.bean.Ticket;
import com.example.simple.bean.TicketProperties; public class ViolinTicketService implements ITicketService {
TicketProperties ticketProperties; @Override
public Ticket getDefaultTicket(String type){//用于其它项目的Controller中
Ticket ticket = new Ticket(9999,ticketProperties.getName(),ticketProperties.getType());
return ticket;
} @Override
public TicketProperties getTicketProperties() {//get方法
return ticketProperties;
} @Override
public void setTicketProperties(TicketProperties ticketProperties) {//set方法
this.ticketProperties = ticketProperties;
} }

TicketServiceAutoConfiguration.java

package com.example.simple.config;

import com.example.simple.bean.TicketProperties;
import com.example.simple.service.ITicketService;
import com.example.simple.service.PianoTicketService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; @Configuration//标注这是一个配置类,这个类的位置不需要在启动类MySpringBootApplication的子包下,因为由META-INF/spring.factories指定了加载位置
@ConditionalOnWebApplication//添加一些条件(也可以不加)web项目时才有效
@ConditionalOnClass({ITicketService.class})//ITicketService.class存在时本配置才有效
//@ConditionalOnMissingClass({"com.example.simple.service.ITicketService"})//指定类不存在的时候配置才有效
@EnableConfigurationProperties(TicketProperties.class)//让TicketProperties在当前配置中直接生效
public class TicketServiceAutoConfiguration {//声明自动配置类 @Autowired
TicketProperties ticketProperties;//自动包装 //声明自动装配的Bean,这样当于在项目启动时就内置加载了该Bean
@Bean
//这个配置就是SpringBoot可以优先使用自定义Bean的核心所在,如果没有我们的自定义Bean ITicketService.class 存在, 那么才会自动配置一个新的Bean
@ConditionalOnMissingBean(ITicketService.class)
public ITicketService ticketService() {
System.out.println("my-spring-boot-starter-autoconfigurer的bean:ticketService装配到容器成功");
ITicketService ticketService = new PianoTicketService();//声明对象
ticketService.setTicketProperties(ticketProperties);//设置属性
return ticketService;//返回对象
} // 参考: https://blog.csdn.net/xcy1193068639/article/details/81517456
//@ConditionOnBean在判断list的时候,如果list没有值,返回false,否则返回true
//@ConditionOnMissingBean在判断list的时候,如果list没有值,返回true,否则返回false,其他逻辑都一样 }

spring.factories

创建文件夹及文件 src\main\resources\META-INF\spring.factories  , 目录不可更改

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.simple.config.TicketAutoConfiguration

如果有多个自动配置类

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.xxx.yyy.Zzz1AutoConfiguration,\
com.xxx.yyy.Zzz2AutoConfiguration,\
com.xxx.yyy.Zzz3AutoConfiguration

2、启动器模块 my-spring-boot-starter

可以包含多个autoconfigurer模块, 方便其它项目引用

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>

<groupId>com.example</groupId>
<artifactId>my-spring-boot-starter</artifactId>
<version>1.0-SNAPSHOT</version>

<!--引入自动配置模块-->
<dependencies>
<dependency>
<groupId>com.example</groupId>
<artifactId>my-spring-boot-starter-autoconfigurer</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency> <!--
<dependency>
<groupId>com.example</groupId>
<artifactId>my-spring-boot-starter-other-autoconfigurer</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
--> </dependencies>
</project>

3、 starter-demo

starter-demo为依赖my-spring-boot-starter的项目 , 就像正常maven项目一样, 在pom.xml添加my-spring-boot-starter即可.

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>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.5.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>starter-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>starter-demo</name>
<description>Demo project for Spring Boot</description>

<properties>
<java.version>1.8</java.version>
</properties>

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<!--配置自定义的starter依赖-->
<dependency>
<groupId>com.example</groupId>
<artifactId>my-spring-boot-starter</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>

</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>

</project>

TicketController.java

http get访问入口 http://localhost:8080/ticket?type=piano

package com.example.starterdemo.controller;

import com.example.simple.bean.Ticket;
import com.example.simple.service.ITicketService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController; @RestController
public class TicketController { @Autowired
ITicketService ticketService; //http://localhost:8080/ticket?type=piano
@GetMapping(value = "/ticket")
public Ticket getDefaultTicket(String type){
Ticket ticket = ticketService.getDefaultTicket(type);
return ticket;
}
}

StarterDemoApplication.java

启动应用的类 , 启用了public ITicketService ticketService() 方法, 会在容器中添加ITicketService bean , 让默认自动配置失效, 当注释该方法后, 又可以启动自动配置.

package com.example.starterdemo;

import com.example.simple.bean.TicketProperties;
import com.example.simple.service.ITicketService;
import com.example.simple.service.PianoTicketService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean; @SpringBootApplication
public class StarterDemoApplication { //声明自动装配的Bean,这样当于在项目启动时就内置加载了该Bean
//本bean将会优先于my-spring-boot-starter-autoconfigurer自动装配模块的 TicketServiceAutoConfiguration 类中的ticketService bean的初始化,
//而自动装配模块有@ConditionalOnMissingBean(ITicketService.class)条件,所以一旦配了该bean,将替换自动装配模块的bean
//为了作出区别,本bean的初始化值不再从properties文件中获取,而是直接代码声明了.
@Bean
public ITicketService ticketService() {
System.out.println("starter-demo的bean:ticketService装配到容器成功, my-spring-boot-starter-autoconfigurer的bean:ticketService不再装配"); ITicketService ticketService = new PianoTicketService();//声明对象
TicketProperties ticketProperties = new TicketProperties();
ticketProperties.setId(8888);
ticketProperties.setName("圣母颂");
ticketProperties.setType("violin"); ticketService.setTicketProperties(ticketProperties);//设置属性
return ticketService;//返回对象
} //http://localhost:8080/ticket?type=piano
public static void main(String[] args) {
SpringApplication.run(StarterDemoApplication.class, args);
}
}

参考

SpringBoot @ConditionalOnBean、@ConditionalOnMissingBean注解源码分析与示例==>https://blog.csdn.net/xcy1193068639/article/details/81517456

我的项目git地址

我的git代码地址: https://gitee.com/KingBoBo/Spring-Boot-Starter-Demo  starter分支

springboot 自定义starter之AutoConfiguration【原】的更多相关文章

  1. SpringBoot --- 自定义 Starter

    SpringBoot --- 自定义 Starter 创建 1.需要创建一个新的空工程 2.新的工程需要引入两个模块 一个Maven 模块 作为启动器 一个SpringBoot 模块 作为自动配置模块 ...

  2. SpringBoot自定义starter及自动配置

    SpringBoot的核心就是自动配置,而支持自动配置的是一个个starter项目.除了官方已有的starter,用户自己也可以根据规则自定义自己的starter项目. 自定义starter条件 自动 ...

  3. SpringBoot自定义Starter实现

    自定义Starter: Starter会把所有用到的依赖都给包含进来,避免了开发者自己去引入依赖所带来的麻烦.Starter 提供了一种开箱即用的理念,其中核心就是springboot的自动配置原理相 ...

  4. SpringBoot自定义starter开发分布式任务调度实践

    概述 需求 在前面的博客<Java定时器演进过程和生产级分布式任务调度ElasticJob代码实战>中,我们已经熟悉ElasticJob分布式任务的应用,其核心实现为elasticjob- ...

  5. SpringBoot系列三:SpringBoot自定义Starter

    在前面两章 SpringBoot入门 .SpringBoot自动配置原理 的学习后,我们对如何创建一个 SpringBoot 项目.SpringBoot 的运行原理以及自动配置等都有了一定的了解.如果 ...

  6. springboot自定义starter

    1,创建一个空工程 2,new一个Modules  ---------------- maven (启动器) : springboottest-spring-boot-starter 3,new一个M ...

  7. Spring-Boot自定义Starter实践

    此文已由作者王慎为授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. disconf-spring-boot-starter 使用方法: 引入maven依赖: <depen ...

  8. Springboot自定义starter打印sql及其执行时间

    前面写到了通过实现mybatis提供的org.apache.ibatis.plugin.Interceptor接口实现了打印SQL执行时间,并格式化SQL及其参数,如果我们使用的是ssm还得再配置文件 ...

  9. SpringBoot第十六篇:自定义starter

    作者:追梦1819 原文:https://www.cnblogs.com/yanfei1819/p/11058502.html 版权声明:本文为博主原创文章,转载请附上博文链接! 前言   这一段时间 ...

随机推荐

  1. LeetCode简单算法之分割平衡字符串 #1221

    在一个「平衡字符串」中,'L' 和 'R' 字符的数量是相同的. 给出一个平衡字符串 s,请你将它分割成尽可能多的平衡字符串. 返回可以通过分割得到的平衡字符串的最大数量. 示例 1: 输入:s = ...

  2. MyEclipse6.5安装SVN插件方法

    MyEclipse6.5安装SVN插件,掌握了几种方法,本节就像大家介绍一下MyEclipse6.5安装SVN插件的三种方法,看完本文你肯定有不少收获,希望本文能教会你更多东西. 一.安装方法: My ...

  3. 二、Web Service开发(.net)

    .net平台内建了对Web Service的支持,包括Web Service的构建和使用.与其它开发平台不同,使用.net平台,你不需要其他的工具或者SDK就可以完成Web Service的开发了.. ...

  4. 查看linux系统的文件inode号码使用情况

    :~$ df -i 文件系统 Inode 已用(I) 可用(I) 已用(I)% 挂载点 udev % /dev tmpfs % /run /dev/sda2 % / tmpfs % /dev/shm ...

  5. JavaScript 实现回文解码

    题目也是源自今日头条前端工程师笔试题.题目描述: 现在有一个字符串,你要对这个字符串进行 n 次操作,每次操作给出两个数字:(p, l) 表示当前字符串中从下标为 p 的字符开始的长度为 l 的一个子 ...

  6. Exception in thread "AWT-EventQueue-0" javax.persistence.PersistenceException: No Persistence provider for EntityManager named null

    swing Exception in thread "AWT-EventQueue-0" javax.persistence.PersistenceException: No Pe ...

  7. oracle习题-简单查询

    题一 1 实现将已知表中的数据插入到另一个表中 学生表:stu1 向表中插入两条数据   学生信息表2:stuinfo 将stu1表中的两条数据导入到stuinfo表中,执行下列语句 此时查看一下st ...

  8. oracle基本认识

    概要图 1. 环境搭建 1.1 Oracle的安装 数据库的三个常用的用户及默认密码sys:change_on_installsystem:managerscott:tiger Oracle客户端: ...

  9. Leetcode572.Subtree of Another Tree另一个树的子树

    给定两个非空二叉树 s 和 t,检验 s 中是否包含和 t 具有相同结构和节点值的子树.s 的一个子树包括 s 的一个节点和这个节点的所有子孙.s 也可以看做它自身的一棵子树. 示例 1: 给定的树 ...

  10. redis书籍

    redis中文官网命令网址:http://doc.redisfans.com/ redis英文官网命令网址:https://redis.io/commands redis书籍 由 Karl Segui ...