Tomcat提供“虚拟主机”支持:可以将引擎/ Web应用程序配置为负责域列表。必须使用特殊的xml指令将这些域放入server.xml / context.xml文件中。
=>是否有可能以编程方式更改Tomcat配置(通常),尤其是Web应用程序/引擎的“虚拟主机”?
例如,如果新用户注册,我必须将他的域添加到“已接受的虚拟主机/域”列表中。我目前想到的唯一方法是通过脚本更改xml文件,然后重新启动Tomcat。
有没有办法添加它们通过一些Java-Methods以编程方式添加运行时?
非常感谢! 扬
答案 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")
,initialSize
,maxTotal
,maxIdle
,maxWaitMillis
,removeAbandonedOnBorrow
,removeAbandonedTimeout
,validationQuery
,{{ 1}},timeBetweenEvictionRunsMillis
,driverClassName
,url
。
另一个令人兴奋的事情是通过调用username
并使用password
,engine.findChild(domain)
,stop()
从tomcat引擎获取主机,并拥有自己的Tomcat Admin面板!