如何在springboot中禁用某些jar的自动配置功能

我们知道在springboot中有这么一个自动配置的功能:假如你在工程中加入某个jar,比如mysql的jar,或者mongodb的jar,或者redis的jar,那么就算不写配置文件,springbboot也会启动相关的功能来简化构建这些客户端的复杂度。

但是有那么一种场景,比如我只想在工程中使用某个jar的某个类的功能,所以我必须要引入某个jar,但是又不想让springboot自动配置,那该怎么办?

其实很简单,只需要在启动类上进行配置,如下用mongodb来举例:

@SpringBootApplication(exclude={MongoAutoConfiguration.class})
public class Application {

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

}

这个时候来问题了,我假如想不包含 redis 的自动配置,那该如何写这个 XXXConfiguration.class 呢,这个到哪里找?
在回答这个问题之前,我们先来看一个错误提示,以redis的自动配置来举例,当设置不正确的时候,springboot启动的时候会进行报错,报错的内容大致如下:

Error starting ApplicationContext. To display the auto-configuration report re-run your application with 'debug' enabled

with ‘debug’ enabled,这个是什么鬼?这个debug在哪里设置啊,难道在 logback 中?不是吧。带着这个问题,我查了资料,找到这篇文章:http://www.it1352.com/908199.html,这篇文章里讲了该如何在springboot中进行设置,哦,原来就是在 application.properties 中假如 debug=true 即可。顺便吐槽一下这篇文章的网站,里面广告太多了,感觉是一个。。。

好了,我们继续上面的那个redis那个例子,我们把 debug=true 设置好,好了,真相出来了:

    RedisAutoConfiguration matched:
      - @ConditionalOnClass found required classes 'org.springframework.data.redis.connection.jedis.JedisConnection', 'org.springframework.data.redis.core.RedisOperations', 'redis.clients.jedis.Jedis'; @ConditionalOnMissingClass did not find unwanted class (OnClassCondition)

   RedisAutoConfiguration.RedisConfiguration#redisTemplate matched:
      - @ConditionalOnMissingBean (names: redisTemplate; SearchStrategy: all) did not find any beans (OnBeanCondition)

   RedisAutoConfiguration.RedisConfiguration#stringRedisTemplate matched:
      - @ConditionalOnMissingBean (types: org.springframework.data.redis.core.StringRedisTemplate; SearchStrategy: all) did not find any beans (OnBeanCondition)

   RedisAutoConfiguration.RedisConnectionConfiguration matched:
      - @ConditionalOnClass found required class 'org.apache.commons.pool2.impl.GenericObjectPool'; @ConditionalOnMissingClass did not find unwanted class (OnClassCondition)

   RedisAutoConfiguration.RedisConnectionConfiguration#redisConnectionFactory matched:
      - @ConditionalOnMissingBean (types: org.springframework.data.redis.connection.RedisConnectionFactory; SearchStrategy: all) did not find any beans (OnBeanCondition)

   RedisCacheConfiguration matched:
      - Cache org.springframework.boot.autoconfigure.cache.RedisCacheConfiguration automatic cache type (CacheCondition)

   RedisRepositoriesAutoConfiguration matched:
      - @ConditionalOnClass found required classes 'redis.clients.jedis.Jedis', 'org.springframework.data.redis.repository.configuration.EnableRedisRepositories'; @ConditionalOnMissingClass did not find unwanted class (OnClassCondition)
      - @ConditionalOnProperty (spring.data.redis.repositories.enabled=true) matched (OnPropertyCondition)
      - @ConditionalOnMissingBean (types: org.springframework.data.redis.repository.support.RedisRepositoryFactoryBean; SearchStrategy: all) did not find any beans (OnBeanCondition)

于是,我们就可以这么设置我们的启动类:

@SpringBootApplication(exclude={RedisRepositoriesAutoConfiguration.class,RedisAutoConfiguration.class})
public class Application {

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

}

上面的RedisCacheConfiguration是个私有类,不能用,不用也达到了效果。

全文结束。

在dubbox的rest接口中使用表单提交对象

dubbox使用resteasy作为rest的实现方式,所以这篇文章的标题也可以称作:在resteasy的接口中使用表单来提交对象。

我们都知道,在resteasy中,假如接口参数是对象,那么参数定义的时候,什么注解都不需要写,直接就可以在前端用requestbody的形式提交json即可,非常方便。

但是需求来了,前端需要用 form 表单的形式来提交对象。

首先我参考了 resteasy 的官方文档 http://docs.jboss.org/resteasy/docs/3.0.7.Final/userguide/html/_Form.html

然后我查了资料,查到的是这样的一篇博文,RESTEasy数据自动装配之@FormParam,写得非常不错,我的解决就是参考这篇博文。但是在这篇文章中有2个疑问:
1,@Mapped这个是个什么鬼,不用这个也没有任何问题。
2,@Consumes(MediaType.APPLICATION_FORM_URLENCODED),这个我在postman中直接用 Content-Type:application/x-www-form-urlencoded 是没有任何问题的,也就是说 @Consumes(MediaType.APPLICATION_FORM_URLENCODED) 完全可以去掉。

在实现的时候,我们用得包和类如下:
@Form 是 org.jboss.resteasy.annotations.Form,属于resteasy-jaxrs-xxx.jar
@FormParam 是 javax.ws.rs.FormParam,属于javax.ws.rs-api-xx.jar

这个示例工程就不举了,因为还牵扯 springboot 和 dubbox 的细节,不举这个工程的例子了,大家参照上面的那篇博文,完全能写出来。

在junit中如何assert一个对象是null或者空字符串

在junit测试中,我们对某个对象需要判断是否为null,但是有时候在一些情况下,该对象可能是””(也就是空字符串),这个时候我们以前写得那个Assert.assertNull()就不行了。其实这种情况在现实中也是大量存在的,比如页面表单提交后的action获取表单中的字段,假如是字符串,那么往往是空字符串的存在。

那么,在junit中如何assert一个对象是null或者空字符串,我查了下资料,可以见这里:https://www.baeldung.com/java-assert-string-not-empty,我们可以用 Apache Commons Lang 来完成这个需求:
Assert.assertTrue(StringUtils.isEmpty(someObject));
不再用Assert.assertNull(),改用Assert.assertTrue()

这里有个小小的工程,可以看看 Assert.assertTrue(StringUtils.isEmpty(someObject)); 的使用:
https://github.com/champbay/springboot-test.git

SpringBootTest中启用不同的profiles

在springboot中,我们的工程常常有下面的配置文件:

application.properties
application-prod.properties
application-dev.properties

其中,application.properties是默认就加载的,prod和dev是需要在application.properties中指定spring.profiles.active=xxx来确定。

在测试的时候,需要测试环境,不管是prod还是dev都不适用的,所以在测试的时候,需要有个地方来设定配置文件。

查了资料,首先查到一篇文章:如何在@SpringBootTest中动态地启用不同的profiles,这篇文章讲了一大堆,我也没有全部看全,可能场景不适合我吧,总觉得这个需求应该非常普遍简单的,总不至于这么复杂的来解决吧。

继续查资料,看到这一篇文章:https://stackoverflow.com/questions/41985262/spring-boot-test-overriding-bootstrap-properties,这里有个人回答了几种办法,其中使用 Add @ActiveProfiles(‘test’),大家 test class 这种方式我觉得应该是最最正确的解决办法。

为此,我做了一个很小的测试工程放在 github 上,用来验证@ActiveProfiles(‘test’),大家可以去下来junit测试看看,看了后就能明白了。

工程地址:
https://github.com/champbay/springboot-test.git

JAVA字符串前补零和后补零的方法

字符串的前补零,往往用在排序上,比如:某个表id是字符串类型,a记录的id是“2”,b记录的id是“11”,从我们看来,因为是a排在b的前面,但是用字符串去排序的话,那么b将是在a的前面,所以这个时候需要进行前补零,其实入库之前就应该前补零就使得a的id就是“02”这样的格式。

字符串的后补零,往往用在财务统计报表上,需要对小数点进行统一,从而使得在界面的排版上数字的排列清晰。

前后补零的文章,我这里转载自一篇博文,JAVA字符串前补零和后补零的快速方法,例子举得很明白。

String fileName = "130181";
System.out.println("================  前补零方法一   =================");
DecimalFormat g1=new DecimalFormat("0000000");
String startZeroStr = g1.format(Integer.valueOf(fileName));
System.out.println("前补零方法一:"+startZeroStr);

System.out.println("================  前补零方法二   =================");
startZeroStr = String.format("%07d",Integer.valueOf(fileName));
System.out.println("前补零方法二:"+startZeroStr);

System.out.println("================  后补零方法一   =================");
DecimalFormat g2=new DecimalFormat("0.000000");
String endZeroStr = g2.format(Integer.valueOf(fileName));
System.out.println("后补零:"+endZeroStr);
System.out.println("虽然后补零出现这种情况,带有小数点");
System.out.println("比如你要长度要在7位以内,可以这么做");
System.out.println("后补零转变后:"+endZeroStr.replace(".","").substring(0,7));

输出结果如下:

================  前补零方法一   =================
前补零方法一:0130181
================  前补零方法二   =================
前补零方法二:0130181
================  后补零方法一   =================
后补零:130181.000000
虽然后补零出现这种情况,带有小数点
比如你要长度要在7位以内,可以这么做
后补零转变后:1301810

对于String.format()方法,可以查看jdk文档,里面有关于 formatter 的详细说明,:anguished:,太详细了以至于看得眼花缭乱,这里有一篇博文 JAVA字符串格式化-String.format()的使用,写得简单明了,大家可以上去看看前补零为什么是这样的格式。

springboot如何正确使用tomcat连接池

在springboot的application.properties中,我们常常这么设置:

spring.datasource.url=jdbc:mysql://192.168.0.1:3306/dbname
spring.datasource.username=aaa
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.jdbc.Driver

假如只有上面这些关于连接池的设置,那么springboot将根据 org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder 中的下面次序去找有没有相应的jar:

private static final String[] DATA_SOURCE_TYPE_NAMES = new String[] {
            "org.apache.tomcat.jdbc.pool.DataSource",
            "com.zaxxer.hikari.HikariDataSource",
            "org.apache.commons.dbcp.BasicDataSource", // deprecated
            "org.apache.commons.dbcp2.BasicDataSource" };

假如工程是内置tomcat容器的,那么默认就是 org.apache.tomcat.jdbc.pool.DataSource,同时tomcat连接池的那些最大最小参数都是默认值:
initialSize 10
maxActive 100
maxIdle 100
minIdle 10
可以看到这些默认值基本上也能满足大多数场景了。

假如觉得上面的这些值还不够好,那么需要在application.properties中这么设置才可以:
spring.datasource.tomcat.initialSize=10
spring.datasource.tomcat.maxActive=200
spring.datasource.tomcat.maxIdle=200
spring.datasource.tomcat.minIdle=10

这是因为在 org.springframework.boot.autoconfigure.jdbc.DataSourceConfiguration.Tomcat 这个类中如下定义:

@Bean
        @ConfigurationProperties(prefix = "spring.datasource.tomcat")
        public org.apache.tomcat.jdbc.pool.DataSource dataSource(
                DataSourceProperties properties) {
            org.apache.tomcat.jdbc.pool.DataSource dataSource = createDataSource(
                    properties, org.apache.tomcat.jdbc.pool.DataSource.class);
            DatabaseDriver databaseDriver = DatabaseDriver
                    .fromJdbcUrl(properties.determineUrl());
            String validationQuery = databaseDriver.getValidationQuery();
            if (validationQuery != null) {
                dataSource.setTestOnBorrow(true);
                dataSource.setValidationQuery(validationQuery);
            }
            return dataSource;
        }

可以看到 prefix = “spring.datasource.tomcat”,所以需要在配置中的前缀应该是 spring.datasource.tomcat,不这么设置,实际上是没有启用这些参数的。

最后,如何验证这些参数是否生效:在 org.apache.tomcat.jdbc.pool.DataSourceProxy 这个类的getConnection()方法中加个断点,然后运行后访问数据库时,查看这个 datasource 的这些参数。

下一篇将是 《springboot如何正确使用dbpc2连接池》