Sap*_*aik 2 java spring spring-boot
我需要使我的Spring Boot应用程序开始/停止动态监听新端口。我知道为此需要在Spring上下文中注入新的tomcat连接器。
我可以使用ServletWebServerFactoryBean和添加连接器tomcatConnectorCustomizer。但是,此bean仅在Spring Bootup期间加载。
@Bean
public ServletWebServerFactory servletContainer() {
TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory();
TomcatConnectorCustomizer tomcatConnectorCustomizer = connector -> {
connector.setPort(serverPort);
connector.setScheme("https");
connector.setSecure(true);
Http11NioProtocol protocol = (Http11NioProtocol) connector.getProtocolHandler();
protocol.setSSLEnabled(true);
protocol.setKeystoreType("PKCS12");
protocol.setKeystoreFile(keystorePath);
protocol.setKeystorePass(keystorePass);
protocol.setKeyAlias("spa");
protocol.setSSLVerifyClient(Boolean.toString(true));
tomcat.addConnectorCustomizers(tomcatConnectorCustomizer);
return tomcat;
}
}
Run Code Online (Sandbox Code Playgroud)
有什么方法可以在运行时添加tomcat连接器吗?说一个方法调用?
我设法在运行时添加了Tomcat连接器。但是对该端口的请求不会发送到我的RestController。
TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory();
TomcatConnectorCustomizer tomcatConnectorCustomizer = connector -> {
Http11NioProtocol protocol = (Http11NioProtocol) connector.getProtocolHandler();
connector.setScheme("http");
connector.setSecure(false);
connector.setPort(8472);
protocol.setSSLEnabled(false);
};
tomcat.addConnectorCustomizers(tomcatConnectorCustomizer);
tomcat.getWebServer().start();
Run Code Online (Sandbox Code Playgroud)
我应该如何进一步进行?
嗨,这是我的示例项目:示例项目
1-主要应用程序(DemoApplication.java):
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
Run Code Online (Sandbox Code Playgroud)
2-配置文件(AppConfig.java):
@Configuration
public class AppConfig {
@Autowired
private ServletWebServerApplicationContext server;
private static FilterConfig filterConfig = new FilterConfig();
@PostConstruct
void init() {
//setting default port config
filterConfig.addNewPortConfig(8080, "/admin");
}
@Bean
@Scope(value = WebApplicationContext.SCOPE_APPLICATION, proxyMode = ScopedProxyMode.TARGET_CLASS)
public FilterConfig createFilterConfig() {
return filterConfig;
}
public void addPort(String schema, String domain, int port, boolean secure) {
TomcatWebServer ts = (TomcatWebServer) server.getWebServer();
synchronized (this) {
ts.getTomcat().setConnector(createConnector(schema, domain, port, secure));
}
}
public void addContextAllowed(FilterConfig filterConfig, int port, String context) {
filterConfig.addNewPortConfig(port, context);
}
public void removePort(int port) {
TomcatWebServer ts = (TomcatWebServer) server.getWebServer();
Service service = ts.getTomcat().getService();
synchronized (this) {
Connector[] findConnectors = service.findConnectors();
for (Connector connector : findConnectors) {
if (connector.getPort() == port) {
try {
connector.stop();
connector.destroy();
filterConfig.removePortConfig(port);
} catch (LifecycleException e) {
e.printStackTrace();
}
}
}
}
}
private Connector createConnector(String schema, String domain, int port, boolean secure) {
Connector conn = new Connector("org.apache.coyote.http11.Http11NioProtocol");
conn.setScheme(schema);
conn.setPort(port);
conn.setSecure(true);
conn.setDomain(domain);
if (secure) {
// config secure port...
}
return conn;
}
}
Run Code Online (Sandbox Code Playgroud)
3-过滤器(NewPortFilter.java):
public class NewPortFilter {
@Bean(name = "restrictFilter")
public FilterRegistrationBean<Filter> retstrictFilter(FilterConfig filterConfig) {
Filter filter = new OncePerRequestFilter() {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
// get allowed url contexts
Set<String> config = filterConfig.getConfig().get(request.getLocalPort());
if (config == null || config.isEmpty()) {
response.sendError(403);
}
boolean accepted = false;
for (String value : config) {
if (request.getPathInfo().startsWith(value)) {
accepted = true;
break;
}
}
if (accepted) {
filterChain.doFilter(request, response);
} else {
response.sendError(403);
}
}
};
FilterRegistrationBean<Filter> filterRegistrationBean = new FilterRegistrationBean<Filter>();
filterRegistrationBean.setFilter(filter);
filterRegistrationBean.setOrder(-100);
filterRegistrationBean.setName("restrictFilter");
return filterRegistrationBean;
}
}
Run Code Online (Sandbox Code Playgroud)
4-过滤器配置(FilterConfig.java):
public class FilterConfig {
private Map<Integer, Set<String>> acceptedContextsByPort = new ConcurrentHashMap<>();
public void addNewPortConfig(int port, String allowedContextUrl) {
if(port > 0 && allowedContextUrl != null) {
Set<String> set = acceptedContextsByPort.get(port);
if (set == null) {
set = new HashSet<>();
}
set = new HashSet<>(set);
set.add(allowedContextUrl);
acceptedContextsByPort.put(port, set);
}
}
public void removePortConfig(int port) {
if(port > 0) {
acceptedContextsByPort.remove(port);
}
}
public Map<Integer, Set<String>> getConfig(){
return acceptedContextsByPort;
}
}
Run Code Online (Sandbox Code Playgroud)
5-控制器(TestController.java):
@RestController
public class TestController {
@Autowired
AppConfig config;
@Autowired
FilterConfig filterConfig;
@GetMapping("/admin/hello")
String test() {
return "hello test";
}
@GetMapping("/alternative/hello")
String test2() {
return "hello test 2";
}
@GetMapping("/admin/addNewPort")
ResponseEntity<String> createNewPort(@RequestParam Integer port, @RequestParam String context) {
if (port == null || port < 1) {
return new ResponseEntity<>("Invalid Port" + port, HttpStatus.BAD_REQUEST);
}
config.addPort("http", "localhost", port, false);
if (context != null && context.length() > 0) {
config.addContextAllowed(filterConfig, port, context);
}
return new ResponseEntity<>("Added port:" + port, HttpStatus.OK);
}
@GetMapping("/admin/removePort")
ResponseEntity<String> removePort(@RequestParam Integer port) {
if (port == null || port < 1) {
return new ResponseEntity<>("Invalid Port" + port, HttpStatus.BAD_REQUEST);
}
config.removePort(port);
return new ResponseEntity<>("Removed port:" + port, HttpStatus.OK);
}
}
Run Code Online (Sandbox Code Playgroud)
怎么测试呢?
在浏览器中:
1-尝试:
http:// localhost:8080 / admin / hello
预期响应:你好测试
2-尝试:
http:// localhost:8080 / admin / addNewPort?port = 9090&context = alternative
预期响应:已添加端口:9090
3-尝试:
http:// localhost:9090 / alternative / hello
预期响应:你好测试2
4-尝试预期的错误:
http:// localhost:9090 / alternative / addNewPort?port = 8181&context = alternative
预期的响应(允许使用上下文[替代],但端点未在控制器中为此上下文注册):Whitelabel错误页面...
http:// localhost:9090 / any / hello
预期的响应(不允许上下文[任何]):Whitelabel错误页面...
http:// localhost:8888 / any / hello
预期的响应(无效的端口号):ERR_CONNECTION_REFUSED
预期的响应(不允许上下文[/ hello]):Whitelabel错误页面...
5-尝试删除端口:
http:// localhost:8080 / admin / removePort?port = 9090
6-检查已移除的端口:
http:// localhost:9090 / alternative / hello
预期响应(端口关闭):ERR_CONNECTION_REFUSED
希望对您有所帮助。
| 归档时间: |
|
| 查看次数: |
266 次 |
| 最近记录: |