我想从像Wildfly这样的Java EE容器中提供套接字,但在Oracle site上发现了这个EJB限制:
为什么企业bean不能监听或接受套接字上的连接?
因为如果企业bean正在监听套接字,它就无法被钝化 - 它必须始终可用。
我向Java EE专家提出了同样的问题并回答说#34;只有状态bean被钝化,所以从单独的无状态启动bean中提供套接字是好的,因为它没有被钝化"。
然而,我随后查阅了EJB 3.2规范并找到了另一种解释:
企业bean不得尝试侦听套接字,接受连接 套接字上的离子,或使用套接字进行多播
EJB体系结构允许企业bean实例成为网络套接字客户端,但它不允许它成为网络服务器。允许实例成为网络服务器会与企业bean的基本功能发生冲突 - 为EJB客户端提供服务。
唉。现在我很困惑。我真的不明白。
此限制是否已过时? 是否是没有单例启动bean(< EJB 3.1)?
的时候的遗留问题类似于以下方法(使用Netty)甚至更简单的方法与Java ServerSocketChannel
接受托管线程中的客户端连接有什么错误。 (不确定Netty是否会产生自己的线程)。
有人可以解释这个限制吗?
@Singleton
@Startup
public class SocketServerBean {
@Resource
private ManagedExecutorService managedExecutorService;
private Channel channel;
@PostConstruct
private void startup() {
EventLoopGroup bossGroup = new NioEventLoopGroup(1, managedExecutorService);
EventLoopGroup workerGroup = new NioEventLoopGroup(1, managedExecutorService);
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
// ...
}
})
.option(ChannelOption.SO_BACKLOG, 128)
.childOption(ChannelOption.SO_KEEPALIVE, true);
// Bind and start to accept incoming connections.
channel = b.bind(6789).channel();
} catch (Exception e) {
e.printStackTrace();
}
}
@PreDestroy
private void shutdown() {
channel.close();
}
}
答案 0 :(得分:1)
为什么企业bean不能监听或接受套接字上的连接?
因为EJB必须充当客户端,而不是服务器。这是EJB 3.2规范确认的。技术原因是EJB本质上是可序列化的,开放流(套接字,文件等)肯定不可序列化。
您的功能需求的正确方法是仅使用CDI托管bean,而不是EJB。
@ApplicationScoped
public class SocketServerBean {
public void startup(@Observes @Initialized(ApplicationScoped.class) ServletContext context) {
// ...
}
@PreDestroy
private void shutdown() {
// ...
}
}
@Observes @Initialized(ApplicationScoped.class)
将确保在应用程序初始化期间构造它。
在这个CDI托管bean中,如果需要,您可以反过来注入EJB。
无关到具体问题,在stinks上从Java EE应用程序手动打开套接字。你确定你也没有用这种方法遇到另一个XY-problem吗?也许你真的想用网络套接字?如果是这样,请改用JSR-356 @ServerEndpoint
。