Spring @Autowired仓库在Netty重写方法中无法注入问题求助
问题:Netty WebSocketHandler中@Autowired注入的Repository始终为null
开发基于Spring Data的Netty Socket项目时,发现WebSocketHandler中通过@Autowired注入的AccountRepository在重写的channelRead方法里始终返回null,尝试用@PostConstruct调用也无法解决。
代码示例
AccountRepository.java
@Repository public interface AccountRepository extends CassandraRepository<Account, UUID> {}
WebSocketHandler.java
@Service public class WebSocketHandler extends ChannelInboundHandlerAdapter { public static List<String> requiredData = Arrays.asList( "request_type" ); @Autowired private AccountRepository accountRepository; @Override public void channelRead(ChannelHandlerContext ctx, Object msg) { if(!(msg instanceof TextWebSocketFrame)) return; System.out.println(accountRepository);//此处始终返回null JSONObject data; try { data = new JSONObject(((TextWebSocketFrame) msg).text()); } catch (Exception ex) { return; } for(String required : requiredData) { try { data.get(required); } catch (Exception ex) { return; } } RequestModule requestModule = RequestAdapter.getModule(data.get("request_type").toString()); if(requestModule == null) return; requestModule.onAction(ctx, data); } }
Netty.java
public class Netty { private UnorderedThreadPoolEventExecutor executorGroup; public Netty() { UtilConsole.log("Netty sunucusu aktifleşiyor..."); try { enable(); } catch (Exception ex) { ex.printStackTrace(); } } private void enable() throws Exception { ResourceLeakDetector.setLevel( ResourceLeakDetector.Level.DISABLED ); // Eats performance EventLoopGroup producer = new NioEventLoopGroup(32); EventLoopGroup consumer = new NioEventLoopGroup(32); try{ executorGroup = new UnorderedThreadPoolEventExecutor(32); ServerBootstrap bootstrap = new ServerBootstrap() .option(ChannelOption.SO_BACKLOG, 1024) .group(producer, consumer) .channel(NioServerSocketChannel.class) .handler(new LoggingHandler(LogLevel.INFO)) .childHandler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel channel) throws Exception { ChannelPipeline pipeline = channel.pipeline(); pipeline.addLast("httpServerCodec", new HttpServerCodec()); pipeline.addLast(new HttpObjectAggregator(Short.MAX_VALUE)); pipeline.addLast(executorGroup, "httpHandler", new NettyListener()); } }) .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 100000) .option(ChannelOption.SO_RCVBUF, Integer.MAX_VALUE); UtilConsole.log("Netty sunucusu aktif edildi!"); bootstrap.bind(Configuration.NETTY_PORT).sync().channel().closeFuture().sync(); }catch(Exception ex){ ex.printStackTrace(); UtilConsole.log("Netty sunucusu aktif edilemedi."); throw ex; }finally{ producer.shutdownGracefully(); consumer.shutdownGracefully(); } } }
NettyListener.java
public class NettyListener extends ChannelInboundHandlerAdapter { private WebSocketServerHandshaker handshaker; @Override public void channelRead(ChannelHandlerContext ctx, Object msg){ if(msg instanceof HttpRequest){ HttpRequest httpRequest = (HttpRequest) msg; HttpHeaders headers = httpRequest.headers(); if("Upgrade".equalsIgnoreCase(headers.get(HttpHeaderNames.CONNECTION)) && "WebSocket".equalsIgnoreCase(headers.get(HttpHeaderNames.UPGRADE))){ ctx.pipeline().replace(this, "websocketHandler", new WebSocketHandler()); handleHandshake(ctx, httpRequest); } } } }
问题根因
核心问题是你手动创建了WebSocketHandler实例:在NettyListener里直接new WebSocketHandler(),这个对象完全脱离Spring容器的管理范围。Spring的依赖注入仅对自身创建并托管的Bean生效,因此@Autowired标注的accountRepository不会被填充,始终为null。
解决方案
让WebSocketHandler和NettyListener都交由Spring容器管理,从容器中获取实例而非手动new。
1. 修改NettyListener,注入Spring上下文并获取WebSocketHandler
@Component public class NettyListener extends ChannelInboundHandlerAdapter { private WebSocketServerHandshaker handshaker; @Autowired private ApplicationContext applicationContext; @Override public void channelRead(ChannelHandlerContext ctx, Object msg){ if(msg instanceof HttpRequest){ HttpRequest httpRequest = (HttpRequest) msg; HttpHeaders headers = httpRequest.headers(); if("Upgrade".equalsIgnoreCase(headers.get(HttpHeaderNames.CONNECTION)) && "WebSocket".equalsIgnoreCase(headers.get(HttpHeaderNames.UPGRADE))){ // 从Spring容器获取托管的WebSocketHandler实例 WebSocketHandler webSocketHandler = applicationContext.getBean(WebSocketHandler.class); ctx.pipeline().replace(this, "websocketHandler", webSocketHandler); handleHandshake(ctx, httpRequest); } } } // 补充握手逻辑(原代码缺失,需实现) private void handleHandshake(ChannelHandlerContext ctx, HttpRequest req) { WebSocketServerHandshakerFactory factory = new WebSocketServerHandshakerFactory( getWebSocketUrl(req), null, true); handshaker = factory.newHandshaker(req); if (handshaker == null) { WebSocketServerHandshakerFactory.sendUnsupportedVersionResponse(ctx.channel()); } else { handshaker.handshake(ctx.channel(), req); } } private String getWebSocketUrl(HttpRequest req) { return "ws://" + req.headers().get(HttpHeaderNames.HOST) + req.uri(); } }
2. 修改Netty类,交由Spring管理并注入NettyListener
@Component public class Netty { private UnorderedThreadPoolEventExecutor executorGroup; @Autowired private NettyListener nettyListener; @PostConstruct public void start() { UtilConsole.log("Netty sunucusu aktifleşiyor..."); try { enable(); } catch (Exception ex) { ex.printStackTrace(); } } private void enable() throws Exception { ResourceLeakDetector.setLevel( ResourceLeakDetector.Level.DISABLED ); EventLoopGroup producer = new NioEventLoopGroup(32); EventLoopGroup consumer = new NioEventLoopGroup(32); try{ executorGroup = new UnorderedThreadPoolEventExecutor(32); ServerBootstrap bootstrap = new ServerBootstrap() .option(ChannelOption.SO_BACKLOG, 1024) .group(producer, consumer) .channel(NioServerSocketChannel.class) .handler(new LoggingHandler(LogLevel.INFO)) .childHandler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel channel) throws Exception { ChannelPipeline pipeline = channel.pipeline(); pipeline.addLast("httpServerCodec", new HttpServerCodec()); pipeline.addLast(new HttpObjectAggregator(Short.MAX_VALUE)); // 使用Spring托管的NettyListener实例 pipeline.addLast(executorGroup, "httpHandler", nettyListener); } }) .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 100000) .option(ChannelOption.SO_RCVBUF, Integer.MAX_VALUE); UtilConsole.log("Netty sunucusu aktif edildi!"); bootstrap.bind(Configuration.NETTY_PORT).sync().channel().closeFuture().sync(); }catch(Exception ex){ ex.printStackTrace(); UtilConsole.log("Netty sunucusu aktif edilemedi."); throw ex; }finally{ producer.shutdownGracefully(); consumer.shutdownGracefully(); } } }
3. 额外注意
确保你的Spring配置类(如启动类)添加了@SpringBootApplication或@ComponentScan注解,保证@Service、@Component标注的类能被Spring扫描并托管。
内容的提问来源于stack exchange,提问作者TNYCL
相关产品推荐
相关产品推荐

