自定义 spring-boot-starter 暴露钩子

这篇具有很好参考价值的文章主要介绍了自定义 spring-boot-starter 暴露钩子。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。


 
       最近看了Springboot 相关的源码,正好项目上有需求,需要对自定义的 spring-boot-starter 封装的方法,暴露出钩子。对封装的方法,做一些前置或后置的扩展,所以简单写个demo 记录一下。

       这里用两种方法实现上面的需求,一种是使用 ApplicationContext 的事件发布机制实现。另一种是自己用 观察者模式 + ApplicationListener 实现。话不多说,直接上代码。

 

1、前置工作:自定义一个 spring-boot-starter

 

1.1、pom文件

 

<?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.demo</groupId>
    <artifactId>my-spring-boot-starter</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <java.version>1.8</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
            <version>2.3.5.RELEASE</version>
        </dependency>
        <!--包含自动配置的代码-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-autoconfigure</artifactId>
            <version>2.1.5.RELEASE</version>
        </dependency>
        <!--非必须:编写配置文件时会有提示-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <version>2.6.8</version>
            <optional>true</optional>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
            <version>2.3.5.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.16</version>
            <optional>true</optional>
        </dependency>

    </dependencies>


</project>

 

1.2、starter 封装的接口

 

package com.demo.server;

public interface MyService {

    // 该方法采用ApplicationContext 实现钩子暴露
    public void methodOne();

    public void methodTwo();

}


 

1.3、starter 的配置类

 

package com.demo;

import com.demo.server.impl.MyServiceImpl;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MyStarterConfig {

    @Bean
    @ConditionalOnMissingBean(MyServiceImpl.class)
    public MyServiceImpl myServiceImpl() {
        return new MyServiceImpl();
    }

}

 

1.4、starter 的 spring.factories

 
spring.factories 文件在 resources\META-INF 目录下

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.demo.MyStarterConfig

 

2、方法一:ApplicationContext 实现

 

2.1、MyService的实现类

 

package com.demo.server.impl;

import com.demo.entity.MethodOneAfter;
import com.demo.entity.MethodOneBefore;
import com.demo.event.PostHandleEvent;
import com.demo.server.MyService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;

@Slf4j
public class MyServiceImpl implements MyService {


    @Autowired
    private ApplicationContext applicationContext;



    @Override
    public void methodOne() {
        MethodOneBefore before = new MethodOneBefore();
        applicationContext.publishEvent(new PostHandleEvent<MethodOneBefore>(before));
        log.info("执行  -> MyServiceImpl.methodOne()");
        MethodOneAfter after = new MethodOneAfter();
        applicationContext.publishEvent(new PostHandleEvent<MethodOneAfter>(after));
    }

}



 

2.2、事件类及泛型实体

 

package com.demo.event;

import org.springframework.context.ApplicationEvent;

// 订阅一个事件类
public class PostHandleEvent<TEntity> extends ApplicationEvent {

    private TEntity event;

    public PostHandleEvent(Object source) {
        super(source);
        this.event = (TEntity) source;
    }

    public TEntity getEvent() {
        return this.event;
    }

}

 


package com.demo.entity;

import lombok.Data;
// 前置钩子泛型实体
@Data
public class MethodOneAfter {
    private String name = "my name is MethodOneAfter";
}



package com.demo.entity;

import lombok.Data;
// 后置钩子泛型实体
@Data
public class MethodOneBefore {
    private String name = "my name is MethodOneBefore";
}

 

2.3、使用钩子

 
先在项目的pom文件中,引入自定义 starter 包的 依赖

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

 
然后监听 ApplicationContext 发布的事件即可

package com.demo.handle;

import com.demo.entity.MethodOneAfter;
import com.demo.entity.MethodOneBefore;
import com.demo.event.PostHandleEvent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

@Slf4j
@Component
public class MyServiceHandle {

    @EventListener
    // @Async  不加这个注解就是同步的,默认同步。加上@Async代表异步执行
    public void methodOneBefore(PostHandleEvent<Object> postHandleEvent) {
        if (postHandleEvent.getEvent() instanceof MethodOneBefore) {
            MethodOneBefore methodOneBefore = (MethodOneBefore) postHandleEvent.getEvent();
            log.info("执行 -> PostHandleEvent.methodOneBefore, name = {}",
                    methodOneBefore.getName());
        } else if (postHandleEvent.getEvent() instanceof MethodOneAfter) {
            MethodOneAfter methodOneAfter = (MethodOneAfter) postHandleEvent.getEvent();
            log.info("执行 -> PostHandleEvent.methodOneAfter, name = {}",
                    methodOneAfter.getName());
        }

    }

}

 
调用 自定义 starter 中的 methodOne() 方法

package com.demo.controller;

import com.demo.server.MyService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;


@RestController
public class TestController {

    @Autowired
    private MyService myService;

    @GetMapping("/methodOne")
    public void methodOne() {
        myService.methodOne();

}

 
执行结果:

2023-09-10 19:01:35.455 MyServiceHandle - 执行 -> PostHandleEvent.methodOneBefore, name = my name is MethodOneBefore
2023-09-10 19:01:35.456 impl.MyServiceImpl - 执行  -> MyServiceImpl.methodOne()
2023-09-10 19:01:35.458 MyServiceHandle - 执行 -> PostHandleEvent.methodOneAfter, name = my name is MethodOneAfter

 

3、方法二:观察者模式 + ApplicationListener 实现

 
       这种方法,只需要在项目中,实现 MyServiceListener 接口,即可达到 调用钩子的效果。并且可以选择性的实现 钩子方法。需要注意的是,实现 MyServiceListener 接口的实现类需要添加 @Component 注解。
 

3.1、定义监听者接口类

 

package com.demo.listener;

// MyService类的监听类,用来实现监听者模式
public interface MyServiceListener {

    public default void methodTwoBefore(String name) {
    }

    public default void methodTwoAfter(String name) {
    }

}

 

3.2、MyService 的实现类

 

package com.demo.server.impl;

import com.demo.listener.MyServiceListener;
import com.demo.server.MyService;
import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.List;

@Slf4j
public class MyServiceImpl implements MyService {
    // 监听者集合
    private List<MyServiceListener> listeners = new ArrayList<>();
    // 添加监听者
    public void addListener(MyServiceListener myServiceListener) {
        this.listeners.add(myServiceListener);
    }

    @Override
    public void methodTwo() {
        String name = "my name is methodTwo()";
        methodTwoBefore(name);
        log.info("执行  -> MyServiceImpl.methodTwo()");
        methodTwoAfter(name);
    }

    /**
     * 通知所有观察者
     * @param name
     */
    public void methodTwoBefore(String name) {
        for (MyServiceListener myServiceListener : this.listeners) {
            myServiceListener.methodTwoBefore(name);
        }
    }

    /**
     * 通知所有观察者
     * @param name
     */
    public void methodTwoAfter(String name) {
        for (MyServiceListener myServiceListener : this.listeners) {
            myServiceListener.methodTwoAfter(name);
        }
    }

}

 

3.3、定义 ApplicationListener

 
       这里监听 ContextRefreshedEvent 节点,在服务启动的 ContextRefreshedEvent 节点,将所有 实现 MyServiceListener 接口的实现类,加到 MyServiceImpl 业务实现类。
 

package com.demo.listener;

import com.demo.server.impl.MyServiceImpl;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;

import java.util.Map;

public class MyListener implements ApplicationListener<ContextRefreshedEvent> {

    @Override
    public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
        ApplicationContext applicationContext = contextRefreshedEvent.getApplicationContext();
        // 获取 BeanFactory 实例
        ListableBeanFactory beanFactory = (ListableBeanFactory ) applicationContext.getAutowireCapableBeanFactory();
        // 获取接口 A 的所有实现类
        Map<String, MyServiceListener> beansOfType = beanFactory.getBeansOfType(MyServiceListener.class);
        MyServiceImpl myService = beanFactory.getBean(MyServiceImpl.class);
        // 遍历监听接口的实现类,将监听者放到MyService业务实现类中
        for (Map.Entry<String, MyServiceListener> entry : beansOfType.entrySet()) {
            myService.addListener(entry.getValue());
        }
    }

}

 

3.4、MyListener 加入 spring.factories 文件

 

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.demo.MyStarterConfig


org.springframework.context.ApplicationListener=\
com.demo.listener.MyListener

 

3.5、使用钩子

 
先在项目的pom文件中,引入自定义 starter 包的 依赖

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

 
然后实现 MyServiceListener 接口

package com.demo.listener;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

@Slf4j
@Component
public class MethodTwoListener implements MyServiceListener{

    // 这里可以选择性实现,因为接口方法是 default 
    @Override
    public void methodTwoBefore(String name) {
        log.info("执行 -> MethodTwoListener.methodTwoBefore  name = {}", name);
    }

    @Override
    public void methodTwoAfter(String name) {
        log.info("执行 -> MethodTwoListener.methodTwoAfter  name = {}", name);
    }
}

 
调用 自定义 starter 中的 methodTwo() 方法
 

package com.demo.controller;

import com.demo.server.MyService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;


@RestController
public class TestController {

    @Autowired
    private MyService myService;

    @GetMapping("/methodTwo")
    public void methodTwo() {
        myService.methodTwo();

}

 
执行结果:

2023-09-10 19:18:27.961 MethodTwoListener - 执行 -> MethodTwoListener.methodTwoBefore  name = my name is methodTwo()
2023-09-10 19:18:27.962 MyServiceImpl - 执行  -> MyServiceImpl.methodTwo()
2023-09-10 19:18:27.962 MethodTwoListener - 执行 -> MethodTwoListener.methodTwoAfter  name = my name is methodTwo()

 

 

 

 
 
 
 
.文章来源地址https://www.toymoban.com/news/detail-709116.html

到了这里,关于自定义 spring-boot-starter 暴露钩子的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 自定义 Spring Boot Starter 组件

    自定义 Spring Boot Starter 组件是为了封装和简化特定功能的配置和集成,让用户能够更容易地集成你提供的库或功能。Spring Boot Starter 组件通常包括自动配置、依赖管理和必要的配置。 下面是创建一个简单的 Spring Boot Starter 的基本步骤: 步骤: 创建一个新的 Maven 或 Gradle 项目

    2024年02月05日
    浏览(42)
  • Spring Boot应用集成Actuator组件以后怎么自定义端点暴露信息

    在平时业务开发中,我们往往会在spring Boot项目中集成Actuator组件进行系统监控,虽然Actuator组件暴露的端点信息已经足够丰富了,但是特殊场景下,我们也需要自己暴露端点信息,此时应该怎么操作呢? 1. 创建一个spring Boot项目,导入相关依赖 3. 暴露端点 注意: 自定义的端

    2024年02月21日
    浏览(36)
  • 深入理解Spring Boot Starter:概念、特点、场景、原理及自定义starter

    在Spring框架的发展过程中,为了简化项目的搭建和配置过程,Spring Boot应运而生。Spring Boot通过提供一系列开箱即用的Starter,使得开发者能够快速整合Spring生态系统中的各种技术栈,提升开发效率。本文将深入探讨Spring Boot Starter的基本概念、主要特点、应用场景以及实现原理

    2024年02月22日
    浏览(45)
  • spring boot学习之自定义starter启动器

    starter启动器的目标 引入maven包即可自动装配配置,个人理解,如jdbc引入即可操作数据库 实现 1新建springboot工程编写实现类 2编写配置类 3配置 4打包 4新建工程引入使用

    2024年02月13日
    浏览(54)
  • 如何优雅地创建一个自定义的Spring Boot Starter

    优雅永不过时,希望看完本文,你会觉得starter如此优雅! Spring Boot Starter是一种简化Spring Boot应用开发的机制,它可以通过引入一些预定义的依赖和配置,让我们快速地集成某些功能模块,而无需繁琐地编写代码和配置文件。Spring Boot官方提供了很多常用的Starter,例如 spring

    2024年02月11日
    浏览(57)
  • 自定义redission装配和集成分布式开源限流业务组件ratelimiter-spring-boot-starter的正确姿势

    自定义redission装配和集成分布式开源限流业务组件ratelimiter-spring-boot-starter的正确姿势   由于使用了redisson-spring-boot-starter,在自定义redisson装配的时候会被redisson-spring-boot-starter里面的start默认装配了,同时在使用开源分布式限流组件ratelimiter-spring-boot-starter的时候,这个里面

    2024年02月07日
    浏览(52)
  • Spring Boot Starters

    Spring Boot Starters 概述 Spring Boot Starters是一系列为特定应用场景预设的依赖管理和自动配置方案。每个Starter都是为了简化特定类型的项目构建和配置。例如, spring-boot-starter-web 是为创建基于Spring MVC的Web应用程序而设计的。 Starter的结构 一个典型的Starter包含以下部分: pom.xml

    2024年01月25日
    浏览(38)
  • shiro-spring-boot-starter针对不同Spring Boot版本

    对于Spring Boot 2.4.10,无法找到shiro-spring-boot-starter的2.7.2版本,这是一个错误的版本号。 shiro-spring-boot-starter针对不同Spring Boot版本,推荐使用的版本如下: Spring Boot 1.x - 使用版本1.4.1 Spring Boot 2.0.x - 使用版本1.5.3 Spring Boot 2.1.x - 使用版本1.6.0 Spring Boot 2.2.x - 使用版本1.7.0 Spring Boot 2.3

    2024年02月13日
    浏览(40)
  • Spring Boot Starter设计实现

    Starter 是 Spring Boot 非常重要的一个硬核功能。 通过 Starter 我们可以快速的引入一个功能或模块,而无须关心模块依赖的其它组件。关于配置,Spring Boot 采用“约定大于配置”的设计理念,Starter 一般都会提供默认配置,只有当我们有特殊需求的时候,才需要在 application.yaml 里

    2024年01月18日
    浏览(47)
  • 6. Spring Boot的starters

    6. Spring Boot的starters(重要) 一般认为,SpringBoot 微框架从两个主要层面影响 Spring 社区的开发者们: 基于 Spring 框架的“约定优先于配置(COC)”理念以及最佳实践之路。 提供了针对日常企业应用研发各种场景的 spring-boot-starter 自动配置依赖模块,如此多“开箱即用”的依赖模

    2024年01月24日
    浏览(43)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包