You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 15:45:34