之前Travis CI支持的Ubuntu 12.X,一般使用还好,但是对于有UI的,需要xvfb的有时候会有点问题。
现在直接支持Ubuntu Trusty了。使用方法
sudo: required dist: trusty
其他照旧。…
之前Travis CI支持的Ubuntu 12.X,一般使用还好,但是对于有UI的,需要xvfb的有时候会有点问题。
现在直接支持Ubuntu Trusty了。使用方法
sudo: required dist: trusty
其他照旧。…
Libgdx一直没有官方的UI编辑器,而cocostudio作为编辑器的能力让人羡慕。
有一个简单的办法就是使用cocostudio,导出项目,然后构建一个LIbgdx的runtime解析器,比如这个项目https://github.com/tianqiujie/cocostudio-ui-for-libgdx
Libgdx有很多版本,如果能够长久保持一定版本的支持(比如最新版为1.9.2,可以考虑支持1.7.0及以上)。
Travis提供了Env功能,可以配置多个环境变量,比如这里以版本为变量
language: java jdk: - oraclejdk7 env: - GDX_VERSION=1.9.2 - GDX_VERSION=1.9.1 - GDX_VERSION=1.9.0 - GDX_VERSION=1.8.0 - GDX_VERSION=1.7.0 before_install: - chmod +x gradlew
然后在Gradle配置中修改一下,改成先判断环境变量,如果没有就是用指定版本1.9.2,这样开发人员在本地不需要其他配置也可以让项目正常运行。
ext {
gdxVersion = System.env.GDX_VERSION != null ? System.env.GDX_VERSION : '1.9.2';
}
然后在Travis CI中的执行效果如下…
CSV,或者叫逗号分隔值,是以逗号为分隔符,简单而使用。虽然并没有真正的标准,但是RFC 4180中有一个大致的表述。
很多时候我们拿到的原始数据都是csv的,而快速将其转为Spark的Dataframe做进一步分析就是一个经常遇到的问题。
先来一个简单的例子,这里以手淘的数据为例子

共有六列。
先建立一个简单对象Record,然后直接用Spark的createDataFrame方法
JavaRDD<Record> list = sc.textFile(userFile).map(new Function<String, Record>() {
@Override
public Record call(String v1) throws Exception {
String[] split = v1.split(",");
return new Record(split[0], split[1], split[2], split[3], split[4], split[5]);
}
});
DataFrame dataFrame = sqlContext.createDataFrame(list, Record.class);…Spring Boot中的Endpoint可以提供很多便利信息,但是有时候自带的信息不能满足需要,就需要我们自己创建一个Endpoint。
对于一个项目而言我们希望能够了解到一些基本的信息,比如项目的构建环境,git仓库信息,CI的build number等等。
Netflix的nebula项目提供了很多gradle的插件,而搜集信息我们可以使用gradle-info-plugin。
buildscript {
repositories { jcenter() }
dependencies { classpath 'com.netflix.nebula:gradle-info-plugin:3.+' }
}
apply plugin: 'nebula.info'
这样在gradle构建项目的时候就会自动搜集信息,并存储在Properties文件中。这样就可以自定义一个Endpoint来展示这些信息。
import com.google.common.collect.Maps; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.boot.actuate.endpoint.AbstractEndpoint; import org.springframework.stereotype.Component; import java.io.IOException; import java.io.InputStream; import java.util.HashMap; import java.util.Map; import…
Spring Framework 4.3有两个有趣的改动,第一个是单一构造函数的自动注入,第二个就是注入依赖条件的配置。
来看看之前版本的代码
@Service
public class FooService {
private final FooRepository repository;
@Autowired
public FooService(FooRepository repository) {
this.repository = repository
}
}
@Autowired注解是一个很关键的东西,如果你忘记了,那么运行就会出现null错误。在新版本中,你无需这个注解了,Spring会自动处理这种情况。当然,这个功能同样对@Configuration等有效。
新的ObjectProvider可以提供两个特别的方法getIfAvailable和getIfUnique。比如这种
@Service
public class FooService {
private final FooRepository repository;
public FooService(ObjectProvider<FooRepository> repositoryProvider) {
this.repository = …对于任何需要认证的系统,Spring Security无疑是一个很好的选择。
无论是从认证本身,还是权限控制,Spring Security都有极好的支持。
Form登录是一种极为常见的方式,用户输入用户名和密码,post登录信息,认证之后登录信息保存在session之中。
但是随着架构演进,前后端逐渐分离,之前的大部分逻辑都变成了API供前端调用,而Form登录逐渐成为累赘,调试上的困难。这个时候就可以考虑换为token模式,进而将后端API stateless化。
第一步是选择token的生成和解析,我们来个简单的,token中只包含加密后的用户名,具体生成才是JWT的HS512加密。
先配置一个登录成功后的响应AuthSuccessHandler
public class AuthSuccessHandler implements AuthenticationSuccessHandler {
public static final String SECRET_KEY = "0Qx*@S7q";
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication authentication) throws IOException, ServletException {
response.setStatus(HttpStatus.OK.value());
JsonNodeFactory factory = …Spring Boot推出后取得了巨大的成功,方便快速上手,还附带了很多product-ready特性。对微服务架构也很友好。
随着Spring Boot一起推出的还有Spring Boot众多的starter。当你喜欢使用某些组件时,试试starter,只需要使用构建工具引用一个依赖,你就可以快速获得它。
了解starter之后你也可以自己实现自己的starter,以便其他同事快速使用公司内部特有的组件。
每个starter都有一个spring.factories文件,位于META-INF目录下。
# Auto Configure org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\ org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\ org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\ org.springframework.boot.autoconfigure.MessageSourceAutoConfiguration,\
随便开一个文件来看
@Configuration
@ConditionalOnClass({ RabbitTemplate.class, Channel.class })
@EnableConfigurationProperties(RabbitProperties.class)
@Import(RabbitAnnotationDrivenConfiguration.class)
public class RabbitAutoConfiguration {
@Bean
@ConditionalOnProperty(prefix = "spring.rabbitmq", name = "dynamic", matchIfMissing = true)
@ConditionalOnMissingBean(AmqpAdmin.class)
public …Spring Boot对于日志的支持是比较到位的,默认logback实现,输出到console。
如果你的console支持ANSI,那么还可以选择彩色输出。
很多时候可能并不只是希望日志能够输出到console,还希望能够保存到目录,甚至后期配合splunk等等做分析统计。
Spring Boot会检测logging.file和logging.path是否存在,如果存在的话就会输出到文件中。这个配置可以在application.properties中设置。
如果应用打包已经完成了,可以直接在命令行配置
java -jar app.jar -Dlogging.path=/alidata/log
…
Spring Boot应用在启动的时候会输出一个Banner,同时还会输出使用的Spring Boot的版本。
默认的Banner如下

如果你需要自己替换的话可以放置一个banner.txt文件,这样Spring Boot就会使用自定义的banner,而不是默认的banner。
Banner的优先级和具体逻辑在SpringApplication中。
private Banner selectBanner(Environment environment) {
String location = environment.getProperty(BANNER_LOCATION_PROPERTY,
BANNER_LOCATION_PROPERTY_VALUE);
ResourceLoader resourceLoader = this.resourceLoader != null ? this.resourceLoader
: new DefaultResourceLoader(getClassLoader());
Resource resource = resourceLoader.getResource(location);
if (resource.exists()) {
return new ResourceBanner(resource);
…Spring Boot提供了一套方便使用的endpoint,暴露了常用的一些应用信息,比如路由情况,堆栈情况等等,灵活的使用不仅可以加快调试,也可以方便运维。
RequestMappingEndpoint类提供了地址为mappings的endpoint,提供了是当前的路由情况,什么样的路径解析到什么样的执行器中。大概的输出如下

当然,任何你自己定义的Controller等等,都会被自动包含到这个mappings中。但是如果你使用Spring Data Rest,你就会发现它的相关信息并没有被包含到这个里面。
要解决这个问题,就需要先来看看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 …