0%

扩展点加载机制主要是为了实现接口和实现的解耦,接口的具体实现并不在代码中指定,而是通过通过外部配置实现,Dubbo的扩展点加载是对JDK的SPI扩展点加强而来,大家如果不了解JDK的SPI也没有关系,这里我们主要来看一下Dubbo的实现

在Dubbo的实现中,主要有三个注解,@SPI@Adaptive@Activate,下面我们来结合例子分别看一下它们的使用

阅读全文 »

线程池的基本使用

Executors框架提供的创建线程池的方法

1
2
3
4
5
6
// 固定线程数量的线程池
Executors.newFixedThreadPool(5);
// 对于添加的任务,如果有线程可用则使用其执行,否则就创建新线程
Executors.newCachedThreadPool();
// 创建只有一个线程的线程池
Executors.newSingleThreadExecutor();

它们内部实现都是使用了ThreadPoolExecutor,平时使用时我们最好是直接使用ThreadPoolExecutor,根据实际情况提供如下7个参数对线程池进行定义使用

配置参数

1
2
3
4
5
6
7
int corePoolSize,                     // 核心线程数
int maximumPoolSize, // 最大线程数
long keepAliveTime, // 超出核心数线程的最大空闲存活时间
TimeUnit unit, // 空闲存活时间的时间单位
BlockingQueue<Runnable> workQueue, // 任务队列
ThreadFactory threadFactory, // 线程工厂,可以在此设置线程是否为守护线程等
RejectedExecutionHandler handler // 饱和策略,任务队列满且线程数达到最大线程数时触发
阅读全文 »

在介绍状态模式之前,我们先看个简单的例子

比如我们正常的网上购物的订单,对于订单它有许多个不同的状态,在不同状态下会有不同的行为能力,如状态有待支付、已支付待发货、待收货、订单完成等等,在整个订单流转过程中,由不同的事件行为导致它状态的变更,可以看下它简单的状态图

order-state

这些状态虽然不同,但是都是属于订单的状态,对应的行为也是订单的行为,在编码的过程中,一种写法是将这些行为(方法)都写到订单这个类或者类似OrderService这种类中,如

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class OrderService {
private OrderDao orderDao;

public void pay(Long orderId) {
Order order = orderDao.findById(orderId);
// 下面逻辑也可以改成使用switch
if (order.getStatus() == OrderStatus.WAIT_PAY) {
// 待支付,则进行支付
} else if (order.getStatus() == OrderStatus.PAYING) {
// 支付中,则进行相应提示
} else if (order.getStatus() == OrderStauts.PART_PAID) {
// 部分支付,则进行相应处理
} else {
// 其他状态进行对应处理
}
}
}

这样每次进行操作时,我们要先进行一下当前状态的判断,如用户支付时,我们要判断一下当前订单的状态,如果是待支付,则进行支付操作后,将状态改为已支付;如果当前状态是已支付时,就要提示用户当前订单已支付,不能再次支付等等,如果订单状态比较复杂时就会导致这个类中充斥大量的ifswitch等判断逻辑,维护不便

而状态模式则提供了另一种解决方案,它将与特定状态相关的行为局部化,也使得状态转换现实化,下面我我们来具体看一下

阅读全文 »

Drools是一款基于Java语言的开源规则引擎,通过drools特定的语法,将复杂多变的业务规则统一管理。

环境配置

一、使用maven创建项目

添加相关依赖,pom.xml如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?xml version="1.0" encoding="UTF-8"?>
<project ...>
<packaging>kjar</packaging>

<dependencies>
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-compiler</artifactId>
<version>7.27.0.Final</version>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.kie</groupId>
<artifactId>kie-maven-plugin</artifactId>
<version>7.27.0.Final</version>
<extensions>true</extensions>
</plugin>
</plugins>
</build>

</project>
阅读全文 »

在Redis中,相同的数据,如果我们使用不同的数据结构来存储,它们使用的内存大小差异可能是非常大的,要想更多的节省空间,我们不仅仅需要了解Redis的几种常用数据类型,还需要了解他们内部在不同情况下使用的具体数据结构

之前曾整理过一篇Redis每种数据类型及对应的内部结构,如果对此不太了解的同学可以先大致看一下

压缩数据结构

Redis为hashsetzset都提供了对应的节约空间的数据结构存储方式,合理使用它们可以大大节约内存空间

下面以hash结构举例,其他的结构也是类似的

阅读全文 »

了解Redis通信内容

Redis我们都比较熟悉,可以用来做缓存、分布式锁等,但是,其中的客户端与服务端是如何进行通信的呢?

我们可以分别模拟一个服务端或者客户端,打印查看来自实际连接的请求来获取它们的通信方式

首先,让我们先使用先模拟一个服务端,使用Jedis进行连接查看

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 一个简单的demo
public class MockRedisServer {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(6379);
Socket socket = serverSocket.accept();
try (InputStream inputStream = socket.getInputStream();
final OutputStream outputStream = socket.getOutputStream()) {
byte[] data = new byte[1024];
final int read = inputStream.read(data);
final byte[] bytes = Arrays.copyOf(data, read);
System.out.println(new String(bytes));
}
}
}
阅读全文 »

什么是 Lambda表达式?

对于 Java 中的 lambda 表达式,我们可以把它简单的理解为一个函数。

比如,我们需要这样一个函数,它需要把两个数字相加,将结果返回 则可以这样定义

1
int add(int a, int b);

但是我们知道,Java中函数是没有办法单独定义存在的,所以我们需要一个接口才能声明这个函数功能

1
2
3
interface Function {
int add(int a, int b);
}

当我们需要实现这个方法的时候,一种方法就是定义一个新的类来实现这个接口

1
2
3
4
5
6
class Calc implements Function {
@Override
public int add(int a, int b) {
return a + b;
}
}
阅读全文 »

接着之前说过的 Java HashMap的Rehash,这次我们来看看 Redis中的 hash结构(对应Java中的Map)是如何实现rehash的。

这次先说下结论,它的结构与HashMap基本一致,只是它有两个哈希表,平时只使用其中的第一个,在发生rehash时,会逐渐的将元素转移到另一个表中,全部转移完成后,再将引用赋值给第一个哈希表

下面我们来开始看代码

阅读全文 »

我们都知道Java中的HashMap是使用数组,结合链表来实现的,其结构如下:

如果加入的元素数量达到了设定的阈值,那么必然会涉及到扩容重新分配空间,将元素重新插入到新的空间中,也就是发生了rehash。这个过程其实是很耗时的,这也是为什么我们写代码时,最好指定的HashMap的初始空间大小的原因,就是为了避免或者减少发生rehash的次数。下面我们来看看这个过程的具体实现。

JDK是一直在升级的,其中的代码也在不断优化调整,我们这次主要就看下JDK1.7JDK1.8中的实现

阅读全文 »

这篇来跟踪一下AbstractBeanFactory#getBean(java.lang.String, java.lang.Class<T>)这个方法获取bean实例的流程,由于过程比较复杂,我们这里以一个简单的例子来跟进一下主要的流程

Spring 配置使用

下面我们看下具体的例子代码

spring配置文件

1
2
3
4
5
6
7
8
9
10
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

<bean class="com.zavier.spring.beans.TestBean"
id="testBean" init-method="myinit" destroy-method="mydestroy">
</bean>

</beans>
阅读全文 »