自定义 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日
    浏览(44)
  • Spring Boot应用集成Actuator组件以后怎么自定义端点暴露信息

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

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

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

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

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

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

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

    2024年02月11日
    浏览(59)
  • 自定义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日
    浏览(55)
  • Spring Boot Starters

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

    2024年01月25日
    浏览(39)
  • 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日
    浏览(44)
  • Spring Boot Starter设计实现

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

    2024年01月18日
    浏览(48)
  • Spring Boot Starter Parent

    在这,您将学习了解 Spring Boot Starter Parent, 它是 Spring Boot 提供的父级 Pom 文件,旨在提供自动版本依赖管理,帮助我们轻松快速地进行 Spring Boot 开发。 通过 Spring Boot Starter Parent, 我们可以进行简单便捷地包依赖管理。在 Spring Boot 每一个发行版中, 均提供了该版本所兼容的依

    2024年02月08日
    浏览(38)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包