001/* 002 * Copyright 2002-2018 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.http.client.reactive; 018 019 020import java.nio.ByteBuffer; 021import java.util.concurrent.Executor; 022 023import org.eclipse.jetty.io.ByteBufferPool; 024import org.eclipse.jetty.io.MappedByteBufferPool; 025import org.eclipse.jetty.util.ProcessorUtils; 026import org.eclipse.jetty.util.component.LifeCycle; 027import org.eclipse.jetty.util.thread.QueuedThreadPool; 028import org.eclipse.jetty.util.thread.ScheduledExecutorScheduler; 029import org.eclipse.jetty.util.thread.Scheduler; 030import org.eclipse.jetty.util.thread.ThreadPool; 031 032import org.springframework.beans.factory.DisposableBean; 033import org.springframework.beans.factory.InitializingBean; 034import org.springframework.lang.Nullable; 035import org.springframework.util.Assert; 036 037/** 038 * Factory to manage Jetty resources, i.e. {@link Executor}, {@link ByteBufferPool} and 039 * {@link Scheduler}, within the lifecycle of a Spring {@code ApplicationContext}. 040 * 041 * <p>This factory implements {@link InitializingBean} and {@link DisposableBean} 042 * and is expected typically to be declared as a Spring-managed bean. 043 * 044 * @author Sebastien Deleuze 045 * @since 5.1 046 */ 047public class JettyResourceFactory implements InitializingBean, DisposableBean { 048 049 @Nullable 050 private Executor executor; 051 052 @Nullable 053 private ByteBufferPool byteBufferPool; 054 055 @Nullable 056 private Scheduler scheduler; 057 058 private String threadPrefix = "jetty-http"; 059 060 061 /** 062 * Configure the {@link Executor} to use. 063 * <p>By default, initialized with a {@link QueuedThreadPool}. 064 * @param executor the executor to use 065 */ 066 public void setExecutor(@Nullable Executor executor) { 067 this.executor = executor; 068 } 069 070 /** 071 * Configure the {@link ByteBufferPool} to use. 072 * <p>By default, initialized with a {@link MappedByteBufferPool}. 073 * @param byteBufferPool the {@link ByteBuffer} pool to use 074 */ 075 public void setByteBufferPool(@Nullable ByteBufferPool byteBufferPool) { 076 this.byteBufferPool = byteBufferPool; 077 } 078 079 /** 080 * Configure the {@link Scheduler} to use. 081 * <p>By default, initialized with a {@link ScheduledExecutorScheduler}. 082 * @param scheduler the {@link Scheduler} to use 083 */ 084 public void setScheduler(@Nullable Scheduler scheduler) { 085 this.scheduler = scheduler; 086 } 087 088 /** 089 * Configure the thread prefix to initialize {@link QueuedThreadPool} executor with. This 090 * is used only when a {@link Executor} instance isn't 091 * {@link #setExecutor(Executor) provided}. 092 * <p>By default set to "jetty-http". 093 * @param threadPrefix the thread prefix to use 094 */ 095 public void setThreadPrefix(String threadPrefix) { 096 Assert.notNull(threadPrefix, "Thread prefix is required"); 097 this.threadPrefix = threadPrefix; 098 } 099 100 /** 101 * Return the configured {@link Executor}. 102 */ 103 @Nullable 104 public Executor getExecutor() { 105 return this.executor; 106 } 107 108 /** 109 * Return the configured {@link ByteBufferPool}. 110 */ 111 @Nullable 112 public ByteBufferPool getByteBufferPool() { 113 return this.byteBufferPool; 114 } 115 116 /** 117 * Return the configured {@link Scheduler}. 118 */ 119 @Nullable 120 public Scheduler getScheduler() { 121 return this.scheduler; 122 } 123 124 @Override 125 public void afterPropertiesSet() throws Exception { 126 String name = this.threadPrefix + "@" + Integer.toHexString(hashCode()); 127 if (this.executor == null) { 128 QueuedThreadPool threadPool = new QueuedThreadPool(); 129 threadPool.setName(name); 130 this.executor = threadPool; 131 } 132 if (this.byteBufferPool == null) { 133 this.byteBufferPool = new MappedByteBufferPool(2048, 134 this.executor instanceof ThreadPool.SizedThreadPool 135 ? ((ThreadPool.SizedThreadPool) executor).getMaxThreads() / 2 136 : ProcessorUtils.availableProcessors() * 2); 137 } 138 if (this.scheduler == null) { 139 this.scheduler = new ScheduledExecutorScheduler(name + "-scheduler", false); 140 } 141 142 if (this.executor instanceof LifeCycle) { 143 ((LifeCycle)this.executor).start(); 144 } 145 this.scheduler.start(); 146 } 147 148 @Override 149 public void destroy() throws Exception { 150 try { 151 if (this.executor instanceof LifeCycle) { 152 ((LifeCycle)this.executor).stop(); 153 } 154 } 155 catch (Throwable ex) { 156 // ignore 157 } 158 try { 159 if (this.scheduler != null) { 160 this.scheduler.stop(); 161 } 162 } 163 catch (Throwable ex) { 164 // ignore 165 } 166 } 167 168}