分类: Spring

  • 新版Spring Boot项目创建工具

    新版Spring Boot项目创建工具

    Spring Initializr是一个非常实用的工具,从工具创建的项目可以快速启动,非常适合新手上手或者新建大量项目的时候。但是有时候可能会遇到一些问题,比如一些特定情况需要手动创建项目,但是创建以后运行不起来,这个时候就需要参考一下。

    新版的Spring Initializr提供了预览功能,即选择了版本,功能等以后不需要下载ZIP包然后解压查看,可以直接在线预览,排查问题。

  • Spring Rest文档生成

    写文档这个事情绝对是软件开发中最纠结的时候了,大部分时候你首先考虑的项目交付,但是从长远来看,一份文档,可以减少很多问题。

    Spring提供了一个Rest doc扩展,可以从单元测试中读取一些一些信息并生成文档。

    @Before
    public void setUp() {
    	this.mockMvc = MockMvcBuilders.webAppContextSetup(this.context)
    			.apply(documentationConfiguration(this.restDocumentation)) 
    			.build();
    }

    首先配置上需要应用文档生成器,这个是一行代码的时候,无所谓。

    但是对于文档的内容,你其实需要从代码中注明,比如

    this.mockMvc.perform(get("/user/5").accept(MediaType.APPLICATION_JSON))
    		.andExpect(status().isOk())
    		.andDo(document("index",
    				responseFields( 
    						subsectionWithPath("contact")
    								.description("The user's contact details"))));

    andDo之后的和测试本身并无关联,只是为了文档生成。

    这个方案在我看来无非就是把文档写到了代码中,并没有根据测试的期待输入和期待输出直接生成文档。

    ScaCap的Auto-Restdocs项目是我目前找到的比较好的解决方案,它除了要求andDo之后表明文档名称以外不强制要求别的信息。

    它会从请求的字段中,还有请求的POJO中抽取字段和验证信息,文档本身还是使用的Spring Rest Docs的模板和样式。

    参考

    https://projects.spring.io/spring-restdocs/

    https://github.com/ScaCap/spring-auto-restdocs

    https://www.slideshare.net/fbenz/introducing-spring-auto-rest-docs…

  • 在Openshift Origin 3上运行Spring Boot应用

    在Openshift Origin 3上运行Spring Boot应用

    Openshift Origin是开源的PAAS平台,如果只是为了单机体验,还可以使用minishift。

    我之前使用过Openshift 2, 还在上面运行了一些Spring Boot应用。最近又要开始接触Openshift新版本,所以想着用这个练练手,先迁移旧应用过来一下。

    在Openshift 2时代,我们需要处理cartridge,它定义了一些基本的东西,比如Tomcat,Cron任务等等,如果你需要的不在这之中,还可以使用Diy。也就是说你需要在代码库中提供action hooks,包括start和stop。我当时是自定义了这两个脚本,然后运行了spring boot应用。

    然后到了Openshift Origin 3,我发现我找不到名为Diy的模板了。一番研究才发现居然没有 cartridge,改成images了。当然原因有很多,官方也给出了一篇详细的说明,但是我并不是很关心,我只想知道怎么迁移。

    为了方便的从源代码生成Docker用镜像,Openshift Origin 3使用了s2i,大致原理如下:

    1. 将源代码注入构建用镜像中
    2. 必要的构建步骤
    3. 将构建结果提交并设置启动入口

    我们用Spring Boot应用来举个例子,大概步骤如下:

    1. 将源代码注入构件用镜像,该镜像包含Java(也可以包含Maven和Gradle,我自建了一个包含不同版本的Maven Wrapper和Gradle Wrapper的镜像)
    2. 运行构建脚本生成jar包
    3. 将jar包提交并设置入口为java -jar <jar path> <other args>

    对于具体的脚本名称,s2i又有如下约定

    1. assemble 构建打包
    2. run 运行应用
    3. save-artifacts 提交构建物
    4. usage 使用说明
  • Spring Cloud Function简化函数式编程的开发和部署

    Spring Cloud Function是基于Spring Boot的函数框架,它提供了很大程度上的抽象除了函数编程本身之外的东西,如果你的业务逻辑由多个独立函数提供,那么就可以使用Spring Cloud Function。

    这个是官方的例子

    @SpringBootApplication
    public class Application {

    @Bean
    public Function<Flux<String>, Flux<String>> uppercase() {
    return flux -> flux.map(value -> value.toUpperCase());
    }

    public static void main(String[] args) {
    SpringApplication.run(Application.class, args);
    }
    }

    其中的Function uppercase使我们暴露的函数,默认会直接暴露一个路径为uppercase的API。

    因为Spring Cloud Function是Spring …

  • Spring Boot项目生成器支持Kotlin

    Kotlin因为之前Android宣布正式支持之后成为了Android世界的Swift,也是大火了一把。

    今天使用Spring Boot Initializr生成一个新项目时,突然发现选择的语言中也出现了Kotlin。

    感觉试验一下看一下具体长啥样。

    首先看看buildscript中多了两个插件,一个是kotlin-gradle-plugin,另外一个是kotlin-allopen。前者是语言支持插件,而后者是专门针对Spring AOP等特性应用的插件,它可以把Kotlin把类和字段变成final的。

    对应的插件使用方法为

    apply plugin: 'kotlin'
    apply plugin: 'kotlin-spring'

    而配置Java语言等级的方法也要使用Kotlin的

    compileKotlin {
    	kotlinOptions.jvmTarget = "1.8"
    }
    compileTestKotlin {
    	kotlinOptions.jvmTarget = "1.8"
    }

    其他的变化不大,毕竟是JVM语言,稍微了解一下语法就可以看懂,比如main函数是

    package com.huangyunkun.kotlin
    
    import org.springframework.boot.SpringApplication
    import org.springframework.boot.autoconfigure.SpringBootApplication
    
    @SpringBootApplication
    class KotlinApplication
    
    fun main(args: Array<String>) 
  • 数据库迁移工具Flyway对比Liquibase

    很多应用的运行是需要数据库支持的,而随着快速迭代,产品更替的节奏加快,除了产品本身需要不断更新以外,数据库也需要做出合适的管理了。

    为什么需要数据库迁移管理

    比如第一个版本的产品只包含了最基本的功能,而第二版本就需要增加评论功能,这就涉及到数据结构的修改(包括创建新表,修改旧表的列,增加已有表的列等等)。直接进入产品数据库修改数据库并不适合快速的开发节奏,不仅仅不安全,更多的情况下数据库可能并不对外或者并不适合对外直接暴露连接,比如PAAS平台的数据库以服务的形式直接提供。

    对比代码管理的一些实践,很明显在数据库方面做的还欠缺很多。比如代码管理中我们有

    • 版本管理(svn,git等等)
    • 持续集成技术
    • 良好的发布工具和流程

    而在数据库方面会遇到很多问题

    • 某台数据库现在是什么状态
    • 修改变更的脚本是否已经应用
    • 对于生产环境的紧急修复有没有被应用在测试环境
    • 如何创建一个新的数据库实例

    数据库迁移工具可以很好的管理这些问题,并提供了以下特性

    • 从迁移脚本中创建新的数据库
    • 检查数据库状态
    • 从一个版本快速到达另外一个版本

     Flyway和Liquibase

    数据库迁移工具很多,这里我们选择Flyway和Liquibase来说主要是两个原因,一是它们都是Java生态圈的,其次就是Spring Boot提供了这两者的内建支持,可以很快应用到产品中。

    Flyway相对简单,直接将你需要执行的SQL语句保存为文件,放入应用中执行即可。比如

    V1__init-database.sql
    V2__add-comment.sql

    Flyway的好处在于简单,而且直接书写SQL并不需要额外的学习。

    Liquibase相对就复杂了很多,它支持四种格式

    • xml
    • json
    • yaml
    • sql

    如果使用过Flyway就会有一定的体会,Flyway的简单是有代价的,举个简单的例子,如果我们开发环境是h2数据库,而测试环境和产品环境是MySQL,这里就有一个问题,SQL语句并不是一个广泛兼容的语言,有些关键字是独有的,而我们并不希望放弃这部分功能。这种情况下你就需要书写两套SQL迁移文件。Spring Boot是内建这种支持的,可以从目录上做区分。

    而Liquibase可以根据数据库的情况为你生成最后的迁移语句,同时因为数据库变动首先是被Liquibase解析,所以也可以简单支持回滚。

    来看一个Liquibase的例子,以XML为例,我个人觉得yaml更简洁,但是经常有对齐的问题。

    <?xml version="1.0" encoding="UTF-8"?>
    
    <databaseChangeLog
            xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
            xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog 
  • Spring Boot 1.5发布

    Spring Boot 1.5今天发布了。

    新版本添加了基于unboundid对于LDAP的支持和Apache Kafka的支持。还有一个有趣的改动是Flyway添加了对于vendor的支持,默认的数据库版本管理地址从db/migration/ 变成了flyway.locations=db/migration/{vendor} ,这里的vendor指的是不同的数据库类型,比如db/migration/mysql 。

    新版本还移除了Gradle 1.x的支持(Gradle最新版是3.x)。比较遗憾的是因为CRaSH project已经处于不活跃状态,所以Spring Boot 1.5移除了所有关于CRaSH的支持,也就是remote功能被废弃了。…

  • Spring Boot配置文件乱码的问题

    Spring Boot配置文件乱码的问题

    Spring Boot对于配置文件的支持非常完善,在配置文件中的内容可以很方便的在程序中应用。在配置文件中可能会出现中文的情况,而这个也是一个可能出现乱码的地方。

    首先Spring Boot支持两大类配置文件,一类是java properties文件,即application.properties文件;一类是yaml文件,即application.yml文件。

    这两种配置文件分别使用PropertiesPropertySourceLoader 和YamlPropertySourceLoader加载。这两种加载器对于编码的处理是不同的。

    PropertiesPropertySourceLoader 会首先检查配置文件后缀,如果是xml文件,那么是可以支持UTF-8的,但是如果是非xml文件,那么它调用的实际上是java的Properties类的load方法,而这个方法默认配置文件的编码是ISO 8859-1的。参考下面的Java API文档:

    The load(Reader) / store(Writer, String) methods load and store properties from and to a character based stream in a simple line-oriented format specified below. The load(InputStream) / store(OutputStream,

  • 再谈Spring Boot中的乱码和编码问题

    再谈Spring Boot中的乱码和编码问题

    编码算不上一个大问题,即使你什么都不管,也有很大的可能你不会遇到任何问题,因为大部分框架都有默认的编码配置,有很多是UTF-8,那么遇到中文乱码的机会很低,所以很多人也忽视了。

    Spring系列产品大量运用在网站开发中,而Spring Boot是为了简化配置而出现的,理论上讲Spring Boot应该默认配置UTF-8为默认编码,但是网络上依然可以看到很多关于Spring Boot乱码的文章,大部分解决方案沿用Spring MVC的方案,自定义EncodingFilter。

    但是仔细查看Spring Boot的文档,可以看到默认的编码的确是UTF-8

    spring.http.encoding.charset=UTF-8 # Charset of HTTP requests and responses. Added to the "Content-Type" header if not set explicitly.
    spring.http.encoding.enabled=true # Enable http encoding support.

    而相关的配置会在HttpEncodingAutoConfiguration中使用

    @Bean
    	@ConditionalOnMissingBean(CharacterEncodingFilter.class)
    	public CharacterEncodingFilter characterEncodingFilter() {
    		CharacterEncodingFilter filter 
  • 自定义SpringBootCondition

    Spring Boot中一个很重要的特性就是自动配置,可以根据很多条件决定是否生成相应的bean或者其他操作。

    大部分情况下自动配置的条件是ConditionalOnMissingBean,也就是没有这个bean,那就用这个自动配置配置一个。

    有时候自动配置条件并不是那么直接,有时候还涉及到一些自己的逻辑,这个时候就可以自定义SpringBootCondition来处理复杂一些的情况。

    继承SpringBootCondition并将自己的逻辑实现在getMatchOutcome方法中。

    自定义的逻辑大部分有两种,第一种是自动配置针对一类情况,需要检测多个独立类的存在性,比如EmbeddedDatabaseCondition,就会自动检测所有可能的数据库驱动,包括H2,DERBY,HSQL

    @Override
    public ConditionOutcome getMatchOutcome( ConditionContext context,
    					 AnnotatedTypeMetadata metadata )
    {
    	if ( anyMatches( context, metadata, this.pooledCondition ) )
    	{
    		return(ConditionOutcome.noMatch( "supported DataSource class found" ) );
    	}
    	EmbeddedDatabaseType type = EmbeddedDatabaseConnection
    				    .get( context.getClassLoader() ).getType();