Friday, August 14, 2020

The note about Java 8 Parallel Streams vs ExecutorService

 The Java 8 parallel streams look neat, compact and easy, however, it has limitations you cannot specify the thread number or thread pool.

I did a comparison using the two implementations, I have a list of stock code, and need access the URL to get the name for the code list (3470 code).

For serial retrieval, it needs 900+ seconds.

For parallel streams retrieval, it spends 138 seconds.

For ExecutorService, it spends 45 seconds for 20 threads, 18 seconds for 50 threads, and 5.75 seconds for 200 threads.

//from 900+ seconds to 138 seconds for parallelStream
List<Code> codeList = codeStringList.parallelStream().map( (code)->{
String name = null;
try {
name = SinaDataProvider.getName(code);
} catch (IOException e) {
logger.error("Fatal error to get name for "+code+","+e.getMessage());
e.printStackTrace();
}
logger.debug(code+","+name);
Code codeObj = new Code();
codeObj.setCode(code);
//remove blank space from name
codeObj.setName(name.replaceAll("\\s",""));
codeObj.setStart_time(yyyyMMdd);
codeObj.setEnd_time("");
return codeObj;
}).collect(Collectors.toList());
//45 seconds for 20 threads for ExecutorService 
//18 seconds for 50 threads
//5.75 seconds for 200 threads
ExecutorService executor = Executors.newFixedThreadPool(200);
Collection<Future<Code>> futures = new LinkedList<Future<Code>>();
for(String code:codeStringList){
futures.add(
executor.submit(()->{
String name = null;
try {
name = SinaDataProvider.getName(code);
} catch (IOException e) {
logger.error("Fatal error to get name for "+code+","+e.getMessage());
e.printStackTrace();
}
logger.debug(code+","+name);
Code codeObj = new Code();
codeObj.setCode(code);
//remove blank space from name
codeObj.setName(name.replaceAll("\\s",""));
codeObj.setStart_time(yyyyMMdd);
codeObj.setEnd_time("");
return codeObj;
}));
};
List<Code> codeList = new ArrayList<>();
for (Future<Code> future : futures) {
try {
Code codeObj = future.get();
codeList.add(codeObj);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
executor.shutdown();

Thursday, August 13, 2020

Nice email

 CEO sends a really nice email

In many ways, the pandemic has changed how we interact with one another – a plastic divider separates us from our colleagues, a mask covers our friendly smile as we greet customers, and many in-person meetings have moved online. And yet, despite this physical distance, our XX family is closer than ever. We are standing together by standing apart – and standing tall – as we demonstrate compassion and understanding in the face of hardship, each in our own way.

Monday, August 10, 2020

Mongodb Auspix note

 db.stock.getIndexes();

db.stock.createIndex({"code":1}); 

db.stock.createIndex({"time":1});

db.stock.find( { $and: [ {"code":"SH1A0001"},{"time":{$lte:"20191231 15:00"}}]} ).sort({"time":-1}).limit(1).pretty();

db.stock.distinct("code").length

db.code.find({start_time:{$ne:20200810}}).pretty()


db.stock.find({code:"SH000001"}).sort({time:1}).limit(3).pretty();


db.code.find({end_time:{$ne:""}}).pretty()

db.code.find({$and:[{code:"SH603277"},{end_time:{$ne:""}}]}).pretty()

--sort and limit, need use match

db.stock.aggregate([

{$match:{code:"SH000001"}},

    {"$sort": {"time":-1}},

    {"$limit": 5},

    {"$sort": {"time": 1}}

]).pretty()


--sort and limit

db.stock.aggregate([

{$match:{ $and: [{code:"SH000001"},{time:{$lte:"20200810 15:00"}}] }},

    {"$sort": {"time":-1}},

    {"$limit": 5},

    {"$sort": {"time": 1}}

]).pretty()

The Java implementation:

public List<Stock> getStockList(String code,String timeStr) throws JsonProcessingException {
List<Stock> stockList = new ArrayList<>();
MongoCollection<Document> stockCollection = mongoTemplate.getCollection(stockColName);
AggregateIterable<Document> stockAgg = stockCollection.aggregate(Arrays.asList(match(Filters.and(Filters.eq("code",code),Filters.lte("time",timeStr))),
sort(Sorts.descending("time")),
limit(379),
sort(Sorts.ascending("time"))));
ObjectMapper objectMapper = new ObjectMapper();
for(Document doc:stockAgg){
doc.remove("_id");
Stock stock = objectMapper.readValue(doc.toJson(),Stock.class);
stockList.add(stock);
logger.debug("stock==="+stock);
}
return stockList;
}


distinct multiple fields are pretty not straightforward and not efficient:

both below are not what I expect


db.stock.aggregate( 

[

{"$group": { "_id": { code: "$code", name: "$name" } } }

]

)


db.stock.aggregate([

{$group: {

    _id: null,

    code: {$addToSet: '$code'},

    name: {$addToSet: '$name'}

    }}

])

Saturday, July 11, 2020

spring boot note


spring-boot-starter-test:测试模块,包括JUnit、Hamcrest、Mockito
'Hamcrest' is an anagram of 'matchers' allowing match rules to be defined declaratively.These matchers have uses in unit testing frameworks such as JUnit and jMock. Hamcrest has been included in JUnit 4 since 2012, but was omitted from Junit 5 in 2017.

虽然,Spring Boot中实现了默认的error映射,但是在实际应用中,错误页面对用户来说并不够友好,我们通常需要去实现我们自己的异常提示。
创建全局异常处理类:通过使用@ControllerAdvice定义统一的异常处理类,而不是在每个Controller中逐个定义。@ExceptionHandler用来定义函数针对的异常类型,最后将Exception对象和请求URL映射到error.html中


Spring Boot 2.2.6.RELEASE原理剖析

https://blog.csdn.net/zhaodongchao1992/article/details/105215849

https://blog.csdn.net/weixin_43570367/article/details/104960677

By default, all sensitive endpoints added by actuator are secured. This includes ‘/refresh' endpoint. For simplicity, we will turn off security by updating bootstrap.properties:
management.security.enabled=falseAdditionally, starting with Spring Boot 2, actuator endpoints are not exposed by default. To make them available for access, we need to add this in an application.yml:management:
endpoints:
web:
exposure:
include: "*"
Let's start the client first and update user role from existing ‘Developer' to ‘Programmer' in the properties file on GitHub. Config server will show updated values straight away; however, the client won't. To make client see new files we just need to send an empty POST request to ‘/refresh' endpoint, which was added by actuator:
$> curl -X POST http://localhost:8080/actuator/refreshWe will get JSON file back showing updated properties:[
  "user.role"
]The user role was updated successfully and by calling ‘/refresh' endpoint. Client updated configuration without restarting.
By using Actuator, we can refresh clients. However, in the cloud environment, we would need to go to every single client and reload configuration by accessing actuator endpoint.To solve this problem, we can use Spring Cloud Bus.
By using Actuator, we can refresh clients. However, in the cloud environment, we would need to go to every single client and reload configuration by accessing actuator endpoint.
To solve this problem, we can use Spring Cloud Bus.
Now, the client will have another endpoint ‘/bus-refresh'. Calling this endpoint will cause:
  • get the latest configuration from the config server and update its configuration annotated by @RefreshScope
  • send a message to AMQP exchange informing about refresh event
  • all subscribed nodes will update their configuration as well
This way, we don't need to go to individual nodes and trigger configuration update.
We will use spring-cloud-config-monitor to monitor configuration changes and broadcast events using RabbitMQ as transport.

Customizing the Management Endpoint Paths

You can use the management.endpoints.web.base-path property to change the prefix for your management endpoint, as shown in the following example:
management.endpoints.web.base-path=/manage
spring.datasource.driver-class-name=oracle.jdbc.OracleDriver spring.datasource.type=oracle.jdbc.pool.OracleDataSource

System.out.println(jdbcTemplate.getDataSource().getConnection());
will print oracle.jdbc.driver.T4CConnection instead of HikariProxyConnection

JSR-303 Bean Validation

JSR-303 是 JAVA EE 6 中的一项子规范,叫做 Bean Validation,官方的参考实现是Hibernate Validator。需要注意的是此实现与 Hibernate ORM 没有任何关系。JSR 303 用于对 Java Bean 中的字段的值进行合法性验证。

默认springboot集成了 hibernate-validator,而且默认是生效的,可以直接使用。默认不支持基础类型的验证,必须配置拦截器MethodValidationPostProcessor,在Controller类上加 @Validated注解可以实现对方法参数的校验。而且默认只验证 controller 方法上的 validator 注解,而不会验证 controller 层以外的。所以,如果要在其他层使用 validator 验证的话,需要单独配置拦截器.

这里可能你产生了疑问,如果校验失败我们怎么办?不知道你是否了解springboot 统一异常处理

(通过@ControllerAdvice 声明一个全局异常类)我们可以通过统一拦截处理校验异常把上面注解中的的message信息返回给前端。值得注意的是,如果你前台传入的参数不在body中,校验失败抛出BindException异常,如果接口方法的参数有@RequstBody 注解,即参数放在body中传输,会抛出MethodArgumentNotValidException 异常,分别加以处理即可。

如果上面的不满足需要,我们还可以对hibernate-validator 进行扩展,甚至可以实现fail-fast 机制(当有错误时剩下的都不再进行校验立即失败)。


Tuesday, July 7, 2020

Kafka


1.
Kafka uses ZooKeeper so you need to first start a ZooKeeper server if you don't already have one.
Kafka comes with a command line client that will take input from a file or from standard input and send it out as messages to the Kafka cluster.
The broker.id property is the unique and permanent name of each node in the cluster. 
2.
Kafka Streams is a client library for building mission-critical real-time applications and microservices, where the input and/or output data is stored in Kafka clusters.

Saturday, July 4, 2020

IntelliJ IDEA


IntelliJ IDEA
1. For the JUnit test, the class must be public, or there's no context to run it. IntelliJ also requires the test methods are public. However, by default when Eclipse creates the JUnit test cases, the class is not public, the methods are not public either.
2. Community version "Terminal" works perfect, however in the company Ultimate version "Terminal" doesn't work, even if IntelliJ is started with administrator.
3. IntelliJ occupies much more memories, for one single Project, the memory usage is over 1G, Eclipse only uses 200 M for the same Project
4. IntelliJ doesn't have the work space concept?