springboot整合quartz框架_Storm框架:Storm整合springboot

我们知道Storm本身是一个独立运行的分布式流式数据处理框架,Springboot也是一个独立运行的web框架。那么如何在Strom框架中集成Springboot使得我们能够在Storm开发中运用Spring的Ioc容器及其他如Spring Jpa等功能呢?我们先来了解以下概念:

  • Storm主要的三个Component:Topology、Spout、Bolt。Topology作为主进程控制着spout、bolt线程的运行,他们相当于独立运行的容器分布于storm集群中的各个机器节点。
  • SpringApplication:是配置Spring应用上下文的起点。通过调用SpringApplication.run()方法它将创建ApplicationContext实例,这是我们能够使用Ioc容器的主要BeanFactory。之后Spring将会加载所有单例模式的beans,并启动后台运行的CommandLineRunner beans等。
  • ApplicationContextAware:这是我们能够在普通Java类中调用Spring容器里的beans的关键接口。
0c5ea2bb03904effe8934a867e6bcebd.png

实现原理

如果想学习Java工程化、高性能及分布式、深入浅出。微服务、Spring,MyBatis,Netty源码分析的朋友可以加我的Java高级交流:854630135,群里有阿里大牛直播讲解技术,以及Java大型互联网技术的视频免费分享给大家。

Storm框架中的每个Spout和Bolt都相当于独立的应用,Strom在启动spout和bolt时提供了一个open方法(spout)和prepare方法(bolt)。我们可以把初始化Spring应用的操作放在这里,这样可以保证每个spout/bolt应用在后续执行过程中都能获取到Spring的ApplicationContext,有了ApplicationContext实例对象,Spring的所有功能就都能用上了。

  • Spout.open方法实现
@Overridepublic void open(Map map, TopologyContext topologyContext, SpoutOutputCollector spoutOutputCollector) { //启动Springboot应用 SpringStormApplication.run(); this.map = map; this.topologyContext = topologyContext; this.spoutOutputCollector = spoutOutputCollector;}
  • Bolt.prepare方法实现
@Overridepublic void prepare(Map map, TopologyContext topologyContext, OutputCollector outputCollector) { //启动Springboot应用 SpringStormApplication.run(); this.map = map; this.topologyContext = topologyContext; this.outputCollector = outputCollector;}
  • SpringStormApplication启动类
@SpringBootApplication@ComponentScan(value = "com.xxx.storm")public class SpringStormApplication { /** * 非工程启动入口,所以不用main方法 * 加上synchronized的作用是由于storm在启动多个bolt线程实例时,如果Springboot用到Apollo分布式配置,会报ConcurrentModificationException错误 * 详见:https://github.com/ctripcorp/apollo/issues/1658 * @param args */ public synchronized static void run(String ...args) { SpringApplication app = new SpringApplication(SpringStormApplication.class); //我们并不需要web servlet功能,所以设置为WebApplicationType.NONE app.setWebApplicationType(WebApplicationType.NONE); //忽略掉banner输出 app.setBannerMode(Banner.Mode.OFF); //忽略Spring启动信息日志 app.setLogStartupInfo(false); app.run(args); }}

与我们传统的Springboot应用启动入口稍微有点区别,主要禁用了web功能,看下正常的启动方式:

@SpringBootApplication@ComponentScan(value = "com.xxx.web")public class PlatformApplication { public static void main(String[] args) { SpringApplication.run(PlatformApplication.class, args); }}
  • 在spout/bolt中调用了SpringStormApplication.run方法后,我们还需要能够拿到ApplicationContext容器对象,这时候我们还需要实现ApplicationContextAware接口,写个工具类BeanUtils:
@Componentpublic class BeanUtils implements ApplicationContextAware { private static ApplicationContext applicationContext = null; @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { if (BeanUtils.applicationContext == null) { BeanUtils.applicationContext = applicationContext; } }  public static ApplicationContext getApplicationContext() { return applicationContext; }  public static Object getBean(String name) { return getApplicationContext().getBean(name); }  public static  T getBean(Class clazz) { return getApplicationContext().getBean(clazz); }  public static  T getBean(String name, Class clazz) { return getApplicationContext().getBean(name, clazz); }}

通过@Component注解使得Spring在启动时能够扫描到该bean,因为BeanUtils实现了ApplicationContextAware接口,Spring会在启动成功时自动调用BeanUtils.setApplicationContext方法,将ApplicationContext对象保存到工具类的静态变量中,之后我们就可以使用BeanUtils.getBean()去获取Spring容器中的bean了。

写个简单例子

  • 在FilterBolt的execute方法中获取Spring bean
@Overridepublic void execute(Tuple tuple) { FilterService filterService = (FilterService) BeanUtils.getBean("filterService"); filterService.deleteAll();}
  • 定义FilterService类,这时候我们就可以使用Spring的相关注解,自动注入,Spring Jpa等功能了。
@Service("filterService")public class FilterService { @Autowired UserRepository userRepository;  public void deleteAll() { userRepository.deleteAll(); }}

将storm应用作为Springboot工程的一个子模块

工程主目录的pom文件还是springboot相关的依赖,在storm子模块中引入storm依赖,这时候启动Strom的topology应用会有一个日志包依赖冲突。

SLF4J: Class path contains multiple SLF4J bindings.SLF4J: Found binding in [jar:file:/Applications/IntelliJ%20IDEA.app/Contents/bin/~/.m2/repository/org/apache/logging/log4j/log4j-slf4j-impl/2.11.1/log4j-slf4j-impl-2.11.1.jar!/org/slf4j/impl/StaticLoggerBinder.class]SLF4J: Found binding in [jar:file:/Applications/IntelliJ%20IDEA.app/Contents/bin/~/.m2/repository/ch/qos/logback/logback-classic/1.2.3/logback-classic-1.2.3.jar!/org/slf4j/impl/StaticLoggerBinder.class]SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.SLF4J: Actual binding is of type [org.apache.logging.slf4j.Log4jLoggerFactory]

我们需要在storm子模块的pom文件中重写org.springframework.boot:spring-boot-starter包依赖,将Springboot的相关日志包排除掉,如下:

org.springframework.boot spring-boot-starter org.apache.logging.log4j log4j-to-slf4j2 ch.qos.logback logback-classic2 

使用maven-shade-plugin打包注意的问题

因为springboot有自己的打包插件,如果使用maven-shade-plugin需要将spring-boot-maven-plugin作为依赖引入,另外spring-boot-starter-parent需要使用dependencyManagement引入。

parent部分替换如下:

org.springframework.boot spring-boot-dependencies 2.1.0.RELEASEpomimport

build如下:

org.apache.maven.plugins maven-compiler-plugin 3.8.0UTF-81.81.8org.apache.maven.plugins maven-jar-plugin 2.6 true lib/com.xxx.storm.pointer.XdPointerTopologyorg.apache.maven.plugins maven-shade-plugin 3.1.1org.springframework.boot spring-boot-maven-plugin 2.1.0.RELEASEtruetrue *:* META-INF/*.SFMETA-INF/*.DSAMETA-INF/*.RSAcom.xxx.storm:xxx-stormorg.slf4j:slf4j-apijavax.mail:javax.mail-apiorg.apache.storm:storm-coreorg.apache.storm:storm-kafkaorg.apache.logging.log4j:log4j-slf4j-implpackageshadeMETA-INF/spring.handlersMETA-INF/spring.factoriesMETA-INF/spring.schemascom.xxx.storm.pointer.XdPointerTopology

注意:META-INF/spring.* 文件不需要我们创建,这是springboot包内部的文件,这里只是需要显示的引入进来。

欢迎工作一到八年的Java工程师朋友们加入Java高级交流:854630135

本群提供免费的学习指导 架构资料 以及免费的解答

不懂得问题都可以在本群提出来 之后还会有直播平台和讲师直接交流噢

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值