SpringBoot的非web工程
SpringBoot的AutoConfiguration会根据类路径是否有servlet来判断是否是web项目,也可以自己强制指定。
@SpringBootApplication
public class RpcServerApplication {
public static void main(String[] args){
SpringApplication app = new SpringApplication(RpcServerApplication.class);
app.setWebEnvironment(false);
app.run(args);
}
}
添加依赖
如果是多模块的项目,由于子模块已经有parent了,所以只能把spring boot的parent放到子模块的parent的pom文件上。
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.3.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
Spring IOC
<!-- spring ioc -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
在bean初始化之后启动
@Component
//实现ApplicationContextAware以获得ApplicationContext中的所有bean
public class NettyServer implements ApplicationContextAware {
private static final Logger logger = LoggerFactory.getLogger(NettyServer.class);
private Channel channel;
private EventLoopGroup bossGroup;
private EventLoopGroup workerGroup;
private Map<String, Object> exportServiceMap = new HashMap<String, Object>();
@Value("${rpcServer.host:127.0.0.1}")
String host;
@Value("${rpcServer.ioThreadNum:5}")
int ioThreadNum;
//内核为此套接口排队的最大连接个数,对于给定的监听套接口,内核要维护两个队列,未链接队列和已连接队列大小总和最大值
@Value("${rpcServer.backlog:1024}")
int backlog;
@Value("${rpcServer.port:9090}")
int port;
/**
* 启动
* @throws InterruptedException
*/
@PostConstruct
public void start() throws InterruptedException {
logger.info("begin to start rpc server");
bossGroup = new NioEventLoopGroup();
workerGroup = new NioEventLoopGroup(ioThreadNum);
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, backlog)
//注意是childOption
.childOption(ChannelOption.SO_KEEPALIVE, true)
.childOption(ChannelOption.TCP_NODELAY, true)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
socketChannel.pipeline()
//真实数据最大字节数为Integer.MAX_VALUE,解码时自动去掉前面四个字节
//io.netty.handler.codec.DecoderException: java.lang.IndexOutOfBoundsException: readerIndex(900) + length(176) exceeds writerIndex(1024): UnpooledUnsafeDirectByteBuf(ridx: 900, widx: 1024, cap: 1024)
.addLast("decoder", new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 4, 0, 4))
.addLast("encoder", new LengthFieldPrepender(4, false))
.addLast(new RpcDecoder(RpcRequest.class))
.addLast(new RpcEncoder(RpcResponse.class))
.addLast(new ServerRpcHandler(exportServiceMap));
}
});
channel = serverBootstrap.bind(host,port).sync().channel();
logger.info("NettyRPC server listening on port " + port + " and ready for connections...");
}
@PreDestroy
public void stop() {
logger.info("destroy server resources");
if (null == channel) {
logger.error("server channel is null");
}
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
channel.closeFuture().syncUninterruptibly();
bossGroup = null;
workerGroup = null;
channel = null;
}
/**
* 利用此方法获取spring ioc接管的所有bean
* @param ctx
* @throws BeansException
*/
public void setApplicationContext(ApplicationContext ctx) throws BeansException {
Map<String, Object> serviceMap = ctx.getBeansWithAnnotation(ServiceExporter.class); // 获取所有带有 ServiceExporter 注解的 Spring Bean
logger.info("获取到所有的RPC服务:{}", serviceMap);
if (serviceMap != null && serviceMap.size() > 0) {
for (Object serviceBean : serviceMap.values()) {
String interfaceName = serviceBean.getClass().getAnnotation(ServiceExporter.class)
.targetInterface()
.getName();
logger.info("register service mapping:{}",interfaceName);
exportServiceMap.put(interfaceName, serviceBean);
}
}
}
}
工程netty-rpc
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。