springboot整合netty過(guò)程詳解
這篇文章主要介紹了springboot整合netty過(guò)程詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
前言
上一篇講了netty的一個(gè)入門(mén)的demo;項(xiàng)目上我也把數(shù)據(jù)處理做好了,就要開(kāi)始存數(shù)據(jù)庫(kù)了;我用的mybatis框架,如果單獨(dú)使用還是覺(jué)得比較麻煩,所以就用了springboot+mybatis+netty;本篇主要講netty與springboot的整合,以及我在這個(gè)過(guò)程中遇到的問(wèn)題,又是怎么去解決的;
正文
我在做springboot與netty整合的時(shí)候在谷歌,百度找了無(wú)數(shù)文章,都沒(méi)有一篇是自己想要的,也達(dá)不到自己所想的目的;
代碼
1. 新建一個(gè)springboot項(xiàng)目,在pom文件中添加netty依賴:
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>5.0.0.Alpha1</version>
</dependency>
2.新建netty服務(wù)
其實(shí)可以復(fù)制上一篇文章的netty的三個(gè)服務(wù)類,做一些稍微的修改就行了;這里為了方便演示,且修都是改好了的,就直接貼出來(lái)了;
DiscardServer類:
@Component
public class DiscardServer {
@Resource
private ChildChannelHandler childChannelHandler;
public void run(int port) throws Exception {
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
System.out.println("準(zhǔn)備運(yùn)行端口:" + port);
try {
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 128)
.childHandler(childChannelHandler);
//綁定端口,同步等待成功
ChannelFuture f = bootstrap.bind(port).sync();
//等待服務(wù)監(jiān)聽(tīng)端口關(guān)閉
f.channel().closeFuture().sync();
} finally {
//退出,釋放線程資源
workerGroup.shutdownGracefully();
bossGroup.shutdownGracefully();
}
}
}
ChildChannelHandler類
@Component
public class ChildChannelHandler extends ChannelInitializer<SocketChannel> {
@Resource
private DiscardServerHandler discardServerHandler;
public void initChannel(SocketChannel socketChannel) throws Exception {
socketChannel.pipeline().addLast(discardServerHandler);
}
}
3.DiscardServerHandler類
特別注意DiscardServerHandler類上需要加@Sharable注解,如果不加的話會(huì)報(bào)錯(cuò);
@Component
@Sharable
public class DiscardServerHandler extends ChannelHandlerAdapter {
@Resource
private BaseService baseService;
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
try {
ByteBuf in = (ByteBuf) msg;
System.out.println("傳輸內(nèi)容是");
System.out.println(in.toString(CharsetUtil.UTF_8));
//這里調(diào)用service服務(wù)
baseService.test();
} finally {
ReferenceCountUtil.release(msg);
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
// 出現(xiàn)異常就關(guān)閉
cause.printStackTrace();
ctx.close();
}
}
3.netty調(diào)用所需的服務(wù)類
1.BaseService接口
public interface BaseService {
/**
* 測(cè)試接口
*/
void test();
}
2.接口實(shí)現(xiàn)類BaseServiceImpl:
@Service
public class BaseServiceImpl implements BaseService {
@Override
public void test() {
System.out.println("調(diào)用service服務(wù)");
}
}
4 springboot啟動(dòng)類
由于main方法是靜態(tài)方法,netty服務(wù)啟動(dòng)類不是靜態(tài)類,在main方法里面需要用new的方式啟動(dòng);
也可以將netty服務(wù)啟動(dòng)類改為靜態(tài)類,然后調(diào)用其他非靜態(tài)的類時(shí)就得用new方法來(lái)構(gòu)造其他類了;
我也百度到了幾篇文章說(shuō)實(shí)現(xiàn)CommandLineRunner接口,所以我用了springboot啟動(dòng)類實(shí)現(xiàn)CommandLineRunner接口的run方法,然后在run方法里啟動(dòng)netty服務(wù)
@SpringBootApplication
public class DemoApplication implements CommandLineRunner {
@Resource
private DiscardServer discardServer;
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
@Override
public void run(String... args) throws Exception {
discardServer.run(8080);
}
}
5.測(cè)試
寫(xiě)一個(gè)能發(fā)送數(shù)據(jù)的socket就可以了;
發(fā)送的數(shù)據(jù)為:
public static void main(String[] args){
try {
Socket socket=new Socket("localhost",8080);
OutputStream outputStream = socket.getOutputStream();
PrintWriter printWriter=new PrintWriter(outputStream);
printWriter.write("$tmb00035ET3318/08/22 11:5804029.94,027.25,20.00,20.00$");
printWriter.flush();
socket.shutdownOutput();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
我的測(cè)試結(jié)果:
傳輸內(nèi)容是 $tmb00035ET3318/08/22 11:5804029.94,027.25,20.00,20.00$ aaaaa
到這里,netty與springboot的整合就完成了;
我在整合過(guò)程中遇到的問(wèn)題
我使用springboot結(jié)合netty的流程
springboot啟動(dòng)類中啟動(dòng)netty啟動(dòng)類(DiscardServer),netty啟動(dòng)類(DiscardServer)再調(diào)用初始化channel類(ChildChannelHandler),然后初始化channel類再調(diào)用(DiscardServerHandler)類;然后DiscardServerHandler類再調(diào)用service服務(wù);如下示例圖:

問(wèn)題:
- springboot啟動(dòng)類我并沒(méi)有實(shí)現(xiàn)CommandLineRunner接口,直接在main方法通過(guò)new的方式啟動(dòng)netty服務(wù)
- 我實(shí)現(xiàn)了CommandLineRunner接口,但是我在run方法中用的new的方式啟動(dòng)的netty服務(wù)或者我在run方法使用注入的方式啟動(dòng)netty,但是在其他某個(gè)地方調(diào)用另一個(gè)類使用了new的方式;
- DiscardServerHandler類上為標(biāo)記@Sharable類,會(huì)報(bào)錯(cuò)誤;
以上總結(jié)起來(lái)的問(wèn)題就是我在springboot整合netty的過(guò)程中有其中一處的調(diào)用其他類時(shí)使用的方式是new構(gòu)造的,這樣雖然springboot能啟動(dòng),netty也能啟動(dòng),但是netty服務(wù)中使用new構(gòu)造的那個(gè)類中無(wú)法依賴注入,會(huì)報(bào)空指針異常;
舉個(gè)栗子:在圖中的過(guò)程中,我在ChildChannelHandler類中通過(guò)new的方式調(diào)用DiscardServerHandler類,其他的過(guò)程都是使用注入的方式調(diào)用,就會(huì)出現(xiàn)上邊的問(wèn)題;
在遇到空指針的時(shí)候,我把spring托管的bean打印了出來(lái),所有的類都在spring的托管中,但是就是無(wú)法注入,我也一直沒(méi)有明白怎么回事,最后用了一個(gè)極端的方法,就是在調(diào)用服務(wù)時(shí),獲取spring的上下文,然后再根據(jù)名字來(lái)獲取bean,你谷歌或百度:非托管類調(diào)用spring托管類,就能找到很多文章了;雖然用這個(gè)方式能解決上述的問(wèn)題,但總是不好的;
最后的解決辦法:所以類之間的調(diào)用都使用spring的依賴注入,別用new的方式來(lái)調(diào)用或者靜態(tài)方法的方式調(diào)用
總結(jié)
既然項(xiàng)目中用到了spring,那么類與類之間的調(diào)用就用依賴注入,不然會(huì)報(bào)空指針的問(wèn)題(就是非托管對(duì)象調(diào)用spring托管對(duì)象);這也算是一個(gè)常識(shí)性的問(wèn)題了,只是自己現(xiàn)在才遇到這樣的問(wèn)題,還是要踩坑才能遇漲記性啊;這些問(wèn)題困擾了我兩三天,還是要有經(jīng)驗(yàn)的人帶,如果有經(jīng)驗(yàn)的人帶的話,說(shuō)不幾分鐘就搞定了;
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Springboot整合Dubbo+Nacos實(shí)現(xiàn)RPC調(diào)用的示例代碼
隨著互聯(lián)網(wǎng)技術(shù)的飛速發(fā)展,越來(lái)越多的企業(yè)和開(kāi)發(fā)者開(kāi)始關(guān)注微服務(wù)架構(gòu),Nacos是阿里巴巴開(kāi)源的一個(gè)動(dòng)態(tài)服務(wù)發(fā)現(xiàn)、配置管理和服務(wù)管理平臺(tái),本文講解如何將Spring Boot與Dubbo和Nacos整合,實(shí)現(xiàn)RPC調(diào)用,需要的朋友可以參考下2024-02-02
springboot中使用Hibernate-Validation校驗(yàn)參數(shù)詳解
這篇文章主要為大家介紹了springboot中使用Hibernate-Validation校驗(yàn)參數(shù)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-07-07
java HashMap,TreeMap與LinkedHashMap的詳解
這篇文章主要介紹了 java HashMap,TreeMap與LinkedHashMap的詳解的相關(guān)資料,這里提供實(shí)例代碼,幫助大家學(xué)習(xí)理解 這部分的內(nèi)容,需要的朋友可以參考下2016-11-11
通過(guò)實(shí)例解析Spring組合注解與元注解
這篇文章主要介紹了通過(guò)實(shí)例解析Spring組合注解與元注解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-11-11
Java框架Struts2實(shí)現(xiàn)圖片上傳功能
這篇文章主要為大家詳細(xì)介紹了Java框架Struts2實(shí)現(xiàn)圖片上傳功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-08-08
Mybatis配置之<environments>配置元素詳解
這篇文章主要介紹了Mybatis配置之<environments>配置元素,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-01-01
關(guān)于Java8新特性O(shè)ptional類的詳細(xì)解讀
Optional類是一個(gè)容器類,它可以保存類型T的值,代表這個(gè)值存在?;蛘邇H僅保存null,表示這個(gè)值不存在,原來(lái)用 null 表示一個(gè)值不存在,現(xiàn)在Optional 可以更好的表達(dá)這個(gè)概念。并且可以避免空指針異常,需要的朋友可以參考下2023-05-05
SpringBoot定時(shí)任務(wù)詳解與案例代碼
SpringBoot是一個(gè)流行的Java開(kāi)發(fā)框架,它提供了許多便捷的特性來(lái)簡(jiǎn)化開(kāi)發(fā)過(guò)程,其中之一就是定時(shí)任務(wù)的支持,讓開(kāi)發(fā)人員可以輕松地在應(yīng)用程序中執(zhí)行定時(shí)任務(wù),本文將詳細(xì)介紹如何在Spring?Boot中使用定時(shí)任務(wù),并提供相關(guān)的代碼示例2023-06-06
mybatis模糊查詢之bind標(biāo)簽和concat函數(shù)用法詳解
大家都知道bind 標(biāo)簽可以使用 OGNL 表達(dá)式創(chuàng)建一個(gè)變量井將其綁定到上下文中,接下來(lái)通過(guò)本文給大家介紹了mybatis模糊查詢——bind標(biāo)簽和concat函數(shù)用法,需要的朋友可以參考下2022-08-08

