据我所知,您所能做的就是传递一个类名(参见 icrovett 的回答),JNDI 将通过反射调用 getDefault() 方法。所以你不能在那里真正传递任何参数。所以我认为没有好的和干净的解决方案。
根据我的需要,我构建了一个SelectiveLdapSslSocketFactory,其中包含一个静态映射主机到不同 SSLSocketFactories 的映射。首先,您可以为不同的主机注册您的自定义SSLSocketFactories。然后,当调用任何createSocket(...) 方法时,它会知道为其创建套接字的主机,因此可以将调用委托给相应的SSLSocketFactory。它还包含一个defaultSslSocketFactory,用于没有任何映射的主机,也包含在getDefaultCipherSuites() 和getSupportedCipherSuites() 方法中。我不确定它是否完全正确,但对我来说效果很好,所以如果你愿意,可以测试一下:
public class SelectiveLdapSslSocketFactory extends SSLSocketFactory {
private static SSLSocketFactory defaultSslSocketFactory;
private static final Map<String, SSLSocketFactory> hostToSslSocketFactoryMap = new HashMap<>();
{
try {
defaultSslSocketFactory = <yourOwnDefaultSslSocketFactory>;
} catch (Exception ex) {
Logger.warn(ex, "Couldn't initialize a defaultSslSocketFactory for LDAP connections!");
}
}
public static SSLSocketFactory getRegisteredSslSocketFactory(String host) {
return hostToSslSocketFactoryMap.get(host);
}
public static void registerSslSocketFactory(String host, SSLSocketFactory sslSocketFactory) {
hostToSslSocketFactoryMap.put(host, sslSocketFactory);
}
public static void deregisterSslSocketFactory(String host) {
hostToSslSocketFactoryMap.remove(host);
}
public SelectiveLdapSslSocketFactory() {
}
public static SocketFactory getDefault() {
return new SelectiveLdapSslSocketFactory();
}
@Override
public String[] getDefaultCipherSuites() {
return defaultSslSocketFactory.getDefaultCipherSuites();
}
@Override
public String[] getSupportedCipherSuites() {
return defaultSslSocketFactory.getSupportedCipherSuites();
}
@Override
public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException {
SSLSocketFactory sslSocketFactory = Objects.requireNonNullElse(hostToSslSocketFactoryMap.get(host), defaultSslSocketFactory);
return sslSocketFactory.createSocket(s, host, port, autoClose);
}
@Override
public Socket createSocket(String host, int port) throws IOException, UnknownHostException {
SSLSocketFactory sslSocketFactory = Objects.requireNonNullElse(hostToSslSocketFactoryMap.get(host), defaultSslSocketFactory);
return sslSocketFactory.createSocket(host, port);
}
@Override
public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException, UnknownHostException {
SSLSocketFactory sslSocketFactory = Objects.requireNonNullElse(hostToSslSocketFactoryMap.get(host), defaultSslSocketFactory);
return sslSocketFactory.createSocket(host, port, localHost, localPort);
}
@Override
public Socket createSocket(InetAddress host, int port) throws IOException {
SSLSocketFactory sslSocketFactory = getSslSocketFactory(host);
return sslSocketFactory.createSocket(host, port);
}
@Override
public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException {
SSLSocketFactory sslSocketFactory = getSslSocketFactory(address);
return sslSocketFactory.createSocket(address, port, localAddress, localPort);
}
private SSLSocketFactory getSslSocketFactory(InetAddress inetAddress) {
SSLSocketFactory sslSocketFactory = hostToSslSocketFactoryMap.get(Objects.requireNonNullElse(inetAddress.getCanonicalHostName(), ""));
if (sslSocketFactory == null) {
sslSocketFactory = hostToSslSocketFactoryMap.get(Objects.requireNonNullElse(inetAddress.getHostName(), ""));
if (sslSocketFactory == null) {
sslSocketFactory = hostToSslSocketFactoryMap.get(Objects.requireNonNullElse(inetAddress.getHostAddress(), ""));
if (sslSocketFactory == null) {
sslSocketFactory = defaultSslSocketFactory;
}
}
}
return sslSocketFactory;
}
}
然后你可以像这样使用它:
...
SelectiveLdapSslSocketFactory.registerSslSocketFactory(host01, sslSocketFactory01);
SelectiveLdapSslSocketFactory.registerSslSocketFactory(host02, sslSocketFactory02);
SelectiveLdapSslSocketFactory.registerSslSocketFactory(host03, sslSocketFactory03);
props.put("java.naming.ldap.factory.socket", SelectiveLdapSslSocketFactory.class.getName());