SpringBoot的AutoConfiguration會根據類路徑是否有servlet來判斷是不是web項目,也能夠本身強制指定。java
@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文件上。git
<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 IOCgithub
<!-- 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>
@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