在Scala项目中使用Spring Cloud
Posted 逸言
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在Scala项目中使用Spring Cloud相关的知识,希望对你有一定的参考价值。
标签 | Scala 微服务
作者 | 张逸
特别说明:本文包含大量代码片段,若要获得更好阅读观感,请点击文末“阅读原文”或访问我的博客。
由于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语言库的依赖:
1 2 3 4 5
|
<dependency> <groupId>org.scala-lang</groupId> <artifactId>scala-library</artifactId> <version>2.11.11</version> </dependency>
|
要支持用ScalaTest编写单元测试,则还需要添加:
1 2 3 4 5 6
|
<dependency> <groupId>org.scalatest</groupId> <artifactId>scalatest_2.11</artifactId> <version>3.0.4</version> <scope>test</scope> </dependency>
|
同时,添加对编译Scala代码的插件依赖:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
|
<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,可以这样实现:
1 2 3 4 5 6 7
|
@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
类型,例如:
1 2 3 4 5 6 7 8 9
|
@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的支持模块:
1 2 3 4 5
|
<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对对象进行映射:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
|
@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中的定义如下所示:
1 2 3 4 5 6 7 8 9
|
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:
1 2 3 4 5 6 7 8 9 10 11
|
@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,并给出符合上述代码定义的值:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
|
{ "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:
1 2 3 4 5 6 7 8 9 10 11
|
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包。
以上是关于在Scala项目中使用Spring Cloud的主要内容,如果未能解决你的问题,请参考以下文章
传统Java Web(非Spring Boot)非Java语言项目接入Spring Cloud方案
在 Golang 项目中使用 Spring Cloud Config Server 管理配置
我们如何在 Spring MVC 项目中使用 Spring Cloud Sleuth?
Spring Cloud学习之-什么是Spring Cloud?
Spring-cloud微服务实战:eureka注册中心(中)
Spring Cloud Zuul 综合使用