一、rpc是什么?
rpc远程服务过程调用,通过请求来完成远程服务的调用,以下案例为获取山东各地市随机天气信息。
二、使用步骤
1.引入库
代码如下(示例):
<!-- https://mvnrepository.com/artifact/io.netty/netty-all -->
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.80.Final</version>
</dependency>
2.读入数据
2.1 服务接口
WeatherService.java
enum CityCode、WeatherCode
package netty.rpc.service;
import java.util.Arrays;
/**
* Create by zjg on 2022/10/16
*/
public interface WeatherService {
/**
* 天气查询服务
* @param cityCode 城市代码
* @return 城市名称
*/
String queryWeather(int cityCode);
enum CityCode{
JINAN("济南",101120101),
WEIFANG("潍坊",101120601),
LINYI("临沂",101120901),
HEZE("菏泽",101121001),
BINZHOU("滨州",101121101),
DONGYING("东营",101121201),
WEIHAI("威海",101121301),
ZAOZHUANG("枣庄",101121401),
RIZHAO("日照",101121501),
LIAOCHENG("聊城",101121701),
QINGDAO("青岛",101120201),
ZIBO("淄博",101120301),
DEZHOU("德州",101120401),
YANTAI("烟台",101120501),
JINING("济宁",101120701),
TAIAN("泰安",101120801);
String city;
int cityCode = 0;
CityCode(String city, int cityCode) {
this.city = city;
this.cityCode = cityCode;
}
public String getCity() {
return city;
}
public int getCityCode() {
return cityCode;
}
public static String getCity(int cityCode){
String city=null;
CityCode[] values = CityCode.values();
for (CityCode value:values) {
if(cityCode==value.cityCode){
return value.city;
}
}
return null;
}
public static CityCode getCityCode(int cityCode){
CityCode[] values = CityCode.values();
for (CityCode value:values) {
if(cityCode==value.cityCode){
return value;
}
}
return null;
}
public static int[] getcityCodeArray(){
CityCode[] cityCodes = CityCode.values();
return Arrays.stream(cityCodes).mapToInt((cityCode)->{
return cityCode.getCityCode();
}).toArray();
}
}
enum WeatherCode{
RAINSTORM(0,"暴雨"),
HEAVYRAIN(1,"大雨"),
MODERATERAIN(2,"中雨"),
LIGHTRAIN(3,"小雨"),
SUNNY(4,"晴"),
CLOUDYTOCLEAR(5,"多云转晴"),
CLOUDY(6,"多云");
int code;
String weather;
WeatherCode(int code, String weather) {
this.code = code;
this.weather = weather;
}
public int getCode() {
return code;
}
public String getWeather() {
return weather;
}
public static String getWeather(int i) {
WeatherCode[] values = WeatherCode.values();
return values[i].weather;
}
public static int getWeatherSize() {
return WeatherCode.values().length;
}
}
}
2.2 生产者
NettyServer.java
package netty.rpc.provider;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
/**
* Create by zjg on 2022/10/16
*/
public class NettyServer {
public static void main(String[] args) {
NioEventLoopGroup bossGroup = null;
NioEventLoopGroup workGroup= null;
try {
bossGroup=new NioEventLoopGroup();
workGroup=new NioEventLoopGroup();
ServerBootstrap bootstrap=new ServerBootstrap();
bootstrap.group(bossGroup,workGroup)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG,128)
.childOption(ChannelOption.SO_KEEPALIVE,true)
.childHandler(new ChannelInitializer() {
@Override
protected void initChannel(Channel channel) throws Exception {
ChannelPipeline pipeline = channel.pipeline();
pipeline.addLast(new StringDecoder());
pipeline.addLast(new StringEncoder());
pipeline.addLast(new NettyServerHandler());
}
});
ChannelFuture channelFuture = bootstrap.bind(8080).sync();
System.out.println("服务端启动完成!");
channelFuture.channel().closeFuture().sync();
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
bossGroup.shutdownGracefully();
workGroup.shutdownGracefully();
}
}
}
NettyServerHandler.java
package netty.rpc.provider;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
/**
* Create by zjg on 2022/10/16
*/
public class NettyServerHandler extends ChannelInboundHandlerAdapter {
private static final String PROTOCOL="#rpc#";
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
String message = msg.toString();
String response;
if(message.startsWith(PROTOCOL)){
String req = message.substring(message.indexOf(PROTOCOL) + PROTOCOL.length());
System.out.println();
System.out.println("接收到客户端请求:"+req);
response = new WeatherServiceImpl().queryWeather(Integer.valueOf(req));
System.out.println("服务端响应:"+response);
ctx.writeAndFlush(response);
}else{
response="未知的协议,请更换协议格式!";
ctx.writeAndFlush(response);
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
System.out.println("异常");
cause.printStackTrace();
ctx.close();
}
}
业务实现类:
WeatherServiceImpl.java
package netty.rpc.provider;
import netty.rpc.service.WeatherService;
import org.apache.commons.lang3.RandomUtils;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
/**
* Create by zjg on 2022/10/16
* 山东各地市随机天气预报
*/
public class WeatherServiceImpl implements WeatherService {
@Override
public String queryWeather(int cityCode) {
LocalDate localDate = LocalDate.now();
String now = localDate.format(DateTimeFormatter.ofPattern("MM月dd日"));
CityCode cityCodeEnum = CityCode.getCityCode(cityCode);
String city = cityCodeEnum.getCity();
int weatherSize = WeatherCode.getWeatherSize();
int i = RandomUtils.nextInt(0, weatherSize);
String weather=WeatherCode.getWeather(i);
return now+" "+city+" "+weather;
}
}
2.3 消费者
NettyClient.java
package netty.rpc.consumer;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import netty.rpc.service.WeatherService;
import java.lang.reflect.Proxy;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* Create by zjg on 2022/10/16
*/
public class NettyClient {
private static final String INETHOST="127.0.1.1";
private static final int INETPORT=8080;
private static NettyClientHandler nettyClientHandler=null;
private static ExecutorService executorService=Executors.newFixedThreadPool(5);
private static ChannelFuture channelFuture = null;
private static NioEventLoopGroup nioEventLoopGroup=null;
private static final String PROTOCOL_01="#rpc#";
public static void main(String[] args) {
WeatherService weatherService= (WeatherService) getService(WeatherService.class,PROTOCOL_01);
int[] codeArray = WeatherService.CityCode.getcityCodeArray();
for(int i=0;i<codeArray.length;i++){
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
String weather = weatherService.queryWeather(codeArray[i]);
System.out.println("响应:"+weather);
}
System.out.println("结束");
close();
}
public static Object getService(final Class<?> service, String protocol){
return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),new Class[]{service},(proxy, method, arg)->{
if(nettyClientHandler==null){
initNettyClient(INETHOST,INETPORT);
}
nettyClientHandler.setRquest(protocol+arg[0]);
return executorService.submit(nettyClientHandler).get();
});
}
public static void initNettyClient(String inetHost,int inetPort){
nettyClientHandler=new NettyClientHandler();
try {
nioEventLoopGroup=new NioEventLoopGroup();
Bootstrap bootstrap=new Bootstrap();
bootstrap.group(nioEventLoopGroup)
.channel(NioSocketChannel.class)
.option(ChannelOption.TCP_NODELAY,true)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
ChannelPipeline pipeline = socketChannel.pipeline();
pipeline.addLast(new StringDecoder());
pipeline.addLast(new StringEncoder());
pipeline.addLast(nettyClientHandler);
}
});
channelFuture = bootstrap.connect(inetHost,inetPort ).sync();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void close(){
executorService.shutdownNow();
channelFuture.channel().closeFuture();
nioEventLoopGroup.shutdownGracefully();
}
}
NettyClientHandler.java
package netty.rpc.consumer;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import java.util.concurrent.Callable;
/**
* Create by zjg on 2022/10/16
*/
public class NettyClientHandler extends ChannelInboundHandlerAdapter implements Callable {
private ChannelHandlerContext channelHandlerContext;
private String para;
private String result;
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
channelHandlerContext=ctx;
}
@Override
public synchronized void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
result=msg.toString();
notify();
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
public void setRquest(String request){
this.para=request;
}
@Override
public synchronized Object call() throws Exception {
channelHandlerContext.writeAndFlush(para);
wait();
return result;
}
}
总结
简单版的。