分类: Spring

  • Spring Cloud Task

    Spring Cloud Task是Spring Cloud下的一个新项目,1.0.0.M1版不久前才发布。

    Spring Cloud项目簇是针对云平台的,然而对于大部分云平台,任何运行于之上的应用都是长实效的,如果退出,那么平台会自动重启它们已达到“恢复“的目的。

    但是有些需求并不是这样的,可能存在一个生命周期极短的应用,它是定时执行的,当结束之后我并希望平台自动重启它,可能的话也希望能够获得应用运行的细节,比如起始时间,退出值等等。这就是Spring Cloud Task希望解决的问题。

    目前该项目只有一个注解@EnableTask,支持主流数据库,能够获得应用(或者任务)的相关信息,也提供了生命周期的管理和对应的代码执行切面方便自定义。

    附上简单的示例代码一份

    @SpringBootApplication
    @EnableTask
    @EnableConfigurationProperties({ TimestampTaskProperties.class })
    public class TaskApplication {
    
    	@Bean
    	public TimestampTask timeStampTask() {
    		return new TimestampTask();
    	}
    
    	public static void main(String[] args) {
    		SpringApplication.run(TaskApplication.class, args);
    	}
    
    	/**
    	 * 
  • Spring Boot 日志管理和收集

    Spring Boot 日志管理和收集

    日志对于应用程序的重要性不言而喻,社区也有各种各样的日志框架。

    Spring Boot从实现上不一依赖于任何日志框架的实现,只有对于common-logging API的依赖,对应的抽象实现是LoggingSystem

    依靠这一层的抽象,对于日志等级的配置可以完全在Spring Boot中实现,比如application.properties

    logging.level.org.springframework.web=INFO
    logging.level.org.hibernate=DEBUG

     

    对于具体的日志框架实现可以选择 Java Util Logging, Log4J, Log4J2 或者 Logback。从mvn库的依赖和下载数量来看Logback的使用数量确实有较大的优势。

    对于具体实现部分的配置还是由实现框架本身管理,比如Logback对应的logback.xml文件。

    大部分日志的输出一般会对应两部分,一部分是stdout,一部分是日志文件。

    对于大规模部署的云原生应用,直接输出到stdout,然后从docker中收集日志也是一个不错的选择的。

    市面上日志聚合和搜索平台实在太多,有部分需要从代码层面做出修改,但是最简单的办法还是从日志实现本身入手。比如
    loggly提供了对于logback的支持。

    只需要在配置加上对应的appender即可。

    <configuration>
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
    <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
    </encoder>
    
  • Spring Boot结合FluentLenium做集成测试

    对于Web应用,一般为了测试功能性,都会结合selenium做功能性测试。

    Selenium会启动浏览器访问网站,然后对网站进行交互性操作,并判断结果。

    一般的操作流程是,打war包,部署war包,等待Web应用启动,开始测试,整理测试结果,关闭Web应用。

    而Selenium只是一个测试工具,并不会管理其他问题,需要自己处理web应用的启动和关闭。

    同时Selenium暴露的API有些底层,对于WebDriver的管理需要自己控制,对于元素的查找等也比较繁碎。

    Spring Boot在1.2.X版本中增强了对于Integration测试的集成,当然也包括了WebIntegration的集成,可以使用这部分功能来管理除具体测试以外的管理问题,
    Spring Boot会在测试开始前启动Web应用,并在测试后关闭它们。

    @RunWith(SpringJUnit4ClassRunner.class)
    @SpringApplicationConfiguration(classes = WebApplication.class)
    @WebIntegrationTest({"server.port=0","spring.profiles.active=test"})

    在测试类加上这段注解,server.port=0表示随机选取端口,而spring.profiles.active=test指定了当前profile为test。

    修改profile是很实用的,比如以我个人的习惯,我会在dev和prod中使用真实的数据库和其他组件,而在CI服务器上一般使用内存数据库,其他依赖组件尽可能使用内嵌式的,或者由docker提供,这样的话相关配置的区别就需要在不同的profile中区分了。

    随机化的端口可以保证测试不会由于端口占用失败,但是测试中我们需要用

    @Value("${local.server.port}")
    int port;

    把具体的端口号取到,以便在测试中使用。

    FluentLenium是一个写selenium测试的工具库,它可以帮你管理webdriver,并提供了更简单的API来加快测试的开发速度和可读性。

    FluentLenium默认使用的是Firefox Driver,可以自己修改。

    比如有一个测试去测试首页的标题

    @RunWith(SpringJUnit4ClassRunner.class)
    @SpringApplicationConfiguration(classes = WebApplication.class)
    @WebIntegrationTest({"server.port=0","spring.profiles.active=test"})
    publicclass HomeTest extends FluentTest {
    @Value("${local.server.port}")
    
  • 使用Java DSL配置Spring Integration

    Spring Integration是Spring下的一个项目,主要为了扩展Spring现有的模型已支持Enterprise Integration Patterns。

    Spring Integration还和其他项目结合紧密,比如Spring XD就可以使用其作为输入来源。

    Spring Integration可以完全依赖于xml工作,即意味着一个核心系统完成后,可以只单单更改xml配置本身来完成相关功能变更。

     

    但是xml配置也有不便利的地方,特别是在项目开发初期,对于开发人员而言,xml的表达能力自然不如java,在需要功能扩展的时候也必须需要java代码才行。

    而Spring的一个新的子项目spring-integration-java-dsl就可以实现使用java dsl来配置相关功能。

    以最简单的消费atom源为例,xml的配置如下

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:int="http://www.springframework.org/schema/integration"
    xmlns:file="http://www.springframework.org/schema/integration/file"
    xmlns:feed="http://www.springframework.org/schema/integration/feed"
    xsi:schemaLocation="http://www.springframework.org/schema/integration/feed http://www.springframework.org/schema/integration/feed/spring-integration-feed.xsd
    http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/integration/file http://www.springframework.org/schema/integration/file/spring-integration-file.xsd
    http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd">
    <feed:inbound-channel-adapter id="news" url="https://spring.io/blog.atom">
    <int:poller fixed-rate="5000"/>
    </feed:inbound-channel-adapter>
    <int:transformer
    
  • 云应用与Lattice

    快,是现在一个很喜欢提的概念。快速发现用户需求,快速的产品原因,快速的提供服务,快速的迭代,快速的部署,快速的试错。

    为了满足这些,软件架构和基础服务也在发生改变。

    从独立机房到云主机,再到所谓的容器,快速的部署一个具有极大扩展性的应用变得越来越容易,当然费用也是越来越低。

    为了适应这些变化,软件架构也在向云应用转变。

    Cloud Native Application

    Cloud Native Application,说实话,我不知道中文名字叫什么,先称为云应用(我相信应该有一个更正式的说法)。

    从中衍生的还有所谓的 Cloud Native Application Architectures,即云应用体系结构。

    简单说来无非是一下几个问题:

    • 以一个或多个无状态进程运行应用
    • 通过端口绑定提供服务
    • 快速启动和优雅终止可最大化健壮性
    • 把日志当作事件流
    • 其他。。。

    应用由小的模块组成,每个模块尽可能无状态,模块能够快速的终止和启动。

    更多的相关概念和理论可以参考文木末的免费电子书。

    Spring-Boot和Spring-Cloud

    以Web应用说明,如果构建成war包然后发布到容器中,那么就很难做到以端口绑定提供服务,多个无状态进程等等。

    Spring-Boot提供了一个很简单的思路,如果发布到容器不行,那么就把容器包含在自身,使用内置的jetty或者tomcat来作为服务的承载。

    当然Spring-Boot还提供了快速的开发的若干便利,从配置到依赖管理,进而到调试和发布。

    Spring-Cloud提供了功能更进一步的“云特性”。

    • 配置管理
    • 路由
    • 负载均衡
    • 服务注册和发现
    • 集群决策和状态管理

    可以说在Spring的大旗之下有超过10个项目或者子项目再为云应用这个理念服务。

    Lattice

    有了理念,有了工具和框架,自然需要一个平台。

    Lattice就是一个为云应用而生的管理平台,主要的功能包括:

    • Http负载均衡
    • 日志
  • Spring boot中的Info Endpoint

    为了监控应用,Spring Boot提供了EndPoint的支持。

    目前提供了十一种,其中大部分都包含默认实现,只有其中的Info需要用户自己提供。

    Info的存在很大程度上可以替代AppCheck功能。

    最简单添加Info信息的方式就是自己在配置中写入

    info.name=app

    这样访问/info就可以获得类似这样的结果

    {
    name: 'app'
    }

    但是有一些信息是不固定的,比如版本号。

    这种可以使用打包工具去完成信息的填充。比如写成

    info.version=${version}

    在Gradle配置中加上

    processResources{
    expand(project.properties)
    }

    当然这样写有一些问题,如果你是用了Flyway等数据库版本管理工具,那么你原声的SQL文件也会被处理,视情况而定,有很高几率信息填充会失败。

    所以先过滤一下

    processResources {
    filesMatching('**/*.properties') { expand(project.properties) }
    }

    当然,有时候我们还需要一些版本库的信息,比如Git相关信息。

    可以Gradle的Git插件来获取数据,然后提供给Info。

    importorg.ajoberstar.grgit.Grgit
    
    Grgit repo = Grgit.open(project.file('.'))
    ext.git = [
    name 
  • Spring MVC和HtmlUnit测试

    如果有一个Spring MVC项目,那么我们的测试一般有两种,一种是单元测试,第二种是端对端测试。

    单元测试可以选用Spring MVC Test框架,当然也可以当作一般的单元测试不使用SpringJUnit4ClassRunner来运行。

    而端对端测试一般是起一个服务,然后使用测试框架启动一个浏览器来测试。这两者相互结合倒也融洽。

    整个Spring项目最近多了一个新的项目,提供了一种介于其中的测试支持。

    Spring Test Htmlunit

    这个项目是Spring原有测试框架和HtmlUnit的一个结合。

    主要在于解决以下三个问题:

    • 集成常见的测试工具同时不启动服务器(当作单元测试对待)
    • 支持Javascript
    • 可以Mock一些组件来加快测试

    先来看看原有的单元测试框架是如何测试的

    MockHttpServletRequestBuilder retrieveProfile = post("/profile/")
    .param("userid","1"));
    
    mockMvc.perform(retrieveProfile)
    .andExpect(status().isOk());

    当然测试中还可以去测试Model。如果需要测试页面渲染,就需要借助xpath了。

    mockMvc.perform(get("/profile/create"))
    .andExpect(xpath("//input[@name='name']").exists())
    .andExpect(xpath("//textarea[@name='introduction']").exists());

    但是页面的交互是很负责,所以更多部分的测试是在端对端中。

    示例

    来看看新的工具是怎样解决问题的。

    首先创建一个WebClient

    WebClient webClient;
    
    @Before
    publicvoidsetup() {
    webClient = MockMvcWebClientBuilder
    .webAppContextSetup(context
    
  • Spring Boot新模块devtools

    Spring Boot 1.3中引入了一个新的模块,devtools。

    顾名思义,这个模块是为开发者构建的,目的在于加快开发速度。

    这个模块包含在最新释出的1.3.M1中。

    dependencies {
    compile("org.springframework.boot:spring-boot-devtools")
    }

    自动禁用模板缓存

    一般情况下,View层都会应用诸如Thymeleaf之类的模版引擎,这些引擎一般会在启动或者第一次加载时编译自己,所以应用启动以后再修改它们就不会立刻生效。

    当然,这种情况下你可以禁用掉缓存已达到快速调试的目的,比如对于Thymeleaf,你需要设置spring.thymeleaf.cache为false。

    devtools会自动帮你做到这些,禁用所有模板的缓存,包括Thymeleaf, Freemarker, Groovy Templates, Velocity, Mustache等。

    自动重加载

    如果你修改了Controller类的代码,那么你只有手动重启来观察修改效果。

    当然也可以配合其他工具来达到自动重加载的目的,比如 JRebel 或者 Spring Loaded。

    现在只需要引入devtools就可以了,它会自动进行重加载。重加载时服务无法访问,下一部分的精力将会放在加快重加载速度,并尽可能自动侦测需要重新加载的类,减少不必要的开销。

    在浏览器方面,devtools内置了一个LiveReload服务,可以自动刷新浏览器。

    其他

    还有个重要的改进是远程调试,主要针对Docker和Pass平台,调试使用的是JDWP。

    目前1.3正式版还没有释出,M2版还有一个改进就是对于默认日志格式的覆盖,这也是一个直接期待的小加强。…

  • 使用Gradle注册SpringXD的module

    使用Gradle注册SpringXD的module

    SpringXD是Pivotal的大数据产品,提供了一个抽象的数据处理平台。

    SpringXD将数据解决方案抽象为数据吸纳,分析,流调度和输出四大块。

    作为源头的数据吸纳可以从各种数据源中获取需要的数据,基于Spring的另外一个项目spring-integration,这一部分的大部分实现都可以使用简单的dsl实现。

    在SpringXD中每一个部分的组件都可以自己编写并注册到服务中,方便之后的使用。

    但是在编写阶段每次都需要打包,上传服务器,然后注册,整个过程还是有点繁琐的。

    Gradle作为一个构建工具,自然可以通过自定义任务完成这个任务。

    微博数据吸纳

    这里以微博的数据源为例。

    微博的数据源因为新浪微博提供了sdk,所以自己编写稍微方便一些。

    SpringXD项目默认也提供了twitter的两个source方便测试。

    先看一下build.gradle的配置

    ext {
    xdVersion ='1.1.1.RELEASE'
    springVersion ='4.1.3.RELEASE'
    moduleType ='source'
    moduleName ='weibo'
    xdServer ="http://192.168.0.12:9393"
    version ='0.0.1-SNAPSHOT'
    }

    最关键的配置变量是moduleType,moduleName和xdServer。

    为了简单明了,WeiboSource并不具有配置参数(一般情况下都需要提供一些配置参数的,比如apiKey),主配置文件如下

    <?xml version="1.0" encoding="UTF-8"?>
    <beans:beans xmlns="http://www.springframework.org/schema/integration"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:beans="http://www.springframework.org/schema/beans"
    xsi:schemaLocation="http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
    http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    
    <channel 
  • Spring根据包名搜索类

    有时候我们会遇到这种情况,需要根据动态获取某个包下的一些特定类。

    比如获取”com.xxx.domain”下所有类。

    Spring中ClassPathScanningCandidateComponentProvider可以快速完成这项任务。

    Spring最核心的一个部分就是Ioc,通过@Component来注解需要委托管理的类。

    ClassPathScanningCandidateComponentProvider提供了一个默认的过滤器来处理Component。

    protectedvoidregisterDefaultFilters() {
    this.includeFilters.add(new AnnotationTypeFilter(Component.class));
    ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader();
    try {
    this.includeFilters.add(new AnnotationTypeFilter(((Class < ?extends Annotation > ) ClassUtils.forName("javax.annotation.ManagedBean", cl)),false));
    logger.debug("JSR-250 'javax.annotation.ManagedBean' found and supported for component scanning");
    }catch(ClassNotFoundException ex) {
    //