TomcatがSSL資格情報に使用するキーストアを更新できるバックグラウンドプロセスがあります。手動で再起動する必要なく、Tomcatにこれを自動的にリロードさせたいと思います。
再起動せずにTomcatにこれをリロードさせることは可能ですか、それとも代わりにそれを行うことができるプログラム的な方法はありますか?
バックグラウンドプロセスでTomcatを自動的に再起動することはできますが、自動的に実行する方法があるとは思いません。キーストアは、jvmが初期化されるときに一度だけ読み取られます。キーストアを定期的に再チェックする独自のハンドラーを作成する場合、解決策があるかもしれませんが、個人的にはインターネットでこれの例を見つけていません。
個々のTomcatコネクタを再起動できます。つまり、jssecacertファイルを変更した後で8443のようにポートを再起動できます。
証明書を追加/削除した後、Tomcatコネクタを再起動するために使用している完全なコード/メソッドを次に示します。
// Stop and restart the SSL connection so that the Tomcat server will
// re-read the certificates from the truststore file.
public void refreshTrustStore() throws Exception
{
try
{
//following line should be replaced based on where you get your port number. You may pass in as argument to this method
String httpsPort = configurationManager.getHttpsPort();
String objectString = "*:type=Connector,port=" + httpsPort + ",*";
final ObjectName objectNameQuery = new ObjectName(objectString);
for (final MBeanServer server: MBeanServerFactory.findMBeanServer(null))
{
if (!server.queryNames(objectNameQuery, null).isEmpty())
{
MBeanServer mbeanServer = server;
ObjectName objectName = (ObjectName) server.queryNames(objectNameQuery, null).toArray()[0];
mbeanServer.invoke(objectName, "stop", null, null);
// Polling sleep to reduce delay to safe minimum.
// Use currentTimeMillis() over nanoTime() to avoid issues
// with migrating threads across sleep() calls.
long start = System.currentTimeMillis();
// Maximum of 6 seconds, 3x time required on an idle system.
long max_duration = 6000L;
long duration = 0L;
do
{
try
{
Thread.sleep(100);
}
catch (InterruptedException e)
{
Thread.currentThread().interrupt();
}
duration = (System.currentTimeMillis() - start);
} while (duration < max_duration &&
server.queryNames(objectNameQuery, null).size() > 0);
// Use below to get more accurate metrics.
String message = "TrustStoreManager TrustStore Stop: took " + duration + "milliseconds";
logger.information(message);
mbeanServer.invoke(objectName, "start", null, null);
break;
}
}
}
catch (Exception exception)
{
// Log and throw exception
throw exception
}
}
これを行う方法は、Tomcat v8.5.24以降にあります。
彼らは次の2つのメソッドを導入しました。
さまざまな方法で呼び出すことができます。
方法1と方法2の詳細は、Tomcatのドキュメントで簡単に入手できます。
方法3を使用する方法の詳細:
以下のサンプルコードを見つけてください:
メインプロトコルクラス:
package com.myown.connector;
import Java.io.File;
import Java.io.InputStream;
import Java.lang.reflect.Field;
import Java.net.URL;
import Java.net.URLConnection;
import Java.nio.file.StandardCopyOption;
import Java.util.ArrayList;
import Java.util.List;
import Java.util.concurrent.ConcurrentMap;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import javax.net.ssl.SSLSessionContext;
import org.Apache.coyote.http11.Http11NioProtocol;
import org.Apache.juli.logging.Log;
import org.Apache.juli.logging.LogFactory;
import org.Apache.Tomcat.util.modeler.Registry;
import org.Apache.Tomcat.util.net.AbstractEndpoint;
import org.Apache.Tomcat.util.net.AbstractJsseEndpoint;
import org.Apache.Tomcat.util.net.GetSslConfig;
import org.Apache.Tomcat.util.net.SSLContext;
import org.Apache.Tomcat.util.net.SSLHostConfig;
import org.Apache.Tomcat.util.net.SSLHostConfigCertificate;
import org.Apache.Tomcat.util.net.SSLImplementation;
import org.Apache.Tomcat.util.net.SSLUtil;
public class ReloadProtocol extends Http11NioProtocol {
private static final Log log = LogFactory.getLog(Http12ProtocolSSL.class);
public ReloadProtocol() {
super();
RefreshSslConfigThread refresher = new
RefreshSslConfigThread(this.getEndpoint(), this);
refresher.start();
}
@Override
public void setKeystorePass(String s) {
super.setKeystorePass(s);
}
@Override
public void setKeyPass(String s) {
super.setKeyPass(s);
}
@Override
public void setTruststorePass(String p) {
super.setTruststorePass(p);
}
class RefreshSslConfigThread extends Thread {
AbstractJsseEndpoint<?> abstractJsseEndpoint = null;
Http11NioProtocol protocol = null;
public RefreshSslConfigThread(AbstractJsseEndpoint<?> abstractJsseEndpoint, Http11NioProtocol protocol) {
this.abstractJsseEndpoint = abstractJsseEndpoint;
this.protocol = protocol;
}
public void run() {
int timeBetweenRefreshesInt = 1000000; // time in milli-seconds
while (true) {
try {
abstractJsseEndpoint.reloadSslHostConfigs();
System.out.println("Config Updated");
} catch (Exception e) {
System.out.println("Problem while reloading.");
}
try {
Thread.sleep(timeBetweenRefreshesInt);
} catch (InterruptedException e) {
System.out.println("Error while sleeping");
}
}
}
}
}
Server.xmlのコネクターは、これをプロトコルとして言及する必要があります。
<Connector protocol="com.myown.connector.ReloadProtocol"
..........
お役に立てれば。