分类: Spring

  • 使用spring-retry实现自动重试和错误异常管理

    经常会遇到一些有很高错误率的情况,比如需要从外部获取数据,而对应的网络条件又很一般,那么常常会出现一些错误和重试的情况,代码可能是这样的

    public class Demo {
        public Data featch() {
            int current = 0;
            Data data;
            while (current < MAX_TRY_LIMIT) {
                try {
                    data = service.call();
                } catch (Exception ex) {
                    index++;
                }
            }
            return data;
        }
    }

    如果项目代码中这种类似的比较多就有点难管理了,而且上面这段代码只处理了重试的情况,并没有超时控制,错误追溯等等。

    spring-retry是专为这种情况而生的,它被spring多个子项目使用,比如batch,integration等。

    @Service
    
  • Spring Boot在Paypal中的应用

    看着分享,slideshare上的,可能需要外网访问权限

    http://www.slideshare.net/SpringCentral/spring-boot-paypal

     

    PayPal很有趣的地方在于虽然Spring体系已经成为一定程度上的事实标准,但是PayPal还是先采用的JSR标准,然后将Spring家族的一部分作为JSR的实现来使用。…

  • Spring Boot 1.4发布

    Spring Boot 1.4昨天(7月28日)发布了,1.3系列经历了7个版本,终于来到了1.4系列。

    1.4有很多更新和新的功能支持,我个人觉得以下几个改动比较实用

    兼容Thymeleaf 3

    虽然默认的支持还是Thymeleaf 2.1,不过对于Thymeleaf 3还是可以用的。本来1.4是不准备支持Thymeleaf 3的,不过社区呼声非常高,所以最后还是采用了兼容方案。

    启动错误信息

    Spring Boot由于各种便利的特性广受喜爱,但是便利特性的同时也引入了一些不成为的规定和注解,而且大量的aop,自动配置穿插其中。如果你的项目有利用这些特性有一些自定义的东西,那么启动失败的追查原因就会非常复杂了。

    2016-02-16 17:46:14.334 ERROR 24753 --- [           main] o.s.boot.SpringApplication               : Application startup failed
    
    java.lang.RuntimeException: java.net.BindException: Address already in use
        at io.undertow.Undertow.start(Undertow.java:181) ~[undertow-core-1.3.14.Final.jar:1.3.14.Final]
        at org.springframework.boot.context.embedded.undertow.UndertowEmbeddedServletContainer.start(UndertowEmbeddedServletContainer.java:121) ~[spring-boot-1.3.2.RELEASE.jar:1.3.2.RELEASE]
        at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.startEmbeddedServletContainer(EmbeddedWebApplicationContext.java:293) ~[spring-boot-1.3.2.RELEASE.jar:1.3.2.RELEASE]
        
  • Spring Boot指定active profile的几种方法

    Spring Boot提供了分割配置的一些方法,不再需要把常常的配置写在一个文件中,而是拆分成诸如data,mvc,backend等对应的配置,这个特性也可以用在区分环境上,比如data-dev,data-dryrun,data-pro。

    Spring Boot提供了灵活的指定Profile的方法,比如注解

    @Configuration
    @Profile("production")
    public class ProductionConfiguration {
    
        // ...
    
    }

    直接写在需要读取配置的对应类上。

    当然我觉得更多的人可能倾向于在主配置文件中引用其他配置文件

    spring.profiles.active=dev,mysql

    当然,也可以用程序去解析,比如一些CI的情况下,你可能会使用特定的环境和配置,这样就需要在代码中判断

    SpringApplication.setAdditionalProfiles(...)

     …

  • 创建展示项目基本信息的Endpoint

    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 注入机制的改进

    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从表单验证到token验证

    对于任何需要认证的系统,Spring Security无疑是一个很好的选择。

    无论是从认证本身,还是权限控制,Spring Security都有极好的支持。

    Form登录是一种极为常见的方式,用户输入用户名和密码,post登录信息,认证之后登录信息保存在session之中。

    但是随着架构演进,前后端逐渐分离,之前的大部分逻辑都变成了API供前端调用,而Form登录逐渐成为累赘,调试上的困难。这个时候就可以考虑换为token模式,进而将后端API stateless化。

    Token的生成和解析

    第一步是选择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 starter

    Spring Boot推出后取得了巨大的成功,方便快速上手,还附带了很多product-ready特性。对微服务架构也很友好。

    随着Spring Boot一起推出的还有Spring Boot众多的starter。当你喜欢使用某些组件时,试试starter,只需要使用构建工具引用一个依赖,你就可以快速获得它。

    了解starter之后你也可以自己实现自己的starter,以便其他同事快速使用公司内部特有的组件。

    spring.factories

    每个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输出日志到文件

    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 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