Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 在spring引导应用程序部署后动态添加servlet或刷新现有servlet映射_Java_Spring_Spring Boot_Servlets - Fatal编程技术网

Java 在spring引导应用程序部署后动态添加servlet或刷新现有servlet映射

Java 在spring引导应用程序部署后动态添加servlet或刷新现有servlet映射,java,spring,spring-boot,servlets,Java,Spring,Spring Boot,Servlets,我需要一个简单的API代理来为我的spring boot应用程序创建基于来自数据库的值的代理映射。我找到了这个API代理,它很简单,符合我的目的 我发现创建动态代理servlet的唯一方法如下 @ManagedBean public final class ExecutorListener implements ServletContextInitializer { private static final String TARGET_URI = "targetUri";

我需要一个简单的API代理来为我的spring boot应用程序创建基于来自数据库的值的代理映射。我找到了这个API代理,它很简单,符合我的目的

我发现创建动态代理servlet的唯一方法如下

@ManagedBean
public final class ExecutorListener implements ServletContextInitializer {

private static final String TARGET_URI = "targetUri";


@Override
public void onStartup(ServletContext servletContext) throws ServletException {
WebApplicationContext springContext = WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext);
EndpointsRepo endpointrepo = springContext.autowireBean(EndpointsRepo.class);
List<Endpoint> endpoints = endpointrepo.findAll();
for(Endpoint endpoint: endpoints){
    ServletRegistration.Dynamic dispatcher = servletContext.addServlet(endpoint.getEndpointCode(), new ProxyServlet());
    dispatcher.setLoadOnStartup(1);
    dispatcher.setInitParameter(TARGET_URI, endpoint.getEndpointUrl());
    dispatcher.addMapping(endpoint.getUrlPattern());
}

}
@ManagedBean
公共最终类ExecutorListener实现ServletContextInitializer{
私有静态最终字符串TARGET_URI=“targetUri”;
@凌驾
启动时公共void(ServletContext ServletContext)引发ServletException{
WebApplicationContext springContext=WebApplicationContextils.getRequiredWebApplicationContext(servletContext);
EndpointsRepo endpointrepo=springContext.autowireBean(EndpointsRepo.class);
List endpoints=endpointrepo.findAll();
用于(端点:端点){
ServletRegistration.Dynamic dispatcher=servletContext.addServlet(endpoint.getEndpointCode(),new ProxyServlet());
dispatcher.setLoadOnStartup(1);
dispatcher.setInitParameter(TARGET_URI,endpoint.getEndpointUrl());
dispatcher.addMapping(endpoint.getUrlPattern());
}
}
代理现在可以正常工作,除非我更新DB中的映射值,否则需要在动态代理中反映这些值

有没有办法在不重新启动spring boot应用程序的情况下刷新servlet映射?我尝试使用applicationcontext.refresh(),但这是由于DB datasource发出无法关闭的消息并导致内存泄漏造成的


如果我尝试在运行时使用SpringServletRegistration添加一个bean,则创建的映射不起作用。似乎只有在启动之前配置servlet(如spring servlet文档所述)时,servlet映射才起作用。

您不能在初始化阶段后添加其他servlet,因为servlet API规范禁止这样做在第4.4节中,当谈到
ServletContext#addServlet
方法时,它说:

这些方法只能在应用程序初始化期间调用 从
ServletContextListener的
ContextInitialized
方法 实现或从
ServletContainerInitializer
实现

您仍然可以重用
ProxyServlet
类,但是您需要编写自己的servlet(映射到
/*
),它将创建
ProxyServlet
的多个实例,配置它们并将请求路由到正确的实例

编辑:基本上你需要这样一个类:

公共类MetaProxyServlet扩展了HttpServlet{
/**
*在不修改代码的情况下配置{@link ProxyServlet}。
*/
私有静态类ProxyServletConfig实现ServletConfig{
私有静态最终字符串P_TARGET_URI=“targetUri”;
私有最终字符串targetUri;
@凌驾
公共字符串getInitParameter(字符串名称){
返回P_TARGET_URI.equals(name)?targetUri:null;
}
//其他方法
}
/**
*用于修改请求的路径信息。
*/
私有静态类RewritenServletRequest扩展了HttpServletRequestWrapper{
私有最终字符串pathInfo;
@凌驾
公共字符串getPathInfo(){
返回路径信息;
}
//其他方法
}
private TreeMap proxyservlet=new TreeMap();
/**
*在此servlet命名空间的{@code pathPrefix}之间添加反向代理
*和{@code targetUri}。
* 
*@param路径前缀
*必须以“/”开头
*@param targetUri
*要代理的URI
*@ServletException
*/
public void addRedirect(字符串路径前缀,字符串targetUri)引发ServletException{
final ProxyServlet servlet=new ProxyServlet();
init(新的ProxyServletConfig(路径前缀,getServletContext(),targetUri));
put(路径前缀,servlet);
}
@凌驾
受保护的无效服务(HttpServletRequest-req、HttpServletResponse-resp)引发ServletException、IOException{
字符串pathInfo=req.getPathInfo();
Entry=proxyServlets.floorEntry(路径信息);
//entry.getKey()位于前面,但不一定是pathInfo的前缀
if(entry!=null&&pathInfo.startsWith(entry.getKey()){
String rewritenPathInfo=pathInfo.substring(entry.getKey().length());
entry.getValue()//
.服务(新的RewritenServletRequest(req,RewritenSpathInfo),resp);
}否则{
响应发送错误(未找到HttpServletResponse.SC_);
}
}
}

完整的代码已打开。

我尝试了这个方法,但我得到了302重定向,因为响应总是302重定向,302重定向可能是由代理站点生成的。
ProxyServlet
无法正确处理相关重定向。我用一个示例更新了答案。你能解释一下如何在spring boot中使用你的代码吗?这与m servlet配置除了重定向?它是一个
servlet
,因此您可以通过多种方式注册它(参见)并将其映射到例如
/proxy/*
(未使用其他映射进行测试)。一旦您在代码中获得它,您可以调用例如
servlet.addRedirect(“/google”,”https://www.google.com")
。我在Tomcat上对它进行了测试,但从Spring Boot开始,它的工作原理应该是一样的。我从哪里调用servlet.addRedirect?我使用@WebFilter(urlPatterns=“/proxy/*”)将它注册为一个servlet。但是如何动态指定目标url呢?