博客

  • 包含Spring Data Rest到mappings endpoint中

    Spring Boot提供了一套方便使用的endpoint,暴露了常用的一些应用信息,比如路由情况,堆栈情况等等,灵活的使用不仅可以加快调试,也可以方便运维。

    RequestMappingEndpoint类提供了地址为mappings的endpoint,提供了是当前的路由情况,什么样的路径解析到什么样的执行器中。大概的输出如下

    mapping-endpoint-sample

    当然,任何你自己定义的Controller等等,都会被自动包含到这个mappings中。但是如果你使用Spring Data Rest,你就会发现它的相关信息并没有被包含到这个里面。

    Mappings Endpoint原理

    要解决这个问题,就需要先来看看RequestMappingEndpoint是如何工作的。

    首先它并没有缓存,这意味着每次访问的时候它都会调用invoke方法来获取信息

    public Map<String, Object> invoke() {
         ....
    }

    而Spring中的路由的映射大致讲只有两种,一种是UrlHandlerMapping,一种是MethodMapping。我们最常用的Controller配合RequestMapping的属于后者。

    而处理这两种情况都是从applicationContext中获取所有实例,然后提取信息。唯一的不同是两种映射的对应信息保持方式不同而已。

    Map <String,AbstractUrlHandlerMapping > mappings = applicationContext.getBeansOfType(AbstractUrlHandlerMapping.class);
    for (Entry < String, AbstractUrlHandlerMapping > mapping: mappings.entrySet()) {
        Map < String, Object > handlers 
  • Spark的Datasets

    对于Spark的使用者来说,越简单易用的API越好。所以在原有的RDD之上,Spark陆续添加了DataFrames和Spark SQL。特别是DataFrames,对于小数据集的快速上手非常简单,其API也是从R中借鉴的,很有亲切感。当然在这之下,底层的实现还是RDD,只是对于使用者,抽象程度更高而已。

    DataSets是为了解决类型安全和面向对象思维而添加的新API,包含在Spark 1.6中,其也是下个版本集中的方向。

    DataSets并不是从关系型数据结构抽象出来的,所以它的API反而和RDD类似,比如

    val lines = sqlContext.read.text("/wikipedia").as[String]
    val words = lines
      .flatMap(_.split(" "))
      .filter(_ != "")
    val counts = words 
        .groupBy(_.toLowerCase)
        .count()

    在直接使用的效率和资源消耗上要好一些(图来自DataBricks)

    Memory-Usage-when-Caching-Chart-1024x359Distributed-Wordcount-Chart-1024x371

    当然,另外一个增强面向对象的特性使用很简单, 主要基于Encoders

    public class Person implements Serializable {
        private String name;
    
        get/set function{}
    }
    
    Dataset<Person> 
  • Http2在JVM环境的支持

    先来看看容器

    • Undertow
    • Jetty
    • Tomcat9

    然后还有 Netty。

    对于TLS的支持

    • Java6只支持v1
    • Java7支持v1.2
    • Java8支持v1.2
    • Java9支持ALPN
  • netflix的gradle插件

    Netflix在开源界的声誉稳步上涨,主要源于其公司产品特性中抽象出的微服务体系概念落地的开源技术。NetflixOSS不管包含主要的抽象组件,也开源了它使用的gradle插件,很多插件非常易用。

    Gradle作为构建工具,有远优于Maven的配置灵活性和Groovy对于Java世界极高的亲和力。

    一个普通的模板项目一般只是用了java和对应IDE插件,比如

    apply plugin: java
    apply plugin: idea
    apply plugin: eclipse

    但是除此之外还有一些基本的,比如发布,版本号升级,项目联系人,协议检查等等等等基本配置。

    Netflix的gradle-netflixoss-project-plugin可以快速实现这些。

    buildscript {
      repositories { jcenter() }
      dependencies { classpath 'com.netflix.nebula:gradle-netflixoss-project-plugin:3.2.2' }
    }
    
    allprojects {
        apply plugin: 'nebula.netflixoss'
    }

    这个插件其实也是调用其他插件,除了协议检查使用了hierynomus的以外,其他都是 Netflix自己的。默认的协议header是Netflix的,需要自己重新配置,格式如下:

    Copyright ${year} Netflix, Inc.
    
    
  • 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 Security的response header

    Spring Security会默认配置若干个相关的HeaderWriter,比如HstsHeaderWriter、XXssProtectionHeaderWriter等。

    默认情况下响应的头部类似这样

    Cache-Control: no-cache, no-store, max-age=0, must-revalidate
    Pragma: no-cache
    Expires: 0
    X-Content-Type-Options: nosniff
    Strict-Transport-Security: max-age=31536000 ; includeSubDomains
    X-Frame-Options: DENY
    X-XSS-Protection: 1; mode=block

    这其中有五个HeaderWrite,撇开第一个Cache Control不谈,因为主要是涉及旧版本迁移,剩下了四个。

    Content Type Options

    这个选项是由于浏览器对于资源会去“猜”。如果返回的资源没有指明类型,那么浏览器就会自己去判断。自动去判断内容是危险,可以构造出XSS攻击。

    X-Content-Type-Options: nosniff

    当然开启这一特性那么就必须在返回的资源中指明类型,不然会出现无法正确解析的情况。

    HTTP Strict Transport Security

    一些网站自身就可以同时通过http和https访问,而有些只允许https访问,设置对应的头

    Strict-Transport-Security: max-age=31536000 ; 
  • Spring boot中使用WebJars

    一个Java Web项目或多或少需要是一些javascript或者css依赖,比较容易想到的办法就是用前端构建工具管理依赖,然后直接拷贝到Webapp目录,当然spring boot对于静态资源还支持一下几个位置:

    "classpath:/META-INF/resources/"
    "classpath:/resources/"
    "classpath:/static/"
    "classpath:/public/"

    我对于前端管理工具并不喜欢,也不想安装诸如node等相关环境,这个时候就可以试用WebJars了。

    WebJars

    WebJars将前端资源打包到jar中,这样开发人员就可以简单的管理依赖,并且可以使用已有的JVM base构建工具和生态链,同时对于RequireJS也有一些自动化支持。

    在Spring Boot中使用WebJars是非常简单的,简单的引入依赖就可以,所有资源都暴露在 /webjars/** 下,只要你知道版本号和文件名,就可以直接在前端页面中引用相关资源。

    Spring Boot的支持

    在Spring Boot中使用WebJars如此简单,主要是因为Spring Boot有一个默认的支持,是否启动对应配置的条件在OnEnabledResourceChainCondition类

    class OnEnabledResourceChainCondition extends SpringBootCondition {
    
    	public static final String WEBJAR_ASSERT_LOCATOR = "org.webjars.WebJarAssetLocator";
    
    	@Override
    	public ConditionOutcome getMatchOutcome(ConditionContext context,
    			AnnotatedTypeMetadata metadata) {
    		
  • Docker container的监控

    迁移到Docker以后遇到的一个问题就是监控上的,比如当前资源消耗如何等等。

    之前的监控是用的OneAPM,但是都是应用级别的,需要不同的应用安装不同的探针。

    虽然也有很多可以监控Docker容器的,但是要在服务器安装服务我确实又不太想,找了一下发现OneAPM支持Docker化安装探针。

    对应镜像的构建脚本可以看这里,官方的老是启动不起来,我就自己构建了一个。

    在DaoCloud直接部署

    agent

    然后就直接去OneAPM控制台看结果了

    docker-info

    可以很容易看到每个container的内容消耗,也可以自己定义仪表盘。…

  • 迁移遗留项目到Docker

    结合DaoCloud体验了几天Docker,感觉非常的不错,所以也准备把已有的一个项目也迁移到Docker上。

    遗留项目

    这个项目是一个Java的Web项目,需要Java8环境,使用了Spring Boot,自带了运行容器,可以直接 java -jar 启动。项目使用了MySql数据库,没有用什么专有特性。数据库中数据也不多,可以mysqldump来迁移。

    迁移数据库

    先从数据库开始吧,原有数据库监听于3306端口,和应用一个主机。第一步打算就是先docker化数据库,但是仍然绑定端口在3306上,这样可以在只迁移数据库的情况下依然保证整个应用可用。

    先去Daocloud的应用编排里面创建一个新的应用

    db:
      image: mariadb
      restart: always
      ports:
      - 3306:3306
      volumes:
      - /alidata/data/acgmo-data:/var/lib/mysql
      environment:
      - MYSQL_ROOT_PASSWORD=你的密码

    然后直接连接到这个数据库

    mysql -u root -p 数据库名 < bak.sql

    完成后直接重启java web应用,看看应用是不是一切正常。

    迁移Java Web项目

    这个就稍微复杂一些了,因为mysql啥的中央库都有,不需要自己构建。但是这个就必须自己构建了。

    DaoCloud提供了代码构建功能,也支持bitbucket的私有库,唯一需要做的就是添加一个Dockerfile来构建,当然如果不想添加到代码库中也可以使用云Dockerfile功能。

    比如这个项目的Dockerfile如下

    FROM