Tomcat:以编程方式更改虚拟主机?

时间:2009-11-13 12:33:04

标签: java tomcat virtual-hosts

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

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

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

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

非常感谢! 扬

5 个答案:

答案 0 :(得分:6)

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实例,以便您可以更好地沙盒化应用程序。例如一个耗尽内存的应用程序不会杀死所有其他应用程序。

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

答案 1 :(得分:3)

您不应该以编程方式更改服务器环境,并且没有可靠且标准的方法来执行此操作。最好的办法是将其全部保存在webapp端。首先,Filter非常适合这种情况。将名称存储在数据库表或您在应用程序范围中缓存的属性文件中。检查HttpServletRequest#getRequestURI()(或getServerName(),如果它是子域而不是pathinfo),并相应地执行转发任务。

希望这有帮助。

答案 2 :(得分: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);

答案 3 :(得分:1)

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

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

答案 4 :(得分:1)

总结app:srcCompat的答案对我很有帮助:

您必须创建一个实现ZZ Coder并覆盖ContainerServlet方法的servlet,以获得setWrapper对象。

为此,您必须在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")initialSizemaxTotalmaxIdlemaxWaitMillisremoveAbandonedOnBorrowremoveAbandonedTimeoutvalidationQuery,{{ 1}},timeBetweenEvictionRunsMillisdriverClassNameurl

另一个令人兴奋的事情是通过调用username并使用passwordengine.findChild(domain)stop()从tomcat引擎获取主机,并拥有自己的Tomcat Admin面板!

相关问题