Live templete - IDEA注释规范

类注释:
className - className()
date - date()
time - time()

1
2
3
4
5
6
/**
* <p>Title: $className$.$END$ </p>
* <p>Description TODO </p>
* @author dragon
* @date $date$ $time$
*/

方法注释:
methodName - methodName()
param - methodParameters
date - date()
time - time()
return - methodRetureType()

1
2
3
4
5
6
7
8
/**
* <p>Title: $methodName$.$END$ </p>
* <p>Description </p>
* @param $param$
* @author dragon
* @date $date$ $time$
* @return $return$
*/

Service手动回滚事务

很多业务场景下,可以使用自动回滚事务。
如在一个Service中,可以使用注解形式整体回滚事务。

1
2
3
4
5
6
7
8
9
10
@Transactional(rollbackFor = Exception.class)
public Boolean methodName() {
boolean flag = true;
if (flag) {
// 处理业务
} else {
throw new RuntimeException("xxx");
}
return flag;
}

但也可能遇到如果对外提供API方法(RPC)需要捕获异常的处理业务的话,对于接口调用方仅需要知道错误信息即可,无需了解堆栈信息,此时try-catch后可以手动回滚事务。

1
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();

1
2
3
4
5
6
7
8
9
10
11
@Transactional
public Boolean methodName() {
boolean flag = true;
try {
// 处理业务
} catch(Exception e) {
// log
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}
return flag;
}

线程池中Feture使用

最近遇到一个业务场景:
在导出Excel的时候、Service查询数据库数据返回List集合,数据量很大,在请求完数据以后还需要遍历调用其他中心RPC服务,这种业务场景下无法完成,超时等在所难免。
考虑到多线程处理业务。
顺便提一下……真的很难受,大数据量分片查询ES本来就很慢,真心很无奈。

Futrue:对于多线程来说,可以先拿到一个未来的Future,等所有分支取到结果后在组合数据。阻塞线程。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
Vector<Map<String,Object>> dataList = new Vector<>();
// 按照业务场景自定义分页大小
int pageSize = 1000;
// 按照CPU核心数自定义线程大小
int processor = 1 << 3;
ExecutorService executorService = new ThreadPoolExecutor(processor, processor, 1000, TimeUnit.MILLISECONDS, new LinkedBlockingDeque(),
new ThreadFactoryBuilder().setNameFormat("package-task-%d").build());
try {
// 选择分页方式查询
int totalPage = (total % pageSize == 0) ? (total / pageSize) : (total / pageSize) + 1;
List<Future<List<Map<String, Object>>>> futures = new ArrayList<>();
for (int i = 1; i <= totalPage; i++) {
final int page = i;
Future<List<Map<String, Object>>> task = executorService.submit(() -> {
PageResult<Map<String, Object>> result = XXX;
List<Map<String, Object>> listData = result.getListData();
return listData;
});
futures.add(task);
}
for (Future<List<Map<String, Object>>> future : futures) {
dataList.addAll(future.get());
}
executorService.shutdown();
} catch (Exception e) {
executorService.shutdown();
return Collections.emptyList();
}

future.get方法:获取计算结果(如果还没计算完,也是必须等待的)

future.cancel方法:还没计算完,可以取消计算过程

future.isDone方法:判断是否计算完

future.isCancelled方法:判断计算是否被取消

真真正正第一次的GitHub开源之旅

Emmm,坚持GitHub的旅行也快到一年了,通过这个‘同性交友’的网站真的学到了很多知识,不仅仅是技术上的积累,还有那许许多多开拓眼界的项目。

划重点

RSSHub是我参与的一个开源项目,介绍请看项目链接哦~虽然仅仅提交了一个分支,但这份参与感,这份点滴积累让我收益很多。

从中学习到了什么?

每一位对代码质量有着‘洁癖’的开发者们让你体会到了哪怕一个小事也要做到最好。开发思想在慢慢的积累到未来的成熟。对待每一个项目的了解程度都会影响到项目的发展和未来的规划。

上面这些可能目前自己用的少(其实有些用不到)但是我相信未来的开源路上会用到他们的。

虽然参与的路上遇到了一些小坎坷,但看到了最后的结果!相信自己可以做好。
image

未来的路,继续加油!(勿忘初心:走的久了,不要忘记自己为什么出发)

什么是@PostConstruct,@PreDestroy注解

首先这两个注解是在JDK1.5增加的,注解@PostConstruct允许在Bean初始化之前执行一些方法,而@PreDestroy是在Bean销毁之前执行的操作。

@PostConstruct(@PreDestroy):被@PostConstruct修饰的方法会在服务器加载Servlet(Bean)的时候运行,并且只会被服务器调用一次。

生命周期如下:

1
2
3
4
5
graph LR
PostConstruct-->init
init-->some-methods
some-methods-->destory
destory-->PreDestroy

例如如下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
/**
* <p>Title: RegistryCenterConfig. </p>
* <p>Description 调度作业,Zookeeper配置(ZK集群配置) </p>
*
* @author dragon
* @date 2018/5/7 上午11:08
*/
@Configuration
@ConditionalOnClass(ElasticJob.class)
@ConditionalOnBean(annotation = MarkElasticJob.class)
@EnableConfigurationProperties(ZookeeperRegistryProperties.class)
@ConditionalOnExpression("'${elaticjob.zookeeper.server-lists}'.length() > 0")
public class RegistryCenterConfig {
private final ZookeeperRegistryProperties regCenterProperties;
@Autowired
public RegistryCenterConfig(ZookeeperRegistryProperties regCenterProperties) {
this.regCenterProperties = regCenterProperties;
}
/**
* <p>Title: regCenter. </p>
* <p>初始化配置中心 </p>
*
* @param serverList 服务列表
* @param namespace 名称
* 注意,在console上配置注册中心时,需要注意:
* 注册中心名称和命名空间->需要和namespace保持一致
*/
@Bean(initMethod = "init")
public ZookeeperRegistryCenter regCenter(@Value("${elaticjob.zookeeper.server-lists}") final String serverList,
@Value("${elaticjob.zookeeper.namespace}") final String namespace) {
ZookeeperConfiguration zookeeperConfiguration = new ZookeeperConfiguration(serverList, namespace);
zookeeperConfiguration.setBaseSleepTimeMilliseconds(regCenterProperties.getBaseSleepTimeMilliseconds());
zookeeperConfiguration.setConnectionTimeoutMilliseconds(regCenterProperties.getConnectionTimeoutMilliseconds());
zookeeperConfiguration.setMaxSleepTimeMilliseconds(regCenterProperties.getMaxSleepTimeMilliseconds());
zookeeperConfiguration.setSessionTimeoutMilliseconds(regCenterProperties.getSessionTimeoutMilliseconds());
zookeeperConfiguration.setMaxRetries(regCenterProperties.getMaxRetries());
zookeeperConfiguration.setDigest(regCenterProperties.getDigest());
return new ZookeeperRegistryCenter(zookeeperConfiguration);
}
/**
* <p>Title: ElasticJobConfig. </p>
* <p>在初始化Zookeeper前,注入Elastic-Job,自动扫描开放任务 </p>
*
* @author dragon
* @date 2018/5/9 下午2:35
*/
@PostConstruct
public ElasticJobConfig initElasticJob() {
return new ElasticJobConfig();
}
@PreDestroy
public void preDestoryMethod() {
System.out.println("preDestoryMethod...");
}
}

对于如上代码,应用场景是elastic-job + zk 的启动方式,需要在zk启动前,先扫描Jobs,然后在执行Zk的init方法。

运行如下:

1
2
3
4
5
graph LR
RegistryCenterConfig-->ElasticJobConfig
ElasticJobConfig-->Autowired-RegistryCenterConfig
Autowired-RegistryCenterConfig-->init(regCenter)
init(regCenter)-->preDestoryMethod

Druid连接池配置连接属性utf8mb4

由于在配置了MySQL数据库,表的编码类型为utf8mb4以后需要重新启动数据库,可由于线上场景的等一些问题的影响,可用过druid设置编码方式。从而让emoji表情可以保存。😈

1
2
3
4
// 配置druid支持表情
String connectionInitSqls = "SET NAMES utf8mb4";
StringTokenizer tokenizer = new StringTokenizer(connectionInitSqls, ";");
druidDataSource.setConnectionInitSqls(Collections.list(tokenizer));

聊聊我的域名史

最近很想收集几个有意义的域名哎…

谈一谈我的域名史吧…

在大学时期,我申请的第一个域名是idragonyuan.com,因为名字很长所以我就换了目前主站使用的dragon-yuan.me域名,但是真的很喜欢dragon.me这个域名,但是可爱的他貌似在一位米农的手中,而且我也不知道从他人手中购买域名的流程是什么,但这个域名肯定好贵好贵的哎。于是在去年的时候moe域名出现了,还是老样子喽,想入手一个dragon.moe发现已经有人提前注册了,无奈之下只好注册了一个loong.moe,我也叫他萌龙。

最近也在想一些好一点的域名,有收藏意义,可能未来还会有商业价值的说呢!