You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@cxf.apache.org by "Andriy Redko (Jira)" <ji...@apache.org> on 2024/02/20 23:57:00 UTC

[jira] [Resolved] (CXF-8973) NettyHttpServerEngineFactory shuts down all netty instances when SpringContext is shutdown

     [ https://issues.apache.org/jira/browse/CXF-8973?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]

Andriy Redko resolved CXF-8973.
-------------------------------
    Resolution: Not A Problem

> 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
>            Priority: Major
>
> {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)