使用注解@Profile来标识加载的对象,配合@Component注解一起使用。
@Component类似的注解也可以一起使用,比如@Service@Controller@Repository@Configuration

如下,我们有两个HelloService的实现,一个是用于开发环境的,这个实现可以简单一点;另外一个是用于真正的生产环境的,要进行真正的处理,比如调用RPC,数据库处理等。

@Service
@Profile({"dev"})
public class HelloServiceDevImpl implements HelloService {
    // ...
}
@Service
@Profile({"pro"})
public class HelloServiceImpl implements HelloService {
    // ...
}

application.yml的配置,如果要使用HelloServiceDevImpl,要激活对应的profile,可以使用:

spring:
  profiles:
    active: dev

类似的正式环境的配置,可以使用:

spring:
  profiles:
    active: pro

如果对象依赖于多个profile,也可以传入多个:

@Service
@Profile({"pro", "A", "B"})
public class HelloServiceImpl implements HelloService {
    // ...
}

这样只有当pro、A、B者三个profile都激活的时候才会启用:

spring:
  profiles:
    active: pro,A,B

扩展开来,控制对象的加载的注解父类为@Conditional,使用该注解的话要自己编写一个类实现org.springframework.context.annotation.Condition来进行处理。
spring-boot提供了多个已经实现好的注解可以用,@Profile只是其中一个,其他类似的还有@ConditionalOnBean@ConditionalOnClass@ConditionalOnExpression@ConditionalOnJava@ConditionalOnProperty等。

ufw 全称 Uncomplicated Firewall ,从名称来看,不那么复杂的防火墙?。

提到linux的防火墙管理,就不得不提iptables,但是说实话,这个命令我实在记不住,用得少,同时参数多,比较复杂。
ufw就是用来解决这个问题的,他算是iptables的一个前端(frontend)。

## 安装ufw
在Debian系的电脑上直接执行以下命令:

   $ sudo apt-get update
   $ sudo apt-get install ufw

启用ufw

    $ sudo ufw enable

禁用ufw

    $ sudo ufw disable

查看默认规则

    $ grep 'DEFAULT_' /etc/default/ufw

Outputs:

DEFAULT_INPUT_POLICY="DROP"
DEFAULT_OUTPUT_POLICY="ACCEPT"
DEFAULT_FORWARD_POLICY="DROP"
DEFAULT_APPLICATION_POLICY="SKIP"

设置默认值

    ## 禁止所有传入,允许所有传出
    $ sudo ufw default allow outgoing
    $ sudo ufw default deny incoming

查看ufw的状态

    $ sudo ufw status
    $ sudo ufw status numbered

打开端口

    ## 打开12345端口,允许tcp协议和udp协议
    $ sudo ufw allow 12345

    ## 打开12345端口,允许tcp协议
    $ sudo ufw allow 12345/tcp

    ## 打开12345端口,允许udp协议
    $ sudo ufw allow 12345/udp

    ## 指定方向,in即传入,out即传出
    ## 如果不指定方向,默认是传入
    $ sudo ufw allow in 12345/tcp
    $ sudo ufw allow out 12345/tcp

关闭端口

    ## 禁止80端口
    $ sudo deny 80/tcp

打开或关闭连续端口

    ## 打开3000到5000之间的所有端口
    $ sudo ufw allow 3000:5000/tcp
    $ sudo ufw allow 3000:5000/udp

对ip做限制

    ## 允许指定ip访问指定端口
    $ sudo ufw allow from 1.2.3.4 to any port 443
    $ sudo ufw allow from 1.2.3.4 to any port 80
    ## 允许子网
    $ sudo ufw allow from 1.2.3.4/23 to any port 443
    $ sudo ufw allow from 1.2.3.4/23 to any port 80

    ## 禁止某ip的所有连接
    $ sudo ufw deny from 1.2.3.4
    ## 禁止子网
    $ sudo ufw deny from 1.2.3.4/24
    ## 禁止ip使用tcp协议访问某个端口
    $ sudo ufw deny from 1.2.3.4 to any port 22 proto tcp

删除操作

    $ sudo delete deny 80/tcp

重置

    $ sudo ufw reset   

重新加载

    $ sudo ufw reload

查看日志

    $ sudo tail -f /var/log/ufw.log

在使用RPC过程中,经常会调用多个RPC服务来获取数据。

比如获取用户个人主页的时候,就要去用户服务获取用户的头像、昵称等基本信息,还要去访问服务获取用户最近访问的信息,还有去关系服务获取用户新增的粉丝或关注的主播的消息。

值得注意的是,这些服务之间并没有依赖,即并不需要先获取用户的头像才能获取用户的访问信息。

如果一个一个地调用这些RPC服务,那么消耗的总时间就是这些RPC调用耗时之和。

因为这些服务之间并没有依赖,所以可以并行地调用,那么消耗的总时间就是耗时最长的那个RPC调用的时间。特别是当调用的RPC服务众多时,并且调用可以大幅度减少时间,提高效率。

如何并行调用呢?

采用线程池和Future就可以,样例如下。
进行两个计算任务,每个需要耗时3秒,如果按照往常调用,那么总共需要6秒时间。但如果并行调用,只需3秒。

import java.time.LocalDateTime;
import java.util.concurrent.*;

public class FutureTest {

    public static void main(String[] args) throws ExecutionException, InterruptedException, TimeoutException {


        ExecutorService executorService =
                Executors.newFixedThreadPool(4);

        Callable<Integer> calculateA = new SumCalculateTask(3, 4);
        Callable<Integer> calculateB = new SumCalculateTask(4, 6);

        System.out.println("START AT " + LocalDateTime.now());
        Future<Integer> futureA = executorService.submit(calculateA);
        Future<Integer> futureB = executorService.submit(calculateB);

        Integer resultA = futureA.get(4, TimeUnit.SECONDS);
        System.out.println(resultA);
        Integer resultB = futureB.get(4, TimeUnit.SECONDS);
        System.out.println(resultB);

        System.out.println("END AT " + LocalDateTime.now());
        executorService.shutdown();
    }


    static class SumCalculateTask implements Callable<Integer> {

        private Integer a;
        private Integer b;

        public SumCalculateTask(Integer a, Integer b) {
            this.a = a;
            this.b = b;
        }

        @Override
        public Integer call() throws Exception {
            Thread.sleep(3000);
            return a + b;
        }
    }
}

Github源码示例:https://github.com/chengjf/java-snippet/blob/master/src/main/java/com/chengjf/future/ConcurrentCalculatorTest.java

其实我自己一直想搭建这么一个工具,可以放一些常用的小工具,比如Json字符串美化,亦或者是查询今日天气,更或者是Base64之类的编解码。

最初我的想法是整一个客户端出来,那时候我看了AWT、Swing,后面有了JavaFX,但这个东西写起来实在麻烦就放弃了。

接下来想用Android来整,有了这个项目SharpPM25SharpWeather,但后来实在觉得丑,也放弃了。

也用Python写过一个,database-interface-doc-management,用的是flask和emberjs。

也用Go写过一个,mymoney

但是都好景不长,基本上是写了一个能跑起来的demo后就没管了。

最近工作时,又发现了经常使用这些东西,特别是查看Json。所以这个想法又涌现出来了。
我基本上是非常不愿意写前端代码的,那些样式、兼容性之类的东西使我很烦。所以我找了一个框架vaadin来写第一版的helper,先用的是vaadin10。但是这个vaadin10太新了,以至于safari和ie的支持都不算太好,我跑起来后就放弃了。

接下来有了这个helper-vue,使用spring-boot和vue。这个spring-boot就是现在工作使用的,vue以前就写过一点。这样项目就搭建起来了,虽然页面样式什么的丑了一点,但是不在乎么,只希望以后不要荒废这个项目。

所以我开了个子域名https://helper.chengjf.com给这个项目。