Camel에서 제공하는 Netty Http 컴포넌트 클래스는 org.apache.camel.component.netty.http.NettyHttpComponent이다.
해당 컴포넌트를 이용하여 서버 모드를 기동할 때 org.apache.camel.component.netty.http.NettyHttpEndpoint의 createConsumer()가 호출된다.
@Override
public Consumer createConsumer(Processor processor) throws Exception {
NettyHttpConsumer answer = new NettyHttpConsumer(this, processor, getConfiguration());
configureConsumer(answer);
if (nettySharedHttpServer != null) {
answer.setNettyServerBootstrapFactory(nettySharedHttpServer.getServerBootstrapFactory());
LOG.info("NettyHttpConsumer: {} is using NettySharedHttpServer on port: {}", answer,
nettySharedHttpServer.getPort());
} else {
// reuse pipeline factory for the same address
HttpServerBootstrapFactory factory = getComponent().getOrCreateHttpNettyServerBootstrapFactory(answer);
// force using our server bootstrap factory
answer.setNettyServerBootstrapFactory(factory);
LOG.debug("Created NettyHttpConsumer: {} using HttpServerBootstrapFactory: {}", answer, factory);
}
return answer;
}
getComponent().getOrCreateHttpNettyServerBootstrapFactory(answer)를 호출하게 되는데, getComponent()가 NettyHttpComponent 이고 해당 코드는 아래와 같다.
protected synchronized HttpServerBootstrapFactory getOrCreateHttpNettyServerBootstrapFactory(NettyHttpConsumer consumer) {
String key = consumer.getConfiguration().getAddress();
HttpServerBootstrapFactory answer = bootstrapFactories.get(key);
if (answer == null) {
HttpServerConsumerChannelFactory channelFactory = getMultiplexChannelHandler(consumer.getConfiguration().getPort());
answer = new HttpServerBootstrapFactory(channelFactory);
answer.init(getCamelContext(), consumer.getConfiguration(), new HttpServerInitializerFactory(consumer));
bootstrapFactories.put(key, answer);
}
return answer;
}
Address를 key로하여 Map 타입의 bootstrapFactories에 존재여부를 판단하여, 존재하지 않을 경우, 새로운 HttpServerBootstrapFactory 객체를 생성하고, 있을 경우, 그 설정을 그대로 사용.
따라서 초기에 설정하는 HttpServerBootstrapFactory의 NettyServerBootstrapConfiguration이 항상 로드된 채로 사용하게 됨.
만약 로드된 상태에서, 새롭게 엔드포인트를 활성화할 경우, 기존 캐시에 저장되어 있던 HttpServerBootstrapFactory의 NettyServerBootstrapConfiguration과 새롭게 엔드포인트를 전달한 설정값을 확인하여, 다른 경우 에러 발생함. 코드는 아래와 같음
HttpServerBootstrapFactory.addConsumer
@Override
public void addConsumer(NettyConsumer consumer) {
if (compatibleCheck) {
// when adding additional consumers on the same port (eg to reuse port for multiple routes etc) then the Netty server bootstrap
// configuration must match, as its the 1st consumer that calls the init method, which configuration is used for the Netty server bootstrap
// we do this to avoid mis configuration, so people configure SSL and plain configuration on the same port etc.
// first it may be the same instance, so only check for compatibility of different instance
if (bootstrapConfiguration != consumer.getConfiguration()
&& !bootstrapConfiguration.compatible(consumer.getConfiguration())) {
throw new IllegalArgumentException(
"Bootstrap configuration must be identical when adding additional consumer: " + consumer.getEndpoint()
+ " on same port: " + port
+ ".\n Existing " + bootstrapConfiguration.toStringBootstrapConfiguration()
+ "\n New "
+ consumer.getConfiguration().toStringBootstrapConfiguration());
}
}
if (LOG.isDebugEnabled()) {
NettyHttpConsumer httpConsumer = (NettyHttpConsumer) consumer;
LOG.debug("BootstrapFactory on port {} is adding consumer with context-path {}", port,
httpConsumer.getConfiguration().getPath());
}
channelFactory.addConsumer((NettyHttpConsumer) consumer);
}
만약 새롭게 엔드포인트를 올릴때마다, 옵션이 바뀌는 경우 NettyHttpComponent를 stop하고, 새로운 NettyHttpComponent 객체를 만들던지, bootstrapFactories이 캐싱하는 로직을 제거.
필자는 bootstrapFactories에 캐싱하는 로직을 제거하였음. 다만, 제거하여 현재 어떠한 문제가 발생할지 의문.