Вам нужен класс, который находит, загружает и создает экземпляры поставщиков услуг (специфицирует c реализации Cipher) и перехватывает их.
Существует некоторый подход к реализации синглетонов. Один из наиболее распространенных способов заключается в том, чтобы сохранить конструктор закрытым и экспортировать члена publi c stati c для предоставления доступа к единственному экземпляру. Этот элемент publi c stati c может быть полем stati c или фабрикой метода stati c (getInstance()
в нашем примере кода):
import serviceLoader.Cipher;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.ServiceLoader;
public final class CipherManager {
private final static ArrayList<Cipher> ciphers = new ArrayList<>();
private final static CipherManager INSTANCE = new CipherManager();
private CipherManager() {
load();
}
private static void load() {
ServiceLoader<Cipher> cipherLoader = ServiceLoader.load(Cipher.class);
Iterator<Cipher> ciphersIterator = cipherLoader.iterator();
List<Cipher> cipherProviders = new ArrayList<>();
ciphersIterator.forEachRemaining(cipherProviders::add);
updateCiphers(cipherProviders);
}
static synchronized void updateCiphers(List<Cipher> cipherProviders) {
ciphers.clear();
ciphers.addAll(cipherProviders);
}
public static CipherManager getInstance() {
return INSTANCE;
}
public void reload() {
load();
}
public Cipher getCipher() {
if (!ciphers.isEmpty()) {
return ciphers.get(0);
}
return null;
}
}
Метод getCipher()
должно быть реализовано так, как вам нужно. Может быть, вы хотите получить privoder по имени класса или любому уникальному свойству вашего сервиса (например, id провайдера, имя и т. Д. c). Имея это в виду, я предпочитаю использовать HashMap для перехвата поставщиков услуг (вместо ArrayList).
private final static HashMap<String, Cipher> ciphers = new HashMap<>();
Еще один способ реализации синглтона - это объявление одноэлементного перечисления:
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.ServiceLoader;
public enum CipherManager {
INSTANCE;
private final static HashMap<String, Cipher> ciphers = new HashMap<>();
static {
load();
}
public static CipherManager getInstance() {
return INSTANCE;
}
public void reload() {
load();
}
private static void load() {
ServiceLoader<Cipher> cipherLoader = ServiceLoader.load(Cipher.class);
Iterator<Cipher> ciphersIterator = cipherLoader.iterator();
HashMap<String, Cipher> cipherProviders = new HashMap<>();
ciphersIterator.forEachRemaining(cipher -> cipherProviders.put(cipher.getClass().getName(), cipher));
updateCiphers(cipherProviders);
}
static synchronized void updateCiphers(Map<String, Cipher> cipherProviders) {
ciphers.clear();
ciphers.putAll(cipherProviders);
}
public Cipher getCipher(String className) {
return ciphers.get(className);
}
}
В этом подходе добавлен метод getInstance()
, чтобы обозначить, что CipherManager следует одноэлементному шаблону. Таким образом, метод getInstance()
можно удалить из кода, и мы можем напрямую использовать поле INSTANCE
.