IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> 进阶篇-SpringBoot2.x自定义starter启动器 -> 正文阅读

[Java知识库]进阶篇-SpringBoot2.x自定义starter启动器

1、本篇前言

Spring Boot为我们提供了简化企业级开发绝大多数场景的
starter pom【比如springb-boot-starter-web,springb-boot-starter-jdbc等】, 使用应用场景所需要的starter pom,只需要引入对应的starter,即可以得到Spring Boot为我们提供的自动配置的Bean。
然而,可能在很多情况下,我们需要自定义stater,这样可以方便公司内部系统调用共同的配置模块的时候可以自动进行装载配置。比如公司的很多内部系统都有认证授权模块、以及基于AOP实现的日志切面等,这些技术在不同的项目中逻辑基本相同,而这些功能可以通过starter自动配置的形式进行配置,即可达到可复用的效果。

(1)Starter的概念

SpringBoot之所以大大地简化了我们的开发,用到的一个很重要的技术就是Starter机制!
Starter机制抛弃了以前xml中繁杂的配置,将各种配置统一集成进了Starter中,开发人员只需要在maven中引入Starter依赖,SpringBoot就能自动扫描出要加载的配置信息并按相应的默认配置来启动项目。
所以Starter可以理解为一个可拔插式的插件,提供了一系列便利的依赖描述符,使得我们可以获得所需的所有Spring和相关技术的一站式服务。应用程序只需要在maven中引入Starter依赖,SpringBoot就能自动扫描到要加载的信息并启动相应的默认配置,我们可以把Starter看做是Springboot的场景启动器。

(2)Starter的优点

  • Starter可以让我们摆脱开发过程中对各种依赖库的冲突处理。
  • 可以简化原有xml中各种负载的配置信息。
  • SpringBoot提供了针对一般研发中各种场景的spring-boot-starter依赖,所有这些依赖模块都遵循着约定成俗的默认配置(”约定大于配置“),并允许我们调整这些配置。Starter的出现极大的帮助开发者们从繁琐的框架配置中解放出来,从而更专注于业务代码。

(3)自定义Starter的场景

在我们的日常开发工作中,经常会有一些独立于业务之外的配置模块,我们经常将其放到一个特定的包下,然后如果另一个工程需要复用这块功能的时候,只需要将其在pom中引用依赖即可,利用SpringBoot为我们完成自动装配即可。

常见的自定义Starter场景比如:

  • 动态数据源
  • 登录模块
  • 基于AOP技术实现日志切面

(4)自定义Starter命名规范

SpringBoot官方建议其官方推出的starter以spring-boot-starter-xxx的格式来命名,而第三方开发者自定义的starter则以xxxx-spring-boot-starter的规则来命名,比如 mybatis-spring-boot-starter。

(5)自定义starter中几个重要注解

  • @Configuration: 表明此类是一个配置类,将变为一个bean被Spring进行管理。
  • @EnableConfigurationProperties: 启用属性配置,将读取指定类里面的属性。
  • @ConditionalOnClass: 当类路径下面有指定的类时,进行自动配置。
  • @ConditionalOnProperty: 判断指定的属性是否具备指定的值。
  • @ConditionalOnMissingBean:当容器中没有指定bean是,创建此bean。
  • @Import: 引入其他的配置类

2、自定义Starter记录日志案例

(1)项目结构

两个工程如下:log-spring-boot-starter[starter模块],spring-boot-demo-starter-test[starter使用演示工程]。

(2)log-spring-boot-starter项目pom文件添加依赖

<dependencies>
        <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>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

(3)编写请求日志注解

/**
 * 功能描述: 请求日志注解
 * @author  TuYong
 * @date  2022/9/7 20:48
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RequestLog {
    //接口方法上的描述信息
    String desc() default "";
}

(4)编写配置类

@Setter
@Getter
@ConfigurationProperties(prefix = "request.log")
public class LogProperties {

    private Boolean enabled = Boolean.FALSE;
}

(5)编写日志拦截器

/**
 * 功能描述: 日志拦截器
 * @author  TuYong
 * @date  2022/9/7 20:49
 */
@Slf4j
public class LogInterceptor implements HandlerInterceptor {
    private static final  ThreadLocal<Long> THREAD_LOCAL = new ThreadLocal<>();

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        HandlerMethod handlerMethod = (HandlerMethod) handler;
        RequestLog methodAnnotation = handlerMethod.getMethodAnnotation(RequestLog.class);
        if(methodAnnotation != null){
            long start = System.currentTimeMillis();
            THREAD_LOCAL.set(start);
        }
        return true;
    }
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        HandlerMethod handlerMethod = (HandlerMethod) handler;
        RequestLog methodAnnotation = handlerMethod.getMethodAnnotation(RequestLog.class);
        if(methodAnnotation != null){
            Method method = handlerMethod.getMethod();
            String requestUri = request.getRequestURI();
            String methodName = method.getDeclaringClass().getName()+":"+method.getName();
            String desc = methodAnnotation.desc();
            long end = System.currentTimeMillis();
            long start = THREAD_LOCAL.get();
            long l = end - start;
            THREAD_LOCAL.remove();
            log.info("请求路径:{},请求方法:{},描述信息:{},总计耗时:{}",requestUri,methodName,desc,l);
        }
    }
}

(6)编写自动配置类

/**
 * 功能描述: 自动配置
 * @author  TuYong
 * @date  2022/9/7 20:55
 */
@Configuration
@EnableConfigurationProperties({LogProperties.class})
@ConditionalOnProperty(
        prefix = "request.log",
        name = {"enabled"},
        havingValue = "true"
)
public class LogAutoConfiguration implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LogInterceptor()).addPathPatterns("/api/**");
        WebMvcConfigurer.super.addInterceptors(registry);
    }
}

(7)编写spring.factories

在resources/META-INF/下建立spring.factories文件,配置自动装配类路径

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
  cn.javaxxw.springboot.LogAutoConfiguration

(8)创建starter演示工程引入starter依赖

<dependencies>
        <dependency>
            <groupId>cn.javaxxw</groupId>
            <artifactId>log-spring-boot-starter</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>

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

(9)编写测试接口并使用starter中定义的注解

@RestController
@RequestMapping("api")
public class ApiController {

    @GetMapping("test")
    @RequestLog(desc = "测试接口")
    public Object test(){
        return "test api!";
    }
}

(10)配置文件

server:
  port: 8080
# 开启starter组件
request:
  log:
    enabled: true

(11)功能测试

通过请求测试接口,我们可以看到starter中的拦截器已经生效

(12)演示工程代码

gitee: https://gitee.com/trazen/springboot-demo.git

3、原理解析

第二章节中的开发流程,有两个地方需要我们了解一下:
(1)starter的自动识别加载:spring.factories里的EnableAutoConfiguration原理。
(2)实现自动加载的智能化、可配置化:@Configuration配置类里注解。

(1)配置类自动加载机制

在SpringBoot的启动类都会加上?@SpringBootApplication?注解。这个注解会引入?@EnableAutoConfiguration?注解。然后?@EnableAutoConfiguration?会?@Import(AutoConfigurationImportSelector.class)?。

AutoConfigurationImportSelector.class?的?selectImports?方法最终会通过?SpringFactoriesLoader.loadFactoryNames?,加载?META-INF/spring.factories?里的?EnableAutoConfiguration?配置值,也就是我们上文中设置的资源文件。

(2)自动加载的智能化可配置化

实际项目中,我们并不总是希望使用默认配置。比如有时候我想自己配置相关功能,或者只有某些bean没有被加载时才会加载starter配置类。这些常见的场景Starter都可以实现,并提供了如下的解决方案:

@Conditional*注解

springboot starter提供了一系列的@Conditional*注解,代表什么时候启用对应的配置,具体的可以去查看springboot的官方文档。常用注解如下:

  • @ConditionalOnBean:当容器里有指定的Bean的条件下。
  • @ConditionalOnClass: 当类路径下面有指定的类时,进行自动配置。
  • @ConditionalOnProperty: 判断指定的属性是否具备指定的值。
  • @ConditionalOnMissingBean:当容器中没有指定bean是,创建此bean。

比如我们案例中的??@ConditionalOnProperty(prefix = "request.log", name = {"enabled"},havingValue = "true")?,只有在应用配置??request.log.enabled = true?时该请求日志拦截功能才会生效。

@ConfigurationProperties注解

这个注解主要是为了解决如下场景:我想要使用starter的默认配置类,但是又想对配置中的某些参数进行自定义配置。@ConfigurationProperties类就是做这个工作的。例如上述例子中,我们在配置中使用enabled参数来决定是否启动该组件的日志拦截功能。

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-09-15 01:51:23  更:2022-09-15 01:52:33 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 13:07:35-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码