10

Tomcat 提供了“虚拟主机”支持的构建:可以将引擎/Web 应用程序配置为负责域列表。这些域必须使用特殊的 xml 指令放入 server.xml/context.xml 文件中。

=> 是否有可能以编程方式更改 Tomcat 配置(通常),尤其是 Web 应用程序/引擎的“虚拟主机”?

例如,如果一个新用户注册,我必须将他的域添加到“接受的虚拟主机/域”列表中。我目前想到的唯一方法是通过脚本更改 xml 文件,然后重新启动 Tomcat。

有没有办法通过一些Java方法以编程方式添加它们添加运行时?

非常感谢!简

4

5 回答 5

8

Tomcat 提供 API 来创建新的虚拟主机。要访问为此所需的包装器对象,您需要实现一个 ContainerServlet。您可以像这样创建虚拟主机,

    Context context = (Context) wrapper.getParent();
    Host currentHost = (Host) context.getParent();
    Engine engine = (Engine) currentHost.getParent();

    StandardHost host = new StandardHost();
    host.setAppBase(appBase);
    host.setName(domainName);

    engine.addChild(host);

您需要确保 appBase 目录存在,并且您必须找到将新主机持久保存到 server.xml 的方法,否则您会在重新启动时丢失主机。

但是,这种方法很少奏效。如果您的用户运行他们自己的应用程序,您真的希望运行单独的 Tomcat 实例,以便您可以更好地对应用程序进行沙箱处理。例如,一个应用程序内存不足并不会杀死所有其他应用程序。

如果您提供应用程序,您可以只使用一台主机(默认主机)。您可以从标头中获取域名Host并在代码中执行任何特定于域的内容。

于 2009-11-13T13:49:56.210 回答
3

使用 JMX

ArrayList serverList = MBeanServerFactory.findMBeanServer(null);
MBeanServer server = (MBeanServer) serverList.get(0);
Object[] params = { "org.apache.catalina.core.StandardHost", hostName };
String[] signature = { "java.lang.String", "java.lang.String" };
server.invoke(new ObjectName("Catalina:type=Engine"), "addChild", params, signature);

如果需要,检索主机对象并使用它:

ObjectName host = new ObjectName("Catalina:type=Host,host=" + hostName);
server.setAttribute(host, new Attribute("autoDeploy", false));
server.invoke(host, "start", null, null);
于 2013-02-27T08:38:23.030 回答
3

您不应该以编程方式更改服务器环境,并且没有可靠和标准的方法可以做到这一点。最好的做法是把它全部放在 webapp 端。首先,aFilter非常适合这个。将名称存储在您缓存在应用程序范围内的数据库表或属性文件中的某处。检查HttpServletRequest#getRequestURI()(或getServerName()如果它是子域而不是路径信息)并相应地执行转发任务。

希望这可以帮助。

于 2009-11-13T12:55:33.887 回答
1

我建议您将应用程序设置为 server.xml 中的默认虚拟主机,这样您的单个虚拟主机就可以响应发往任何主机名的请求。Tomcat 将 localhost 应用程序设置为默认虚拟主机。因此,您可以通过简单地检查 vanilla tomcat 安装的 server.xml 文件来了解如何执行此操作。您可以使用ServletRequest.getServerName()方法以编程方式确定用户将请求发送到的主机名。

Tomcat 曾经附带一个名为“host-manager”的 Web 应用程序。注意:这与 Tomcat 仍然附带的“管理器”Web 应用程序不同。主机管理器允许在不重新启动服务器的情况下即时更改配置或添加新的虚拟主机。您可以通过 HTTP 与主机管理器交互(如果需要,以编程方式)。但是,它有一个不幸的缺陷是没有将其更改提交到 server.xml,因此它们在 Web 服务器重新启动时都丢失了。无论出于何种原因,从版本 6 开始,Tomcat 不再附带主机管理器应用程序。所以似乎不再支持它。

于 2009-11-13T12:55:16.070 回答
1

总结一下ZZ Coder对我有很大指导的答案:

您必须创建一个实现ContainerServlet和覆盖setWrapper方法的 servlet 来获取org.apache.catalina.Wrapper对象。

为此,您必须privileged="true"context.xml Context标签中包含,否则会引发异常。然后您可以使用该Wrapper对象并:

StandardContext context = (StandardContext) wrapper.getParent();
StandardHost currentHost = (StandardHost) context.getParent();
StandardEngine engine = (StandardEngine) currentHost.getParent();

StandardHost host = new StandardHost();
host.setAppBase(currentHost.getAppBase()); //in my case I created another instance of the same application
host.setDomain(currentHost.getDomain());
host.setAutoDeploy(false); // not restarting app whenever changes happen
host.setName("domain.com");
host.setThrowOnFailure(true);// tell it to throw an exception here if it fails to create the host
host.setDeployOnStartup(true);
host.setStartChildren(true);
host.setParent(engine); 
// you can add multiple aliases
host.addAlias(alias);

StandardContext ctx = new StandardContext();
ctx.setDocBase(context.getDocBase()); //again I reused my same application setting
ctx.setPath("");
if(currentHost.getWorkDir() != null)
{//create a working directory based on your new host's name
    ctx.setWorkDir(currentHost.getWorkDir().replace(currentHost.getName(), host.getName()));
}
ctx.setName(host.getDomain());

//some extra config that you can use
ctx.setUseHttpOnly(false);
ctx.setReloadable(false);
ctx.setXmlValidation(false);
ctx.setXmlNamespaceAware(false);
ctx.setCrossContext(false);
ctx.setParent(host);
// you have to have this or it will not work!!
ctx.addLifecycleListener(new ContextConfig()); 

//you can also create resources and add it to the context like so:
final ContextResource res = new ContextResource();
res.setName("name");
res.setAuth("Container");
res.setType("javax.sql.DataSource");
ctx.getNamingResources().addResource(res);

host.addChild(ctx);

engine.addChild(host);

您可以通过调用向资源添加属性res.setProperty("name", "value") 可以使用的一些属性是: initialSize, maxTotal, maxIdle, maxWaitMillis, removeAbandonedOnBorrow, removeAbandonedTimeout, validationQuery, timeBetweenEvictionRunsMillis, driverClassName, url, username, password

另一个令人兴奋的事情是通过调用engine.findChild(domain)和使用从tomcat引擎获取主机stop(),并拥有自己的Tomcat管理面板start()getStateName()

于 2020-08-27T05:31:46.583 回答