Springboot集成ProtoBuf的實(shí)例
Springboot集成ProtoBuf
ProtoBuf是一種序列化和解析速度遠(yuǎn)高于JSON和XML的數(shù)據(jù)格式,項(xiàng)目中使用了CouchBase作為緩存服務(wù)器,從數(shù)據(jù)庫(kù)中拿到數(shù)據(jù)后通過(guò)protobuf序列化后放入CouchBase作為緩存,查詢(xún)數(shù)據(jù)的時(shí)候解壓并反序列化成數(shù)據(jù)對(duì)象,下面是ProtoBuf的具體使用方法
1、pom.xml引入相關(guān)依賴(lài)
<dependency> ? ? <groupId>com.google.protobuf</groupId> ?? ?<artifactId>protobuf-java</artifactId> ?? ?<version>3.5.0</version> </dependency> <dependency> ?? ?<groupId>io.protostuff</groupId> ?? ?<artifactId>protostuff-core</artifactId> ?? ?<version>1.4.0</version> </dependency> <dependency> ?? ?<groupId>io.protostuff</groupId> ?? ?<artifactId>protostuff-runtime</artifactId> ?? ?<version>1.4.0</version> </dependency>
2、新建序列化工具類(lèi)ProtoBufUtil.java
package com.xrq.demo.utils;? import java.util.Map; import java.util.concurrent.ConcurrentHashMap; ? import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.objenesis.Objenesis; import org.springframework.objenesis.ObjenesisStd; ? import io.protostuff.LinkedBuffer; import io.protostuff.ProtostuffIOUtil; import io.protostuff.Schema; import io.protostuff.runtime.RuntimeSchema; ? /** ?* ProtoBufUtil 轉(zhuǎn)換工具類(lèi) ?*? ?* @author XRQ ?* ?*/ public class ProtoBufUtil { ?? ?private static Logger log = LoggerFactory.getLogger(ProtoBufUtil.class); ?? ?private static Map<Class<?>, Schema<?>> cachedSchema = new ConcurrentHashMap<Class<?>, Schema<?>>(); ? ?? ?private static Objenesis objenesis = new ObjenesisStd(true); ? ?? ?@SuppressWarnings("unchecked") ?? ?private static <T> Schema<T> getSchema(Class<T> cls) { ?? ??? ?Schema<T> schema = (Schema<T>) cachedSchema.get(cls); ?? ??? ?if (schema == null) { ?? ??? ??? ?schema = RuntimeSchema.createFrom(cls); ?? ??? ??? ?if (schema != null) { ?? ??? ??? ??? ?cachedSchema.put(cls, schema); ?? ??? ??? ?} ?? ??? ?} ?? ??? ?return schema; ?? ?} ? ?? ?public ProtoBufUtil() { ?? ?} ? ?? ?@SuppressWarnings({ "unchecked" }) ?? ?public static <T> byte[] serializer(T obj) { ?? ??? ?Class<T> cls = (Class<T>) obj.getClass(); ?? ??? ?LinkedBuffer buffer = LinkedBuffer.allocate(LinkedBuffer.DEFAULT_BUFFER_SIZE); ?? ??? ?try { ?? ??? ??? ?Schema<T> schema = getSchema(cls); ?? ??? ??? ?return ProtostuffIOUtil.toByteArray(obj, schema, buffer); ?? ??? ?} catch (Exception e) { ?? ??? ??? ?log.error("protobuf序列化失敗"); ?? ??? ??? ?throw new IllegalStateException(e.getMessage(), e); ?? ??? ?} finally { ?? ??? ??? ?buffer.clear(); ?? ??? ?} ?? ?} ? ?? ?public static <T> T deserializer(byte[] bytes, Class<T> clazz) { ?? ??? ?try { ?? ??? ??? ?T message = (T) objenesis.newInstance(clazz); ?? ??? ??? ?Schema<T> schema = getSchema(clazz); ?? ??? ??? ?ProtostuffIOUtil.mergeFrom(bytes, message, schema); ?? ??? ??? ?return message; ?? ??? ?} catch (Exception e) { ?? ??? ??? ?log.error("protobuf反序列化失敗"); ?? ??? ??? ?throw new IllegalStateException(e.getMessage(), e); ?? ??? ?} ?? ?} ? }
3、新建實(shí)體類(lèi)User.java
注:重點(diǎn)是@Tag標(biāo)簽需要按照順序往下排,如果需要新增字段,只能接著往下排,不能改變已存在的標(biāo)簽序號(hào)
package com.xrq.demo.bo;? import java.io.Serializable; import java.util.Date; ? import io.protostuff.Tag; ? /** ?* 用戶(hù)信息類(lèi) ?*? ?* @ClassName: User ?* @author XRQ ?* @date 2019年4月30日 ?*/ public class User implements Serializable { ? ? private static final long serialVersionUID = 1L; ? ? ? // 用戶(hù)ID ? ? @Tag(1) ? ? private int userId; ? ? ? // 用戶(hù)類(lèi)型 ? ? @Tag(2) ? ? private int userTypeId; ? ? ? // 用戶(hù)名? ? ? @Tag(3) ? ? private String userName; ? ? ? // 創(chuàng)建時(shí)間 ? ? @Tag(4) ? ? private Date createDateTime;? ? ? public int getUserId() ? ? { ? ? ? ? ? return userId; ? ? } ? ? ? public void setUserId(int userId) ? ? { ? ? ? ? ? this.userId = userId; ? ? } ? ? ? public int getUserTypeId() ? ? { ? ? ? ? ? return userTypeId; ? ? } ? ? ? public void setUserTypeId(int userTypeId) ? ? { ? ? ? ? ? this.userTypeId = userTypeId; ? ? } ? ? ? public String getUserName() ? ? { ? ? ? ? ? return userName; ? ? } ? ? ? public void setUserName(String userName) ? ? { ? ? ? ? ? this.userName = userName; ? ? } ? ? ? public Date getCreateDateTime() ? ? { ? ? ? ? ? return createDateTime; ? ? } ? ? ? public void setCreateDateTime(Date createDateTime) ? ? { ? ? ? ? ? this.createDateTime = createDateTime; ? ? } }
4、使用方式
User user = new User(); user.setUserId(1); user.setUserTypeId(1); user.setUserName("XRQ"); user.setCreateDateTime(new Date()); //序列化成ProtoBuf數(shù)據(jù)結(jié)構(gòu) byte[] userProtoObj= ProtoBufUtil.serializer(userInfo) ? //ProtoBuf數(shù)據(jù)結(jié)構(gòu)反序列化成User對(duì)象 User newUserObj = ProtoBufUtil.deserializer(userProtoObj, User.class))
ProtoBuf+Java+Springboot+IDEA應(yīng)用
什么是Protobuf
1.Google Protocol Buffer( 簡(jiǎn)稱(chēng) Protobuf) 是 Google 公司內(nèi)部的混合語(yǔ)言數(shù)據(jù)標(biāo)準(zhǔn);
2.Protocol Buffers 是一種輕便高效的結(jié)構(gòu)化數(shù)據(jù)存儲(chǔ)格式,可以用于結(jié)構(gòu)化數(shù)據(jù)串行化,或者說(shuō)序列化。它很適合做數(shù)據(jù)存儲(chǔ)或 RPC 數(shù)據(jù)交換格式。可用于通訊協(xié)議、數(shù)據(jù)存儲(chǔ)等領(lǐng)域的語(yǔ)言無(wú)關(guān)、平臺(tái)無(wú)關(guān)、可擴(kuò)展的序列化結(jié)構(gòu)數(shù)據(jù)格式;
3.形式為.proto結(jié)尾的文件;
應(yīng)用環(huán)境
近期接觸公司的網(wǎng)約車(chē)接口對(duì)接項(xiàng)目,第三方公司限定了接口的數(shù)據(jù)用protobuf格式序列化后,通過(guò)AES128加密后傳輸。
開(kāi)發(fā)環(huán)境
Java+Spring boot+IDEA+Windows
新建Spring boot項(xiàng)目 在IDEA開(kāi)發(fā)工具中安裝protobuf插件
添加配置maven依賴(lài)(可能一開(kāi)始自己的項(xiàng)目中存在固有的配置,不要?jiǎng)h除,在對(duì)應(yīng)的地方添加下面的配置即可,不需要修改)
<dependency> <groupId>io.protostuff</groupId> <artifactId>protostuff-runtime</artifactId> <version>1.4.0</version> </dependency>
<plugin> <groupId>org.xolstice.maven.plugins</groupId> <artifactId>protobuf-maven-plugin</artifactId> <version>0.5.0</version> <configuration> <protocArtifact> com.google.protobuf:protoc:3.1.0:exe:${os.detected.classifier} </protocArtifact> <pluginId>grpc-java</pluginId> </configuration> <executions> <execution> <goals> <goal>compile</goal> <goal>compile-custom</goal> </goals> </execution> </executions> </plugin>
寫(xiě)項(xiàng)目對(duì)應(yīng)的.proto文件(這里貼一部分代碼)
// 版本號(hào) syntax = "proto2"; // 打包路徑 option java_package="XXX1"; // Java文件名 option java_outer_classname="XXX2"; // 屬性信息 message BaseInfo { // 公司標(biāo)識(shí) required string CompanyId = 1; // 公司名稱(chēng) required string CompanyName = 2; // 操作標(biāo)識(shí) required uint32 Flag = 3; // 更新時(shí)間 required uint64 UpdateTime = 4; }
.proto文件存在項(xiàng)目路徑
生成.java文件方式(點(diǎn)擊項(xiàng)目中的.proto文件,找到對(duì)應(yīng)的maven依賴(lài),雙擊標(biāo)識(shí)2對(duì)應(yīng)的protobuf:compile文件)
運(yùn)行成功之后在對(duì)應(yīng)路徑下查看生成的.java文件
生成的Java文件即可使用(如果在業(yè)務(wù)中.proto文件很大,生成的Java大小超出IDEA默認(rèn)的2.5M,生成的Java文件將被IDEA誤認(rèn)為不是Java文件,導(dǎo)致生成的Java文件不可使用,這時(shí)需要修改IDEA的配置文件,將默認(rèn)的大小修改,重啟IDEA即可) 進(jìn)行數(shù)據(jù)序列化
List<BaseInfo> baseInfoList = baseInfoMapper.selectAll(); XXX2.OTIpcList.Builder listBuilder = XXX2.OTIpcList.newBuilder(); XXX2.OTIpc.Builder otipcBuilder = XXX2.OTIpc.newBuilder(); otipcBuilder.setCompanyId(ProjectConstant.COMPANY_ID); otipcBuilder.setSource(ProjectConstant.COMPANY_SOURCE); otipcBuilder.setIPCType(OTIpcDef.IpcType.baseInfoCompany); for(int i=0;i<baseInfoList .size();i++){ try{ XXX2.BaseInfo.Builder baseInfoBuilder = XXX2.BaseInfo.newBuilder(); baseInfoBuilder .setCompanyId(baseInfoList .get(i).getCompanyid()); baseInfoBuilder .setCompanyName(baseInfoList .get(i).getCompanyname()); baseInfoBuilder .setFlag(baseInfoList .get(i).getFlag()); baseInfoBuilder .setUpdateTime(baseInfoList .get(i).getUpdatetime()); for(int j=0;j<10;j++) { otipcBuilder.addBaseInfo(baseInfoBuilder .build()); } } catch (Exception e){ LoggerUtils.info(getClass(),e.getMessage()); } } listBuilder.addOtpic(otipcBuilder);
進(jìn)行數(shù)據(jù)AES128位加密
public static String sendScreate(OTIpcDef.OTIpcList.Builder listBuilder) { String screateKeyString = getSecretKey(); String screateKey = screateKeyString.split(";")[1]; String screateValue = screateKeyString.split(";")[0]; OTIpcDef.OTIpcList list = listBuilder.build(); ByteArrayOutputStream output = new ByteArrayOutputStream(); try { list.writeTo(output); } catch (IOException e) { e.printStackTrace(); } byte[] data = null; try{ byte[] keyByte = new byte[screateValue.length()/2]; for(int j=0;j<screateValue.length()/2;j++) { byte b = (byte) ((Integer.valueOf(String.valueOf(screateValue.charAt(j*2)), 16) << 4) | Integer.valueOf(String.valueOf(screateValue.charAt(j*2+1)), 16)); keyByte[j] = b; } Key secretKey= new SecretKeySpec(keyByte,"AES"); Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider()); Cipher cipher= Cipher.getInstance("AES/ECB/PKCS7Padding", "BC"); cipher.init(Cipher.ENCRYPT_MODE, secretKey); data = cipher.doFinal(output.toByteArray()); sendPostJSON(screateKey, data); return "success"; } catch(Exception e){ e.printStackTrace(); } return null; }
小結(jié)一下:經(jīng)驗(yàn)證,Protobuf 序列化相比XML,JSON性能更好,在Protobuf 官網(wǎng)看到在創(chuàng)建對(duì)象,將對(duì)象序列化為內(nèi)存中的字節(jié)序列,然后再反序列化的整個(gè)過(guò)程中相比其他相似技術(shù)的性能測(cè)試結(jié)果圖,但是在通用性上會(huì)存在局限性,功能相對(duì)簡(jiǎn)單,不適合用來(lái)描述數(shù)據(jù)結(jié)構(gòu)。
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Mybatis-plus使用selectList查詢(xún)數(shù)據(jù)為null的問(wèn)題及解決辦法
這篇文章主要介紹了Mybatis-plus使用selectList查詢(xún)數(shù)據(jù)為null的問(wèn)題及解決方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-07-07springboot?aop配合反射統(tǒng)一簽名驗(yàn)證實(shí)踐
這篇文章主要介紹了springboot?aop配合反射統(tǒng)一簽名驗(yàn)證實(shí)踐,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-12-12Java復(fù)制(拷貝)數(shù)組的4種方法:arraycopy()方法、clone() 方法、copyOf()和copyOfRa
這篇文章主要介紹了Java復(fù)制(拷貝)數(shù)組的4種方法:arraycopy()方法、clone() 方法、copyOf()和copyOfRan,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-01-01nas實(shí)現(xiàn)java開(kāi)發(fā)的環(huán)境詳解
這篇文章主要為大家介紹了nas實(shí)現(xiàn)java開(kāi)發(fā)的環(huán)境詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-11-11java 算法之希爾排序詳解及實(shí)現(xiàn)代碼
這篇文章主要介紹了java 算法之希爾排序詳解及實(shí)現(xiàn)代碼的相關(guān)資料,需要的朋友可以參考下2017-03-03java實(shí)現(xiàn)上傳圖片尺寸修改和質(zhì)量壓縮
這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)上傳圖片尺寸修改和質(zhì)量壓縮,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-04-04淺談Spring @Async異步線(xiàn)程池用法總結(jié)
本篇文章主要介紹了淺談Spring @Async異步線(xiàn)程池用法總結(jié),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-07-07詳解Java豆瓣電影爬蟲(chóng)——小爬蟲(chóng)成長(zhǎng)記(附源碼)
這篇文章主要介紹了詳解Java豆瓣電影爬蟲(chóng)——小爬蟲(chóng)成長(zhǎng)記(附源碼) ,具有一定的參考價(jià)值,有需要的可以了解一下。2016-12-12