在Scala项目中使用Spring Cloud
由于Scala本身属于JVM下的语言,因此它能够较好地与Java项目融合在一起。在Scala中调用Java库,基本上与在Java中调用Java库的方式是相同的(反过来则未必,必将Java没有Scala中独有的语法糖)。因此,在Scala中可以非常方便地调用Spring Cloud,使其支持Spring Cloud提供的微服务基础设施,例如Eureka、Feign以及Spring Boot等。
不过仍然有几点需要注意,这些方面包括:
- Maven依赖
- Spring的语法
- Json的序列化
Maven依赖
在Scala项目中,如果仍然使用Maven管理依赖,则它与在Java项目中添加Spring Boot依赖几乎完全相同,不同在于项目要支持Scala,需要添加对Scala语言库的依赖:
<dependency>
<groupId>org.scala-lang</groupId>
<artifactId>scala-library</artifactId>
<version>2.11.11</version>
</dependency>
要支持用ScalaTest编写单元测试,则还需要添加:
<dependency>
<groupId>org.scalatest</groupId>
<artifactId>scalatest_2.11</artifactId>
<version>3.0.4</version>
<scope>test</scope>
</dependency>
同时,添加对编译Scala代码的插件依赖:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>1.10</version>
<executions>
<execution>
<id>add-source</id>
<phase>generate-sources</phase>
<goals>
<goal>add-source</goal>
</goals>
<configuration>
<sources>
<source>src/main/scala</source>
</sources>
</configuration>
</execution>
<execution>
<id>add-test-source</id>
<phase>generate-test-sources</phase>
<goals>
<goal>add-test-source</goal>
</goals>
<configuration>
<sources>
<source>src/test/scala</source>
</sources>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>net.alchim31.maven</groupId>
<artifactId>scala-maven-plugin</artifactId>
<version>3.2.2</version>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>testCompile</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
Spring的语法
Scala语言中照样可以使用Java的Annotation,因此scala项目的Application,可以这样实现:
@SpringBootApplication
@EnableDiscoveryClient
class SqlEngineApplication
object SqlEngineApplication extends App {
SpringApplication.run(classOf[SqlEngineApplication], args: _*)
}
注意,Spring Cloud以及Spring Boot提供的annotation是运用在类上面的,而Scala可以运用的Application则可以直接定义为与类同名的object。
而对于Spring Boot的Controller,在语法上有少许差异,即在值中要使用Scala的Array
类型,例如
@RestController
@RequestMapping(Array("/"))
class SqlStatementController extends SqlGenerator {
@RequestMapping(value = Array("/sql"), method = Array(GET))
def getSql:String = ???
@RequestMapping(value = Array("/sql"), method = Array(POST))
def generateSql(@RequestBody request: GenerateSqlRequest): String = ???
}
Json的序列化
添加依赖
Spring Boot使用Jackson作为Json的序列化支持,若要在Scala项目也要使用Jackson,则需要添加jackson对scala的支持模块:
<dependency>
<groupId>com.fasterxml.jackson.module</groupId>
<artifactId>jackson-module-scala_2.11</artifactId>
<version>2.8.7</version>
</dependency>
添加WebConfig
同时还需要添加WebConfig,告诉Spring Boot选择Scala Module对对象进行映射:
@Configuration
class WebConfig extends WebMvcConfigurerAdapter {
override def configureMessageConverters(converters: java.util.List[HttpMessageConverter[_]]): Unit =
converters.add(jackson2HttpMessageConverter())
@Bean
def jackson2HttpMessageConverter(): MappingJackson2HttpMessageConverter =
new MappingJackson2HttpMessageConverter(objectMapper())
@Bean
def objectMapper(): ObjectMapper =
new ObjectMapper() {
setVisibility(PropertyAccessor.FIELD, Visibility.ANY)
registerModule(DefaultScalaModule)
}
}
对多态的支持
客户端发过来的Request中,包含了一棵表达式树。这棵树的节点分为两种类型:
- Condition Group
- Condition
Condition Group作为根节点,可以递归嵌套Condition Group和Condition,如下图所示:
在Scala中的定义如下所示:
case class GenerateSqlRequest(sqlTemplateName: String, criteria: Option[ConditionGroup] = None, groupBy: List[GroupByField] = Nil)
abstract class ConditionExpression {
def evaluate: String
}
case class ConditionGroup(logicOperator: String, conditions: List[ConditionExpression]) extends ConditionExpression
case class Condition(fieldName: String, operator: String, values: List[String], dataType: String) extends ConditionExpression
GenerateSqlRequest
中包含的criteria属性的类型就是前面提及的表达式树,它对应的Json结构需要支持Json类型的多态,即前面代码所示的ConditionExpression
抽象类型,子类ConditionGroup
与Condition
拥有不同的属性定义。要支持这种Json的多态,则必须在抽象类型ConditionExpression
上添加如下annotation:
@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.PROPERTY,
property = "type")
@JsonSubTypes(Array(
new Type(value = classOf[Condition], name = "condition"),
new Type(value = classOf[ConditionGroup], name = "group")
))
abstract class ConditionExpression {
def evaluate: String
}
即使ConditionGroup
与Condition
子类没有定义type属性,在对应的Json结构中也需要添加type,并给出符合上述代码定义的值:
{
"sqlTemplateName": "name1",
"criteria": {
"type": "group",
"logicOperator": "and",
"conditions": [
{
"type": "condition",
"fieldName": "sales",
"operator": "between",
"values": ["3", "100"],
"dataType": "Integer"
},
{
"type": "group",
"logicOperator": "or",
"conditions": [
{
"type": "condition",
"fieldName": "brand",
"operator": "=",
"values": ["apple"],
"dataType": "String"
},
{
"type": "condition",
"fieldName": "location",
"operator": "in",
"values": ["Sichuan", "Shanghai"],
"dataType": "String"
}
]
}
]
},
"groupBy": [
{
"fieldName": "location"
},
{
"fieldName": "brand"
}
]
}
注意,这种对多态的支持不仅仅是针对Scala,同样支持Java:
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY)
@JsonSubTypes({
@JsonSubTypes.Type(value = Condition.class, name = "condition"),
@JsonSubTypes.Type(value = ConditionGroup.class, name = "group") }
)
public abstract class ConditionExpression {}
一旦在Scala项目中使用了Spring Boot以及Spring Cloud,在编译打包后,使用方式和普通Java项目结合Spring Boot与Spring Cloud是完全一样的,毕竟scala编译后生成的就是一个不同的Jar包。
- React、Vue、Ember 及其他前端开发者,请暂缓更新到 Chrome 59 浏览器
- 微软开源全新的文档生成工具DocFX
- 使用 MimeKit 和 MailKit 发送邮件
- 使用 React Native 重写大型 Ionic 应用后,我们想分享一下这八个经验
- 基于OWin的Web服务器Katana发布版本3
- 【工具推荐】图像界的魔术师 ImageMagick
- 使用Metrics.NET 构建 ASP.NET MVC 应用程序的性能指标
- 如何设计完善的构建系统,为日常开发提速一倍
- 两年 100 期技术周报后,我收获了这四点
- 如何为技术博客设计一个推荐系统(中):基于 Google 搜索的半自动推荐
- 我是如何为技术博客设计一个推荐系统(上):统计与评分加权
- c#处理空白字符
- 后台优化:使用应用性能管理工具
- Disruptor-NET和内存栅栏
- java教程
- Java快速入门
- Java 开发环境配置
- Java基本语法
- Java 对象和类
- Java 基本数据类型
- Java 变量类型
- Java 修饰符
- Java 运算符
- Java 循环结构
- Java 分支结构
- Java Number类
- Java Character类
- Java String类
- Java StringBuffer和StringBuilder类
- Java 数组
- Java 日期时间
- Java 正则表达式
- Java 方法
- Java 流(Stream)、文件(File)和IO
- Java 异常处理
- Java 继承
- Java 重写(Override)与重载(Overload)
- Java 多态
- Java 抽象类
- Java 封装
- Java 接口
- Java 包(package)
- Java 数据结构
- Java 集合框架
- Java 泛型
- Java 序列化
- Java 网络编程
- Java 发送邮件
- Java 多线程编程
- Java Applet基础
- Java 文档注释
- 算法和数据结构: 二 基本排序算法
- 非中间人就没法劫持TCP了吗?
- HW在即——红队活动之Lnk样本载荷篇
- 用正则表达式修改html字符串的所有div的style样式
- 深入理解 WebSecurityConfigurerAdapter【源码篇】
- 算法和数据结构: 十二 无向图相关算法基础
- 算法和数据结构: 十一 哈希表
- 【DB笔试面试849】在Oracle中,在没有配置ORACLE_HOME环境变量的情况下,如何获取ORACLE_HOME目录?
- 算法和数据结构: 九 平衡查找树之红黑树
- 算法和数据结构: 七 二叉查找树
- Python 面向对象编程(下篇)
- 算法和数据结构: 符号表及其基本实现
- 算法和数据结构:堆排序
- mysql 优化海量数据插入和查询性能
- 聊聊dubbo-go的DubboPackage