在Netty中处理请求时,调用一个由Spring Boot管理的@Component注解的类
在Netty中处理请求时,调用一个由Spring Boot管理的@Component注解的类,需要确保Spring上下文能够正确地注入这些组件。
方法一:使用@Autowired注入Spring组件
创建Spring配置类:
首先,你需要确保你的Netty服务器是在Spring的上下文中启动的。这通常意味着你的Netty服务器启动代码应该位于一个由Spring管理的类中。
创建spring管理的测试类
@Component
public class VoiceFileImpl {private static final Logger logger = LoggerFactory.getLogger(VoiceFileImpl .class);@Overridepublic void uploadFile(Object msg) {logger.info("语音文件上传");}
}
在Handler中使用@Autowired:
创建一个Netty处理器类,并在其中使用@Autowired注入你的Spring组件。
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;@Component
public class VoiceFileHandler extends ChannelInboundHandlerAdapter {@Autowiredprivate VoiceFileImpl voiceFileImpl;@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {// 使用mySpringComponent处理消息voiceFileImpl.uploadFile(msg);ctx.fireChannelRead(msg);}// 其他处理方法...
}
在Netty管道中注册Handler
确保在Netty的管道(pipeline)中注册你的处理器时,这个处理器实例是从Spring上下文中获取的。
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.stereotype.Component;@Component
public class NettyServer {private ApplicationContext context;// 使用@Autowired注解的setter方法@Autowiredpublic void setApplicationContext(ApplicationContext context) {this.context = context;}public void start(int port) throws Exception {EventLoopGroup bossGroup = new NioEventLoopGroup();EventLoopGroup workerGroup = new NioEventLoopGroup();try {ServerBootstrap b = new ServerBootstrap();b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class).childHandler(new ChannelInitializer<SocketChannel>() {@Overridepublic void initChannel(SocketChannel ch) throws Exception {ChannelPipeline p = ch.pipeline();// 从Spring上下文中获取Handler实例VoiceFileHandler handler = context.getBean(VoiceFileHandler .class);p.addLast(handler);}});b.bind(port).sync().channel().closeFuture().sync();} finally {bossGroup.shutdownGracefully();workerGroup.shutdownGracefully();}}
}
启动Netty服务器
在你的Spring Boot应用程序启动类或其他合适的地方启动Netty服务器。
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class MyApplication implements CommandLineRunner {@Autowiredprivate NettyServer nettyServer;public static void main(String[] args) {SpringApplication.run(MyApplication.class, args);}@Overridepublic void run(String... args) throws Exception {nettyServer.start(8080); // 假设Netty服务器监听8080端口}
}
方法二:使用ApplicationContextAware手动获取Bean(推荐)
创建ApplicationContextProvider类用于手动获取Bean
实现ApplicationContextAware接口来手动获取Spring Bean。
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;@Component
public class ApplicationContextProvider implements ApplicationContextAware {private static ApplicationContext context;@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {context = applicationContext;}public static ApplicationContext getApplicationContext() {return context;}public static <T> T getBean(Class<T> requiredType) {return context.getBean(requiredType);}
}
在Handler中:
public class VoiceFileHandler extends ChannelInboundHandlerAdapter {private VoiceFileImpl voiceFileImpl;public VoiceFileHandler() {this.voiceFileImpl= ApplicationContextProvider.getBean(VoiceFileImpl.class);}@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {voiceFileImpl.uploadFile(msg);ctx.fireChannelRead(msg);}// 其他处理方法...
}
这种方法减少了在每个Handler中注入Spring组件的样板代码,但牺牲了类型安全性(因为getBean方法在编译时不会检查类型)。
创建spring管理的类
@Component
public class VoiceFileImpl {private static final Logger logger = LoggerFactory.getLogger(VoiceFileImpl .class);@Overridepublic void uploadFile(Object msg) {logger.info("语音文件上传");}
}
现状
截止到2025年1月2日下午17点09分,
方案一可能性待定。
方案二已验证通过。