Eric created CXF-8973:
-------------------------
Summary: NettyHttpServerEngineFactory shuts down all netty
instances when SpringContext is shutdown
Key: CXF-8973
URL: https://issues.apache.org/jira/browse/CXF-8973
Project: CXF
Issue Type: Bug
Reporter: Eric
{color:#000000}NettyHttpServerEngineFactory{color} and
{color:#000000}{color:#000000}JettyHttpServerEngineFactory are very similar in
how they manage their ports and their lifecycle. There seems, however, to be
minor difference in the Netty...Factory which seems to be the potential cause
of bugs:
{color}{color}
{color:#000000}{color:#000000}{color:#000000}
{color}{color}{color}
{code:java}
class JettyHTTPServerEngineFactory {
...
JettyHTTPServerEngineFactory(Bus bus) {
setBus(bus);
}
void setBus(Bus bus) {
this.bus = bus;
if (bus != null) {
bus.setExtension(this, JettyHTTPServerEngineFactory.class);
lifeCycleManager = bus.getExtension(BusLifeCycleManager.class);
if (null != lifeCycleManager) {
lifeCycleManager.registerLifeCycleListener(new
JettyBusLifeCycleListener());
}
}
}
class JettyBusLifeCycleListener implements BusLifeCycleListener { ... }
...
{code}
{color:#000000}{color:#000000}vs{color}{color}
{code:java}
class NettyHttpServerEngineFactory implements BusLifeCycleListener {
NettyHttpServerEngineFactory (Bus bus) {
setBus(bus);
}
void setBus(Bus bus) {
this.bus = bus;
if (bus != null) {
bus.setExtension(this, NettyHttpServerEngineFactory.class);
lifeCycleManager = bus.getExtension(BusLifeCycleManager.class);
if (null != lifeCycleManager) {
lifeCycleManager.registerLifeCycleListener(this);
}
}
}
...
{code}
{color:#000000}{color:#000000}Both Variants seem to be very similar, however
there is a subtle difference when it comes to this class:{color}{color}
{code:java}
class CXFBusLifeCycleManager implements BusLifeCycleManager {
void initComplete() {
if (bus != null){
bus.getExtension(ConfiguredBeanLocator.class)
.getBeansOfType(BusLifeCycleListener.class);
}
...
}
...
}{code}
{color:#000000}{color:#000000}Because NettyHttpServerEngineFactory implements
BusLifeCycleListener, it can be found as an Extension in the LifeCycleManager,
which cause the Constructor with the Bus Parameter to be call, which in turn
automatically registers the Factory for automatic shutdown when a spring
context is closed.{color}{color}
{color:#000000}{color:#000000}This can have unexpected side-effects, when, for
example in tests, Spring Contexts are created and destroyed on demand and
combined with indendenpend server instances, like this:
{color}{color}
{code:java}
class TestWithNetty {
@BeforeAll
static void setupServer() {
JAXRSServerFactoryBean sf = new JAXRSServerFactoryBean();
sf.setResourceClasses(SomeWebResource.class);
sf.setAddress("http://localhost:9000");
Server server = sf.create();
}
@RepeatedTest(2)
void runtTestWithSpringContext(@Autowired ApplicationContextRunner runner) {
runner.run(ctx -> // do something with spring context, calling
localhost:9000);
}
}
{code}
{color:#000000}{color:#000000}This scenario, when called with a dependency on
this works:{color}{color}
{code:java}
org.apache.cxf:cxf-rt-transports-http-jetty {code}
{color:#000000}{color:#000000}That is, since netty is never registered as a
outside of the beforeblock{color}{color}
{color:#000000}{color:#000000}The same scenario with netty, however
fails:{color}{color}
{code:java}
org.apache.cxf:cxf-rt-transports-http-netty-server {code}
{color:#000000}{color:#000000}That is the Case because after the first test,
the spring context is shutdown, which has the side effekt of destroying all
netty servers, even those which where never managed by spring at all, simply
because the constructor NettyHttpServerEngineFactory (Bus bus) was implicitly
called by .getBeansOfType(BusLifeCycleListener.class), which registered the
factory in the LifeCycle of the SpringBus{color}{color}
--
This message was sent by Atlassian Jira
(v8.20.10#820010)