如果你比较熟悉JavaWeb应用开发,那么对Spring框架一定不陌生,并且JavaWeb通常是基于SSM搭起的架构,主要用Java语言开发。但是开发Spark程序,Scala语言往往必不可少。

众所周知,Scala如同Java一样,都是运行在JVM上的,所以它具有很多Java语言的特性,同时作为函数式编程语言,又具有自己独特的特性,实际应用中除了要结合业务场景,还要对Scala语言的特性有深入了解。

如果想像使用Java语言一样,使用Scala来利用Spring框架特性、并结合Spark来处理离线数据,应该怎么做呢?

本篇文章,通过详细的示例代码,介绍上述场景的具体实现,大家如果有类似需求,可以根据实际情况做调整。

1. 定义一个程序启动入口

object Bootstrap {
private val log = LoggerFactory.getLogger(Bootstrap.getClass) //指定配置文件如log4j的路径
val ConfFileName = "conf"
val ConfigurePath = new File("").getAbsolutePath.substring(0, if (new File("").getAbsolutePath.lastIndexOf("lib") == -1) 0
else new File("").getAbsolutePath.lastIndexOf("lib")) + this.ConfFileName + File.separator //存放实现了StatsTask的离线程序处理的类
private val TASK_MAP = Map("WordCount" -> classOf[WordCount]) def main(args: Array[String]): Unit = {
//传入一些参数,比如要运行的离线处理程序类名、处理哪些时间的数据
if (args.length < 1) {
log.warn("args 参数异常!!!" + args.toBuffer)
System.exit(1)
}
init(args)
} def init(args: Array[String]) {
try {
SpringUtils.init(Array[String]("applicationContext.xml"))
initLog4j() val className = args(0)
// 实例化离线处理类
val task = SpringUtils.getBean(TASK_MAP(className)) args.length match {
case 3 =>
// 处理一段时间的每天离线数据
val dtStart = DateTimeFormat.forPattern("yyyy-MM-dd").parseDateTime(args(1))
val dtEnd = DateTimeFormat.forPattern("yyyy-MM-dd").parseDateTime(args(2))
val days = Days.daysBetween(dtStart, dtEnd).getDays + 1
for (i <- 0 until days) {
val etime = dtStart.plusDays(i).toString("yyyy-MM-dd")
task.runTask(etime) log.info(s"JOB --> $className 已成功处理: $etime 的数据")
} case 2 =>
// 处理指定的某天离线数据
val etime = DateTimeFormat.forPattern("yyyy-MM-dd").parseDateTime(args(1)).toString("yyyy-MM-dd")
task.runTask(etime)
log.info(s"JOB --> $className 已成功处理: $etime 的数据") case 1 =>
// 处理前一天离线数据
val etime = DateTime.now().minusDays(1).toString("yyyy-MM-dd")
task.runTask(etime)
log.info(s"JOB --> $className 已成功处理: $etime 的数据") case _ => println("执行失败 args参数:" + args.toBuffer)
}
} catch {
case e: Exception =>
println("执行失败 args参数:" + args.toBuffer)
e.printStackTrace()
} // 初始化log4j
def initLog4j() {
val fileName = ConfigurePath + "log4j.properties"
if (new File(fileName).exists) {
PropertyConfigurator.configure(fileName)
log.info("日志log4j已经启动")
}
}
}
}

2. 加载Spring配置文件工具类

object SpringUtils {
private var context: ClassPathXmlApplicationContext = _ def getBean(name: String): Any = context.getBean(name) def getBean[T](name: String, classObj: Class[T]): T = context.getBean(name, classObj) def getBean[T](_class: Class[T]): T = context.getBean(_class) def init(springXml: Array[String]): Unit = {
if (springXml == null || springXml.isEmpty) {
try
throw new Exception("springXml 不可为空")
catch {
case e: Exception => e.printStackTrace()
}
}
context = new ClassPathXmlApplicationContext(springXml(0))
context.start()
} }

3. Spring配置文件applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd"> <!-- 配置包扫描 -->
<context:component-scan base-package="com.bigdata.stats"/> </beans>

4. 定义一个trait,作为离线程序的公共"父类"

trait StatsTask extends Serializable {
//"子类"继承StatsTask重写该方法实现自己的业务处理逻辑
def runTask(etime: String)
}

5. 继承StatsTask的离线处理类

//不要忘记添加 @Component ,否则无法利用Spring对WordCount进行实例化
@Component
class WordCount extends StatsTask { override def runTask(etime: String): Unit = {
val sparkSession = SparkSession
.builder()
.appName("test")
.master("local[*]")
.getOrCreate() import sparkSession.implicits._ val words = sparkSession.read.textFile("/Users/BigData/Documents/data/wordcount.txt").flatMap(_.split(" "))
.toDF("word") words.createOrReplaceTempView("wordcount") val df = sparkSession.sql("select word, count(*) count from wordcount group by word") df.show()
}
}

推荐文章:

Spark流式状态管理

Spark实现推荐系统中的相似度算法

Scala中的IO操作及ArrayBuffer线程安全问题

学好Spark必须要掌握的Scala技术点


关注微信公众号:大数据学习与分享,获取更对技术干货

Spark和Spring整合处理离线数据的更多相关文章

  1. idea+springmvc+spring+mybatis+maven整合返回json数据webapi

    首先看一张目录结构图: : 创建步骤: 1.创建maven  webapp工程, 创建完后的目录结构为: 2.添加项目依赖(添加jar包) 需要的jar包: spring-webmvc, spring ...

  2. 项目一:第十四天 1.在realm中动态授权 2.Shiro整合ehcache 缓存realm中授权信息 3.动态展示菜单数据 4.Quartz定时任务调度框架—Spring整合javamail发送邮件 5.基于poi实现分区导出

    1 Shiro整合ehCache缓存授权信息 当需要进行权限校验时候:四种方式url拦截.注解.页面标签.代码级别,当需要验证权限会调用realm中的授权方法   Shiro框架内部整合好缓存管理器, ...

  3. 使用Spring整合Hibernate,并实现对数据表的增、删、改、查的功能

    1.1 问题 使用Spring整合Hibernate,并实现资费表的增.删.改.查. 1.2 方案 Spring整合Hibernate的步骤: 1.3 步骤 实现此案例需要按照如下步骤进行. 采用的环 ...

  4. spring整合flex

    在常规的开发中只是用flex二不和后台交互是不可能的,为此flex也提供了和后台交互的2种解决方案一种是Data Services另一种是BlazeDs,本篇博客是用的是后一种,我的开发步骤如下: 1 ...

  5. java框架之Spring(4)-Spring整合Hibernate和Struts2

    准备 导包 Struts2 导入 Struts2 zip 包解压目录下 'apps/struts-blank.war' 中所有 jar 包,如下: asm-3.3.jar asm-commons-3. ...

  6. Spark与Spring集成做web接口

    需要实现的功能: 写访问spark的接口,也就是从web上输入网址就能把我们需要的信息通过提交一个job然后返回给我们json数据. 成果展示: 通过url请求,然后的到一个wordcount的jso ...

  7. hadoop离线数据存储和挖掘架构

    前序: 当你把你知道的东西,写下来,让人看明白是一种境界:当你能把自己写下来的东西给人讲明白,又是另一种境界.在这个过程中,我们都需要历练. 基于hadoop集群下海量离线数据存储和挖掘分析架构: 架 ...

  8. Spring整合Ehcache管理缓存

    前言 Ehcache 是一个成熟的缓存框架,你可以直接使用它来管理你的缓存. Spring 提供了对缓存功能的抽象:即允许绑定不同的缓存解决方案(如Ehcache),但本身不直接提供缓存功能的实现.它 ...

  9. spring整合hibernate

    spring整合hibernate包括三部分:hibernate的配置.hibernate核心对象交给spring管理.事务由AOP控制 好处: 由java代码进行配置,摆脱硬编码,连接数据库等信息更 ...

随机推荐

  1. PHP-数组相关知识总结

    PHP-数组相关知识总结 (一)数组创建 //创建数组(php5.4 起可以使用短数组定义语法,用 [] 替代 array()) <?php$array = array(    "fo ...

  2. C++ 标准模板库(STL):map

    目录 4. map 4.1 map的定义 4.2 map容器内元素的访问 4.3 map常用函数实例解析 4.4 map的常见用途 4. map map翻译为映射,也是常用的STL容器. 在定义数组时 ...

  3. jvm学习第二天

    0.垃圾回收概述 1.什么是垃圾,怎么判断? 1.1引用计数法 含义 顾名思义,此种算法会在每一个对象上记录这个对象被引用的次数,只要有任何一个对象引用了此对象,这个对象的计数器就+1,取消对这个对象 ...

  4. P3381 [模板] 最小费用最大流

    EK  + dijkstra (2246ms) 开氧气(586ms) dijkstra的势 可以处理负权 https://www.luogu.org/blog/28007/solution-p3381 ...

  5. 【noi 2.2_7891】一元三次方程求解(二分枚举+输出程序运行时间)

    对于noi上的题有2种解法: 1.数据很小(N=100),可以直接打for循环枚举和判断. 2.不会"三分",便用二分.利用"两根相差>=1"和 f(x1 ...

  6. Codeforces Round #603 C. Everyone is a Winner!

    题意:给你一个整数n,求所有n/k的值(k∈{1,2,3...,n,.......}). 题解:最简单的方法是用枚举1~sqrt(n),把除数和商放进set中,就能直接水过,但后来看其他人的题解了解到 ...

  7. Base64 编码原理

    什么是 Base64 编码 Base64 编码是最常见的编码方式,基于 64 个可打印字符来表示任意二进制数据的方法,是从二进制转换到可见字符的过程. 使用场景 数据加密或签名通过 Base64 转换 ...

  8. Ubuntu——常用命令

    一.进入文件夹 1.cd .. # 进入上一个文件夹 2.cd ../.. # 进入上两个文件夹 3.cd - # 去到进入当前文件夹之前的那个文件夹 二.复制文件 cp 目标文件 复制文件名 三.移 ...

  9. CGI & FastCGI 协议

    目录 CGI 是什么 CGI 特点 CGI 的流程 FastCGI 是什么 CGI & FastCGI(转载) 推荐Blog: CGI是什么,FastCGI是什么 CGI 是什么 公共网关接口 ...

  10. Linux-单用户/救援模式

    目录 企业案例一:忘记root密码 企业案例二:修改了默认的运行级别为poweroff或者reboot 企业案例三:误损坏MBR(只能以救援模式解决) 企业案例四:误删除GRUB菜单(只能以救援模式解 ...