最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java?Kryo,Protostuff,Hessian序列化方式對比

 更新時間:2022年07月05日 11:36:02   作者:??Pymjl????  
這篇文章主要介紹了Java?Kryo,Protostuff,Hessian序列化方式對比,文章圍繞主題展開詳細的內容介紹,具有一定的參考價值,需要的小伙伴可以參考一下

前言

前段時間在寫RPC框架的時候用到了Kryo、Hessian、Protostuff三種序列化方式。但是當時因為急于實現功能,就只是簡單的的看了一下如何使用這三種序列化方式,并沒有去深入研究各自的特性,以及優(yōu)點和缺點。知道現在就將RPC框架寫完了之后,才有時間靜下心來對三種方式做一個對比,總結。

Kryo、Hessain、Protostuff都是第三方開源的序列化/反序列化框架,要了解其各自的特性,我們首先需要知道序列化/反序列化是什么:

序列化:就是將對象轉化成字節(jié)序列的過程。

反序列化:就是講字節(jié)序列轉化成對象的過程。

seriallization 序列化 : 將對象轉化為便于傳輸的格式, 常見的序列化格式:二進制格式,字節(jié)數組,json字符串,xml字符串。

deseriallization 反序列化:將序列化的數據恢復為對象的過程

如果對序列化相關概念還不是很清楚的同學可以參照美團技術團隊的序列化和反序列化

筆記參考圖:

image-20220702131833644

性能對比

前期準備

  • 我們先創(chuàng)建一個新的Maven項目
  • 然后導入依賴
<dependency>
 ? ?<groupId>org.junit.jupiter</groupId>
 ? ?<artifactId>junit-jupiter-api</artifactId>
 ? ?<version>5.8.2</version>
 ? ?<scope>test</scope>
</dependency>
<!-- 代碼簡化 -->
<dependency>
 ? ?<groupId>org.projectlombok</groupId>
 ? ?<artifactId>lombok</artifactId>
 ? ?<version>1.18.20</version>
</dependency>
<!--kryo-->
<dependency>
 ? ?<groupId>com.esotericsoftware</groupId>
 ? ?<artifactId>kryo-shaded</artifactId>
 ? ?<version>4.0.2</version>
</dependency>
<dependency>
 ? ?<groupId>commons-codec</groupId>
 ? ?<artifactId>commons-codec</artifactId>
 ? ?<version>1.10</version>
</dependency>
<!--protostuff-->
<dependency>
 ? ?<groupId>io.protostuff</groupId>
 ? ?<artifactId>protostuff-core</artifactId>
 ? ?<version>1.7.2</version>
</dependency>
<dependency>
 ? ?<groupId>io.protostuff</groupId>
 ? ?<artifactId>protostuff-runtime</artifactId>
 ? ?<version>1.7.2</version>
</dependency>
<!--hessian2-->
<dependency>
 ? ?<groupId>com.caucho</groupId>
 ? ?<artifactId>hessian</artifactId>
 ? ?<version>4.0.62</version>
</dependency>

工具類:

kryo

package cuit.pymjl.utils;
import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;
import org.apache.commons.codec.binary.Base64;
import org.objenesis.strategy.StdInstantiatorStrategy;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.UnsupportedEncodingException;
/**
 * @author Pymjl
 * @version 1.0
 * @date 2022/4/18 20:07
 **/
@SuppressWarnings("all")
public class KryoUtils {
 ? ?private static final String DEFAULT_ENCODING = "UTF-8";
?
 ? ?//每個線程的 Kryo 實例
 ? ?private static final ThreadLocal<Kryo> KRYO_LOCAL = new ThreadLocal<Kryo>() {
 ? ? ? ?@Override
 ? ? ? ?protected Kryo initialValue() {
 ? ? ? ? ? ?Kryo kryo = new Kryo();
?
 ? ? ? ? ? ?/**
 ? ? ? ? ? ? * 不要輕易改變這里的配置!更改之后,序列化的格式就會發(fā)生變化,
 ? ? ? ? ? ? * 上線的同時就必須清除 Redis 里的所有緩存,
 ? ? ? ? ? ? * 否則那些緩存再回來反序列化的時候,就會報錯
 ? ? ? ? ? ? */
 ? ? ? ? ? ?//支持對象循環(huán)引用(否則會棧溢出)
 ? ? ? ? ? ?kryo.setReferences(true); //默認值就是 true,添加此行的目的是為了提醒維護者,不要改變這個配置
?
 ? ? ? ? ? ?//不強制要求注冊類(注冊行為無法保證多個 JVM 內同一個類的注冊編號相同;而且業(yè)務系統(tǒng)中大量的 Class 也難以一一注冊)
 ? ? ? ? ? ?kryo.setRegistrationRequired(false); //默認值就是 false,添加此行的目的是為了提醒維護者,不要改變這個配置
?
 ? ? ? ? ? ?//Fix the NPE bug when deserializing Collections.
 ? ? ? ? ?  ((Kryo.DefaultInstantiatorStrategy) kryo.getInstantiatorStrategy())
 ? ? ? ? ? ? ? ? ?  .setFallbackInstantiatorStrategy(new StdInstantiatorStrategy());
?
 ? ? ? ? ? ?return kryo;
 ? ? ?  }
 ?  };
 ? ?/**
 ? ? * 獲得當前線程的 Kryo 實例
 ? ? *
 ? ? * @return 當前線程的 Kryo 實例
 ? ? */
 ? ?public static Kryo getInstance() {
 ? ? ? ?return KRYO_LOCAL.get();
 ?  }
?
 ? ?//-----------------------------------------------
 ? ?// ? ? ? ?  序列化/反序列化對象,及類型信息
 ? ?// ? ? ? ?  序列化的結果里,包含類型的信息
 ? ?// ? ? ? ?  反序列化時不再需要提供類型
 ? ?//-----------------------------------------------
?
 ? ?/**
 ? ? * 將對象【及類型】序列化為字節(jié)數組
 ? ? *
 ? ? * @param obj 任意對象
 ? ? * @param <T> 對象的類型
 ? ? * @return 序列化后的字節(jié)數組
 ? ? */
 ? ?public static <T> byte[] writeToByteArray(T obj) {
 ? ? ? ?ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
 ? ? ? ?Output output = new Output(byteArrayOutputStream);
?
 ? ? ? ?Kryo kryo = getInstance();
 ? ? ? ?kryo.writeClassAndObject(output, obj);
 ? ? ? ?output.flush();
?
 ? ? ? ?return byteArrayOutputStream.toByteArray();
 ?  }
 ? ?/**
 ? ? * 將對象【及類型】序列化為 String
 ? ? * 利用了 Base64 編碼
 ? ? *
 ? ? * @param obj 任意對象
 ? ? * @param <T> 對象的類型
 ? ? * @return 序列化后的字符串
 ? ? */
 ? ?public static <T> String writeToString(T obj) {
 ? ? ? ?try {
 ? ? ? ? ? ?return new String(Base64.encodeBase64(writeToByteArray(obj)), DEFAULT_ENCODING);
 ? ? ?  } catch (UnsupportedEncodingException e) {
 ? ? ? ? ? ?throw new IllegalStateException(e);
 ? ? ?  }
 ?  }
 ? ?/**
 ? ? * 將字節(jié)數組反序列化為原對象
 ? ? *
 ? ? * @param byteArray writeToByteArray 方法序列化后的字節(jié)數組
 ? ? * @param <T> ? ? ? 原對象的類型
 ? ? * @return 原對象
 ? ? */
 ? ?@SuppressWarnings("unchecked")
 ? ?public static <T> T readFromByteArray(byte[] byteArray) {
 ? ? ? ?ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArray);
 ? ? ? ?Input input = new Input(byteArrayInputStream);
?
 ? ? ? ?Kryo kryo = getInstance();
 ? ? ? ?return (T) kryo.readClassAndObject(input);
 ?  }
 ? ?/**
 ? ? * 將 String 反序列化為原對象
 ? ? * 利用了 Base64 編碼
 ? ? *
 ? ? * @param str writeToString 方法序列化后的字符串
 ? ? * @param <T> 原對象的類型
 ? ? * @return 原對象
 ? ? */
 ? ?public static <T> T readFromString(String str) {
 ? ? ? ?try {
 ? ? ? ? ? ?return readFromByteArray(Base64.decodeBase64(str.getBytes(DEFAULT_ENCODING)));
 ? ? ?  } catch (UnsupportedEncodingException e) {
 ? ? ? ? ? ?throw new IllegalStateException(e);
 ? ? ?  }
 ?  }
 ? ?//-----------------------------------------------
 ? ?// ? ? ? ?  只序列化/反序列化對象
 ? ?// ? ? ? ?  序列化的結果里,不包含類型的信息
 ? ?//-----------------------------------------------
?
 ? ?/**
 ? ? * 將對象序列化為字節(jié)數組
 ? ? *
 ? ? * @param obj 任意對象
 ? ? * @param <T> 對象的類型
 ? ? * @return 序列化后的字節(jié)數組
 ? ? */
 ? ?public static <T> byte[] writeObjectToByteArray(T obj) {
 ? ? ? ?ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
 ? ? ? ?Output output = new Output(byteArrayOutputStream);
 ? ? ? ?Kryo kryo = getInstance();
 ? ? ? ?kryo.writeObject(output, obj);
 ? ? ? ?output.flush();
 ? ? ? ?return byteArrayOutputStream.toByteArray();
 ?  }
?
 ? ?/**
 ? ? * 將對象序列化為 String
 ? ? * 利用了 Base64 編碼
 ? ? *
 ? ? * @param obj 任意對象
 ? ? * @param <T> 對象的類型
 ? ? * @return 序列化后的字符串
 ? ? */
 ? ?public static <T> String writeObjectToString(T obj) {
 ? ? ? ?try {
 ? ? ? ? ? ?return new String(Base64.encodeBase64(writeObjectToByteArray(obj)), DEFAULT_ENCODING);
 ? ? ?  } catch (UnsupportedEncodingException e) {
 ? ? ? ? ? ?throw new IllegalStateException(e);
 ? ? ?  }
 ?  }
 ? ?/**
 ? ? * 將字節(jié)數組反序列化為原對象
 ? ? *
 ? ? * @param byteArray writeToByteArray 方法序列化后的字節(jié)數組
 ? ? * @param clazz ? ? 原對象的 Class
 ? ? * @param <T> ? ? ? 原對象的類型
 ? ? * @return 原對象
 ? ? */
 ? ?@SuppressWarnings("unchecked")
 ? ?public static <T> T readObjectFromByteArray(byte[] byteArray, Class<T> clazz) {
 ? ? ? ?ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArray);
 ? ? ? ?Input input = new Input(byteArrayInputStream);
?
 ? ? ? ?Kryo kryo = getInstance();
 ? ? ? ?return kryo.readObject(input, clazz);
 ?  }
 ? ?/**
 ? ? * 將 String 反序列化為原對象
 ? ? * 利用了 Base64 編碼
 ? ? *
 ? ? * @param str ? writeToString 方法序列化后的字符串
 ? ? * @param clazz 原對象的 Class
 ? ? * @param <T> ? 原對象的類型
 ? ? * @return 原對象
 ? ? */
 ? ?public static <T> T readObjectFromString(String str, Class<T> clazz) {
 ? ? ? ?try {
 ? ? ? ? ? ?return readObjectFromByteArray(Base64.decodeBase64(str.getBytes(DEFAULT_ENCODING)), clazz);
 ? ? ?  } catch (UnsupportedEncodingException e) {
 ? ? ? ? ? ?throw new IllegalStateException(e);
 ? ? ?  }
 ?  }
}

Hessian

package cuit.pymjl.utils;
import com.caucho.hessian.io.Hessian2Input;
import com.caucho.hessian.io.Hessian2Output;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;

/**
 * @author Pymjl
 * @version 1.0
 * @date 2022/7/2 12:39
 **/
public class HessianUtils {
 ? ?/**
 ? ? * 序列化
 ? ? *
 ? ? * @param obj obj
 ? ? * @return {@code byte[]}
 ? ? */
 ? ?public static byte[] serialize(Object obj) {
 ? ? ? ?Hessian2Output ho = null;
 ? ? ? ?ByteArrayOutputStream baos = null;
 ? ? ? ?try {
 ? ? ? ? ? ?baos = new ByteArrayOutputStream();
 ? ? ? ? ? ?ho = new Hessian2Output(baos);
 ? ? ? ? ? ?ho.writeObject(obj);
 ? ? ? ? ? ?ho.flush();
 ? ? ? ? ? ?return baos.toByteArray();
 ? ? ?  } catch (Exception ex) {
 ? ? ? ? ? ?ex.printStackTrace();
 ? ? ? ? ? ?throw new RuntimeException("serialize failed");
 ? ? ?  } finally {
 ? ? ? ? ? ?if (null != ho) {
 ? ? ? ? ? ? ? ?try {
 ? ? ? ? ? ? ? ? ? ?ho.close();
 ? ? ? ? ? ? ?  } catch (IOException e) {
 ? ? ? ? ? ? ? ? ? ?e.printStackTrace();
 ? ? ? ? ? ? ?  }
 ? ? ? ? ?  }
 ? ? ? ? ? ?if (null != baos) {
 ? ? ? ? ? ? ? ?try {
 ? ? ? ? ? ? ? ? ? ?baos.close();
 ? ? ? ? ? ? ?  } catch (IOException e) {
 ? ? ? ? ? ? ? ? ? ?e.printStackTrace();
 ? ? ? ? ? ? ?  }
 ? ? ? ? ?  }
 ? ? ?  }
 ?  }
 ? ?/**
 ? ? * 反序列化
 ? ? *
 ? ? * @param bytes 字節(jié)
 ? ? * @param clazz clazz
 ? ? * @return {@code T}
 ? ? */
 ? ?public static ?<T> T deserialize(byte[] bytes, Class<T> clazz) {
 ? ? ? ?Hessian2Input hi = null;
 ? ? ? ?ByteArrayInputStream bais = null;
 ? ? ? ?try {
 ? ? ? ? ? ?bais = new ByteArrayInputStream(bytes);
 ? ? ? ? ? ?hi = new Hessian2Input(bais);
 ? ? ? ? ? ?Object o = hi.readObject();
 ? ? ? ? ? ?return clazz.cast(o);
 ? ? ?  } catch (Exception ex) {
 ? ? ? ? ? ?throw new RuntimeException("deserialize failed");
 ? ? ?  } finally {
 ? ? ? ? ? ?if (null != hi) {
 ? ? ? ? ? ? ? ?try {
 ? ? ? ? ? ? ? ? ? ?hi.close();
 ? ? ? ? ? ? ?  } catch (IOException e) {
 ? ? ? ? ? ? ? ? ? ?e.printStackTrace();
 ? ? ? ? ? ? ?  }
 ? ? ? ? ?  }
 ? ? ? ? ? ?if (null != bais) {
 ? ? ? ? ? ? ? ?try {
 ? ? ? ? ? ? ? ? ? ?bais.close();
 ? ? ? ? ? ? ?  } catch (IOException e) {
 ? ? ? ? ? ? ? ? ? ?e.printStackTrace();
 ? ? ? ? ? ? ?  }
 ? ? ? ? ?  }
 ? ? ?  }
 ?  }
}

Protostuff

package cuit.pymjl.utils;
import io.protostuff.LinkedBuffer;
import io.protostuff.ProtostuffIOUtil;
import io.protostuff.Schema;
import io.protostuff.runtime.RuntimeSchema;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
 * @author Pymjl
 * @version 1.0
 * @date 2022/6/28 21:00
 **/
public class ProtostuffUtils {
 ? ?/**
 ? ? * 避免每次序列化都重新申請Buffer空間
 ? ? * 這個字段表示,申請一個內存空間用戶緩存,LinkedBuffer.DEFAULT_BUFFER_SIZE表示申請了默認大小的空間512個字節(jié),
 ? ? * 我們也可以使用MIN_BUFFER_SIZE,表示256個字節(jié)。
 ? ? */
 ? ?private static final LinkedBuffer BUFFER = LinkedBuffer.allocate(LinkedBuffer.DEFAULT_BUFFER_SIZE);
 ? ?/**
 ? ? * 緩存Schema
 ? ? * 這個字段表示緩存的Schema。那這個Schema是什么呢?就是一個組織結構,就好比是數據庫中的表、視圖等等這樣的組織機構,
 ? ? * 在這里表示的就是序列化對象的結構。
 ? ? */
 ? ?private static final Map<Class<?>, Schema<?>> SCHEMA_CACHE = new ConcurrentHashMap<>();
?
 ? ?/**
 ? ? * 序列化方法,把指定對象序列化成字節(jié)數組
 ? ? *
 ? ? * @param obj 對象
 ? ? * @return byte[]
 ? ? */
 ? ?@SuppressWarnings("unchecked")
 ? ?public static <T> byte[] serialize(T obj) {
 ? ? ? ?Class<T> clazz = (Class<T>) obj.getClass();
 ? ? ? ?Schema<T> schema = getSchema(clazz);
 ? ? ? ?byte[] data;
 ? ? ? ?try {
 ? ? ? ? ? ?data = ProtostuffIOUtil.toByteArray(obj, schema, BUFFER);
 ? ? ?  } finally {
 ? ? ? ? ? ?BUFFER.clear();
 ? ? ?  }
 ? ? ? ?return data;
 ?  }
?
 ? ?/**
 ? ? * 反序列化方法,將字節(jié)數組反序列化成指定Class類型
 ? ? *
 ? ? * @param data  字節(jié)數組
 ? ? * @param clazz 字節(jié)碼
 ? ? * @return
 ? ? */
 ? ?public static <T> T deserialize(byte[] data, Class<T> clazz) {
 ? ? ? ?Schema<T> schema = getSchema(clazz);
 ? ? ? ?T obj = schema.newMessage();
 ? ? ? ?ProtostuffIOUtil.mergeFrom(data, obj, schema);
 ? ? ? ?return obj;
 ?  }
 ? ?@SuppressWarnings("unchecked")
 ? ?private static <T> Schema<T> getSchema(Class<T> clazz) {
 ? ? ? ?Schema<T> schema = (Schema<T>) SCHEMA_CACHE.get(clazz);
 ? ? ? ?if (schema == null) {
 ? ? ? ? ? ?schema = RuntimeSchema.getSchema(clazz);
 ? ? ? ? ? ?if (schema == null) {
 ? ? ? ? ? ? ? ?SCHEMA_CACHE.put(clazz, schema);
 ? ? ? ? ?  }
 ? ? ?  }
 ? ? ? ?return schema;
 ?  }
}

創(chuàng)建一個實體類進行測試:

package cuit.pymjl.entity;
?
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serial;
import java.io.Serializable;
/**
 * @author Pymjl
 * @version 1.0
 * @date 2022/7/2 12:32
 **/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student implements Serializable {
 ? ?@Serial
 ? ?private static final long serialVersionUID = -91809837793898L;
?
 ? ?private String name;
 ? ?private String password;
 ? ?private int age;
 ? ?private String address;
 ? ?private String phone;
}

序列化后字節(jié)所占空間大小比較

編寫測試類:

public class MainTest {
 ? ?@Test
 ? ?void testLength() {
 ? ? ? ?Student student = new Student("pymjl", "123456", 18, "北京", "123456789");
 ? ? ? ?int kryoLength = KryoUtils.writeObjectToByteArray(student).length;
 ? ? ? ?int hessianLength = HessianUtils.serialize(student).length;
 ? ? ? ?int protostuffLength = ProtostuffUtils.serialize(student).length;
 ? ? ? ?System.out.println("kryoLength: " + kryoLength);
 ? ? ? ?System.out.println("hessianLength: " + hessianLength);
 ? ? ? ?System.out.println("protostuffLength: " + protostuffLength);
 ?  }
}

運行截圖:

image-20220702131907826

由圖可知,Hessian序列化后字節(jié)所占的空間都顯著比其他兩種方式要大得多

其他比較

  • Hessian使用固定長度存儲int和long,而kryo使用變長的int和long保證這種基本數據類型序列化后盡量小,實際應用中,很大的數據不會經常出現。
  • Kryo進行序列化的時候,需要傳入完整類名或者利用 register() 提前將類注冊到Kryo上,其類與一個int型的ID相關聯,序列中只存放這個ID,因此序列體積就更小,而Hessian則是將所有類字段信息都放入序列化字節(jié)數組中,直接利用字節(jié)數組進行反序列化,不需要其他參與,因為存的東西多處理速度就會慢點
  • Kryo使用不需要實現Serializable接口,Hessian則需實現
  • Kryo數據類的字段增、減,序列化和反序列化時無法兼容,而Hessian則兼容,Protostuff是只能在末尾添加新字段才兼容
  • Kryo和Hessian使用涉及到的數據類中必須擁有無參構造函數
  • Hessian會把復雜對象的所有屬性存儲在一個Map中進行序列化。所以在父類、子類存在同名成員變量的情況下,Hessian序列化時,先序列化子類,然后序列化父類,因此反序列化結果會導致子類同名成員變量被父類的值覆蓋
  • Kryo不是線程安全的,要通過ThreadLocal或者創(chuàng)建Kryo線程池來保證線程安全,而Protostuff則是線程安全的
  • Protostuff和Kryo序列化的格式有相似之處,都是利用一個標記來記錄字段類型,因此序列化出來體積都比較小

小結

 優(yōu)點缺點
Kryo速度快,序列化后體積小跨語言支持較復雜
Hessian默認支持跨語言較慢
Protostuff速度快,基于protobuf需靜態(tài)編譯
Protostuff-Runtime無需靜態(tài)編譯,但序列化前需預先傳入schema不支持無默認構造函數的類,反序列化時需用戶自己初始化序列化后的對象,其只負責將該對象進行賦值
Java使用方便,可序列化所有類速度慢,占空間

到此這篇關于Java Kryo,Protostuff,Hessian序列化方式對比的文章就介紹到這了,更多相關Java序列化內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • java導出json格式文件的示例代碼

    java導出json格式文件的示例代碼

    本篇文章主要介紹了java導出json格式文件的示例代碼,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-09-09
  • mybatis-plus 自定義 Service Vo接口實現數據庫實體與 vo 對象轉換返回功能

    mybatis-plus 自定義 Service Vo接口實現數據庫實體與 vo

    這篇文章主要介紹了mybatis-plus 自定義 Service Vo接口實現數據庫實體與 vo 對象轉換返回功能,本文通過實例圖文相結合給大家介紹的非常詳細,感興趣的朋友跟隨小編一起看看吧
    2024-08-08
  • java 抽象類與接口的區(qū)別總結

    java 抽象類與接口的區(qū)別總結

    這篇文章主要介紹了java 抽象類與接口的區(qū)別總結的相關資料,需要的朋友可以參考下
    2017-02-02
  • Java AbstractMethodError原因案例詳解

    Java AbstractMethodError原因案例詳解

    這篇文章主要介紹了Java AbstractMethodError原因案例詳解,本篇文章通過簡要的案例,講解了該項技術的了解與使用,以下就是詳細內容,需要的朋友可以參考下
    2021-08-08
  • Java多線程實現多人聊天室功能

    Java多線程實現多人聊天室功能

    這篇文章主要為大家詳細介紹了Java多線程實現多人聊天室功能,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-06-06
  • Java編程中的vector類用法學習筆記

    Java編程中的vector類用法學習筆記

    Vector通常被用來實現動態(tài)數組,即可實現自動增長的對象數組,和C++一樣vector類同樣被Java內置,下面就來看一下vector類的基本用法.
    2016-05-05
  • Java設計模式之適配器模式的示例詳解

    Java設計模式之適配器模式的示例詳解

    適配器模式,即將某個類的接口轉換成客戶端期望的另一個接口的表示,主要目的是實現兼容性,讓原本因為接口不匹配,沒辦法一起工作的兩個類,可以協(xié)同工作。本文將通過示例詳細介紹適配器模式,需要的可以參考一下
    2022-02-02
  • idea在用Mybatis時xml文件sql不提示解決辦法(提示后背景顏色去除)

    idea在用Mybatis時xml文件sql不提示解決辦法(提示后背景顏色去除)

    mybatis的xml文件配置的時候,有時候會沒有提示,這讓我們很頭疼,下面這篇文章主要給大家介紹了關于idea在用Mybatis時xml文件sql不提示的解決辦法,提示后背景顏色去除的相關資料,需要的朋友可以參考下
    2023-03-03
  • SpringBoot實體多層嵌套判空字段的方式

    SpringBoot實體多層嵌套判空字段的方式

    這篇文章主要介紹了SpringBoot實體多層嵌套如何判空字段,最近在公司了接了個需求:需要開發(fā)一個中間系統(tǒng),進行三方聯調,文中通過代碼示例介紹的非常詳細,需要的朋友可以參考下
    2024-09-09
  • SpringCloud?Gateway之請求應答日志打印方式

    SpringCloud?Gateway之請求應答日志打印方式

    這篇文章主要介紹了SpringCloud?Gateway之請求應答日志打印方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-03-03

最新評論

沁水县| 炉霍县| 花垣县| 朝阳区| 兴隆县| 天柱县| 赣州市| 库车县| 彩票| 芜湖县| 广德县| 神木县| 泸定县| 万全县| 宁海县| 梅州市| 绥滨县| 铅山县| 万宁市| 宁安市| 崇义县| 赣州市| 定远县| 蒲江县| 长寿区| 汉源县| 沅陵县| 马关县| 靖远县| 土默特左旗| 平泉县| 五指山市| 醴陵市| 云林县| 乐亭县| 眉山市| 随州市| 洪江市| 甘德县| 连州市| 苏州市|