jvm-元空间

基础概念:

  1. 方法区:jvm规范中的定义,指一片内存区域,用于存放加载到内存中的类信息、常量池等。

  2. 永久代:JDK1.7(含)之前方法区的实现方式,使用永久代实现主要是为了把GC分代收集扩展至方法区,省去了专门为方法区编写内存管理代码的工作。

查看更多

SpringCloud-微服务使用入门

传统java编程中如果想要在程序中发起http请求有哪些做法?开源的http工具包有很多,OkHttp、HttpClient、jdk自带的等等,使用这些工具并不方便,需要程序员手动封装一些请求参数,构造请求,手动调用发送请求,处理响应。。。

因此在spring对这些工具类进行了封装,对外只提供RestTemplate类,开发人员使用RestTemplate可以很方便的发送http请求,只需要指定http请求的服务器地址及端口号。

父项目依赖配置:

父项目pom配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<properties>
<spring.boot.version>2.2.0.RELEASE</spring.boot.version>
<spring.cloud.version>Hoxton.RELEASE</spring.cloud.version>
...
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring.boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring.cloud.version}</version>
<scope>import</scope>
<type>pom</type>
</dependency>
</dependencies>
</dependencyManagement>

boot版本号 2.2.x.RELEASE 应当使用的cloud版本序列为Hoxton.RELEASE

查看更多

jvm-对象的内存布局

对象内的布局是:最前面是对象头,有两个VM内部字段:_mark 和 _klass。

后面紧跟着就是对象的所有实例字段,紧凑排布,规则如下:

  • 继承深度越浅的类所声明的字段越靠前,继承深度越深的类所声明的字段越靠后。
  • 在同一个类中声明的字段按字段的类型宽度来重排序,对普通Java类默认的排序是:long/double - 8字节、int/float - 4字节、short/char - 2字节、byte/boolean - 1字节,最后是引用类型字段(4或8字节)。
查看更多

SpringBoot-注解@ConfigurationProperties的正确使用姿势

1. 前言

在编写项目代码时,我们要求更灵活的配置,更好的模块化整合。在 Spring Boot 项目中,为满足以上要求,我们将大量的参数配置在 application.properties 或 application.yml 文件中,通过 @ConfigurationProperties 注解,我们可以方便的获取这些参数值

2. 使用 @ConfigurationProperties 配置模块

假设我们正在搭建一个发送邮件的模块。在本地测试,我们不想该模块真的发送邮件,所以我们需要一个参数来「开关」 disable 这个功能。另外,我们希望为这些邮件配置一个默认的主题,这样,当我们查看邮件收件箱,通过邮件主题可以快速判断出这是测试邮件

在 application.yml文件中创建这些参数:

1
2
3
4
app: 
mail:
enable: true
default-subject: This is a Test

我们可以使用 @Value 注解或着使用 Spring Environment bean 访问这些属性,是这种注入配置方式有时显得很笨重。我们将使用更安全的方式(@ConfigurationProperties )来获取这些属性

查看更多

Mybatis-动态sql

为什么需要动态sql?

我们通常会把多种条件查询放在一个接口中,后端接口不知道前端回会传什么参数,所以要将所有的参数类型考虑在内,执行之前根据传入参数类型动态的生成查询语句。

Mybatis的动态sql是基于ognl表达式的。

动态标签

按照官网的分类,Mybatis的动态标签主要有四类:if,choose(when,otherwise),trim(where,set),foreach

if–用在需要判断的时候,条件写在test中:

查看更多

微信支付-异步回调通知

应用后台调用统一下单接口时需要指定回调的notify_url,微信支付平台执行统一下单后,会调用该url,发送一个异步通知给应用后台,同时后台需要调用查询微信后台这笔订单的支付结果以及金额,这是一个并行操作,需要注意的是微信后台收到的金额和订单金额需要进行比对,为了防止钓鱼,所以这个查询是有必要的,必须匹配:收到的到账金额 >= 订单金额,具体细节参考微信支付开发者文档

好吧,来看一下代码,异步通知地址需要自己配置好,在生成预付单的时候就得传过去,这个地址就是自己的应用后台中的某个rest-controller,如下:

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
@RequestMapping("/notice")
public void notice(HttpServletRequest request, HttpServletResponse response)
throws IOException {
InputStream inStream = request.getInputStream();
ByteArrayOutputStream outSteam = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len = 0;
while ((len = inStream.read(buffer)) != -1) {
outSteam.write(buffer, 0, len);
}
outSteam.close();
inStream.close();
String result = new String(outSteam.toByteArray(), "utf-8");
Map<String, String> map = null;
try {
map = XMLUtil.doXMLParse(result);
} catch (JDOMException e) {
e.printStackTrace();
}

// 此处调用订单查询接口验证是否交易成功
WXOrderQuery wxpayResult = reqOrderQueryResult(map);
boolean isSucc = wxpayResult.isSuccess();

// 支付成功,商户处理后同步返回给微信参数
PrintWriter writer = response.getWriter();
if (!isSucc) {
// 支付失败, 记录流水失败
System.out.println("===============支付失败==============");
} else {
orderService.doWXPayNotice(wxpayResult);
System.out.println("===============付款成功,业务处理完毕==============");

// 通知微信已经收到消息,不要再给我发消息了,否则微信会8连击调用本接口
String noticeStr = setXML("SUCCESS", "");
writer.write(noticeStr);
writer.flush();
}

String noticeStr = setXML("FAIL", "");
writer.write(noticeStr);
writer.flush();
}

public static String setXML(String return_code, String return_msg) {
return "<xml><return_code><![CDATA[" + return_code + "]]></return_code><return_msg><![CDATA[" + return_msg + "]]></return_msg></xml>";
}

XMLUtil.java是用于解析支付结果通知信息的工具类,用到了

compile group: 'jdom', name: 'jdom', version: '1.0'

查看更多

java-会用HashMap

一个问题引发的思考

如果确定只装载100个元素,new HashMap(?)多少是最佳的,why?
要解答这个问题,第一要知道HashMap的数据结构,第二再弄明白存取数据的逻辑。

1.首先,我是一个数组

HashMap本质上是一个数组,数组的每个元素是一个单链表或者红黑树,由0个或多个节点组成。
java源码中的定义如下:

1
transient Node<K,V>[] table;

1.1节点类Node<K,V>

Node类是HashMap的一个静态内部类,可以将其看成是一个独立的类,只是声明在HashMap类内部而已。下面是源码:

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
static class Node<K,V> implements Map.Entry<K,V> {//Entry是Map接口中的一个内部接口
final int hash;//此节点的哈希值,同一个链表上的哈希值不一定相同
final K key;//键,不能修改
V value;//值
Node<K,V> next;//指向下一个节点

Node(int hash, K key, V value, Node<K,V> next) {
this.hash = hash;
this.key = key;
this.value = value;
this.next = next;
}

public final K getKey() { return key; }
public final V getValue() { return value; }
public final String toString() { return key + "=" + value; }

public final int hashCode() {//此Node类的hashCode方法
return Objects.hashCode(key) ^ Objects.hashCode(value);
}

public final V setValue(V newValue) {//重新设置节点Value,返回旧Value
V oldValue = value;
value = newValue;
return oldValue;
}

public final boolean equals(Object o) {//判断节点相等的方法,
if (o == this)//同一个对象,返回true
return true;
if (o instanceof Map.Entry) {
Map.Entry<?,?> e = (Map.Entry<?,?>)o;
if (Objects.equals(key, e.getKey()) &&
Objects.equals(value, e.getValue()))
return true;//键和值都相等则返回true
}
return false;
}
}

查看更多