记一次parallelStream错误使用导致的NullPointerException

parallelStream

在 Java8 中,新增了一个很有用的功能就是 ,这个功能可以使我们可以快速的写出优雅的代码,其中 stream 是一个串行流(说法可能有误…就是不会采取多线程来进行处理)。还有一种就是 parallelStream 采用 ForkJoinPool 来实现并发,加快执行效率。

所以在使用 parallelStream 的时候一定要注意线程安全的问题,首先看一段代码:

在这段代码中,是首先判断 dataListList 里面对象的 name 属性是否是偶数,是的话则添加至偶数List,反之则添加至奇数List。

然后开始测试这段代码:

阅读更多

WeakHashMap的实现原理

简介

什么是WeakHashMap

WeakHashMap实现了 Map 接口,属于 Java 集合中的一员,其用法几乎和 HashMap 一致,但是由于它的 Entry 还继承了 WeakHashMap ,因此导致它的这个 Entry 在触发 FullGc 的时候是有可能可以被回收的。

以下测试,JVM参数统一为:-Xmx64M -Xms64M -XX:+PrintGCDetails

首先上一段代码:

阅读更多

代理模式之JDK为什么需要实现接口(下篇)

前言

在上篇主要介绍了 JDK 动态代理执行的一些流程,通过 Proxy 类来实现生成新的代理类,在这一篇主要讲的是 Proxy 是如何来生成以及缓存生成的代理类

二级缓存

在上一篇的结尾提到过了一个map,其结构如下:

ConcurrentMap<Object, ConcurrentMap<Object, Supplier>>

阅读更多

代理模式之JDK为什么需要实现接口(上篇)

简介

首先代理模式分为静态代理和动态代理,由于JDK采用的是动态代理,所以静态代理在这里不再介绍。

动态代理

JDK动态代理

首先JDK的动态代理要求真实的对象必须实现一个接口,而代理类则实现InvocationHandler接口来完成动态代理。如下代码:

阅读更多

重温Java中String

本文的内容都是基于 JDK1.8 来写的,主要是复习下 String 类的设计。

简介

String 是一个用于存储字符串的类,其内部是通过 char 数组来实现,在 Java 中,1byte = 8bit,1char = 2byte, 所以在 Java 中,String 的code point是16位。
String 类是由 final 关键字来修饰的,因此表明该类不可以被继承,同时 String 又实现了 Serializable、Comparable、CharSequence接口,表明 String 可以被序列化,以及使用cpmpareTo来比较两个字符串的值。

字符集编码

内码

阅读更多

SpringBoot中异步线程的处理

在工作或者学习的时候,我们都会接触到异步编程,大多数情况下都是通过新建一个线程池,然后调用submit方法或者execute方法来执行。如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public void simpleThreadPool(){
ExecutorService executor = new ThreadPoolExecutor(4,5,0, TimeUnit.SECONDS,new LinkedBlockingDeque<Runnable>());
executor.execute(new Runnable() {
@Override
public void run() {
System.out.println("run");
}
});
Callable<String> callable = new Callable<String>() {
@Override
public String call() throws Exception {
return "callable";
}
};
Future future = executor.submit(callable);
System.out.println(future.get());
}

在Springboot中其实也可以这样做,但是不利于后期的维护,加入后期需要把 runable 的方法修改为同步类型的,那么此时就需要大量的改动代码,如果说很多地方都用到的了的话,就会很容易漏掉了一处导致bug的产生。

Spring的解决方法

不需要返回值的异步

阅读更多

ES7中大小写不敏感的模糊匹配

在ES7.0中

如果要实现大小写的模糊查询,则首先必须要自定义 analysis,在自定义的 analysis 里面,如果是针对keyword类型的字段, analysis 要定义成 normalizer,而对于text类型的话,则需要为analyzer。如下演示的是normalizer类型的定义。

新建索引

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
{
"settings": {
"analysis": {
"normalizer": {
"self_normalizer": {
"type": "custom",
"char_filter": [],
"filter": [
"lowercase",
"asciifolding"
]
}
}
}
},
"mappings":{
"properties":{
"field_1":{
"type":"keyword",
"normalizer": "self_normalizer"
}
}
}
}

此时向ES中新增几条数据:

阅读更多

springboot多数据源-sqlSessionFactory

在SpringBoot中,动态的切换数据源的方式有两种,一种是通过AbstractRoutingDataSource来通过注解实现,另一种则是通过配置不同的SqlSessionFactory来读取不同文件夹的mapper,从而实现多数据源。
代码如下:

DataSourceOneConfig

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
@Configuration
@MapperScan(basePackages = {"xyz.somersames.dao.one"} ,sqlSessionTemplateRef = "dataSourceOneSqlSessionTemplate")
public class DataSourceOneConfig {

@Primary
@Bean(name = "dataSourceOneT")
// 这里后面加一个T是防止Spring出现skiped mapperFactoryBean 错误,导致无法注入
@ConfigurationProperties(prefix = "spring.datasource.one")
public DataSource getDataSource(){
return new DruidDataSource();
}

@Primary
@Bean(name = "dataSourceOneSqlSessionFactory")
public SqlSessionFactory setSqlSessionFactory(@Qualifier("dataSourceOneT") DataSource dataSource) throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(dataSource);
bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mapper/one/*.xml"));
return bean.getObject();
}

@Primary
@Bean(name = "dataSourceOneTransactionManager")
public DataSourceTransactionManager setTransactionManager(@Qualifier("dataSourceOneT") DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}

@Primary
@Bean(name = "dataSourceOneSqlSessionTemplate")
public SqlSessionTemplate setSqlSessionTemplate(@Qualifier("dataSourceOneSqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {
return new SqlSessionTemplate(sqlSessionFactory);
}
}

DataSourceTwoConfig

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
@Configuration
@MapperScan(basePackages = {"xyz.somersames.dao.two"} ,sqlSessionTemplateRef = "dataSourceTwoSqlSessionTemplate")
public class DataSourceTwoConfig {

@Bean(name = "dataSourceTwoT")
// 这里后面加一个T是防止Spring出现skiped mapperFactoryBean 错误,导致无法注入
@ConfigurationProperties(prefix = "spring.datasource.two")
public DataSource getDataSource(){
return new DruidDataSource();
}

@Bean(name = "dataSourceTwoSqlSessionFactory")
public SqlSessionFactory setSqlSessionFactory(@Qualifier("dataSourceTwoT") DataSource dataSource) throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(dataSource);
bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mapper/two/*.xml"));
return bean.getObject();
}

@Bean(name = "dataSourceTwoTransactionManager")
public DataSourceTransactionManager setTransactionManager(@Qualifier("dataSourceTwoT") DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}

@Bean(name = "dataSourceTwoSqlSessionTemplate")
public SqlSessionTemplate setSqlSessionTemplate(@Qualifier("dataSourceTwoSqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {
return new SqlSessionTemplate(sqlSessionFactory);
}
}

阅读更多

SpringBoot2.x是怎样只初始化LettuceConnectionFactory的呢

SpringBoot1.5使用Redis和2.x的区别

在 SpringBoot1.5 的版本的时候,如果要创建一个 RedisTemplate 的话,那么可以直接使用如下代码:

1
2
3
4
5
6
7
@Bean
public RedisTemplate<String,Object> redisTemplate(JedisConnectionFactory jedisConnectionFactory){
RedisTemplate<String,Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(jedisConnectionFactory);
// 添加序列化代码
return redisTemplate;
}

然后在业务类中直接通过 @Autowired 注解来调用 redisTemplate,但是如果将 SpringBoot1.5 升级到 2.0 之后,你会发现这样写的话,SpringBoot 启动的时候会报错。报错内容如下:

1
2
3
4
5
The following candidates were found but could not be injected:
- Bean method 'redisConnectionFactory' in 'JedisConnectionConfiguration' not loaded because @ConditionalOnBean (types: org.springframework.data.redis.connection.RedisConnectionFactory; SearchStrategy: all) found beans of type 'org.springframework.data.redis.connection.RedisConnectionFactory' redisConnectionFactory

Consider revisiting the entries above or defining a bean of type 'org.springframework.data.redis.connection.jedis.JedisConnectionFactory' in your configuration.

阅读更多

浅谈工厂模式

简介

工厂模式解决的是频繁的修改某一些 new 操作,隐藏真实的创建过程,方便以后更加快速的新增和扩展,简单来说就是维护一类关系。

简单工厂:

把对象的创建放到一个Util中,通过不同的入参来创建不同的类。这也是日常编码中经常用到的,不过缺点就是每次新增一个类的时候,都需要修改if/else判断,有点繁琐。

工厂方法:

阅读更多