Mam zamiar zastąpić komponent bean środowiska używany przez program Spring z własną implementacją. Czy to jest zła praktyka, a jeśli nie, jak mogę to zrobić w czysty sposób? Obecnie utworzyłem komponent bean, który implementuje interfejs Środowisko i używa istniejącego komponentu bean Środowisko, ale oznacza to, że cały kod konfiguracyjny wymagający komponentu bean Środowisko musi teraz korzystać z niestandardowego komponentu bean Środowisko. Sądzę, że czystsze byłoby zastąpienie sprężyny Springs Environment moją własną, wtedy żadna konfiguracja, która tego wymaga, nie musiałaby się zmieniać. Obecnie jedyny sposób, w jaki mogę to zrobić, to albo utworzyć mój własny kontekst aplikacji, ustawiając w ten sposób środowisko na własne potrzeby, albo mieć coś z ApplicationContextAware i ustawić tam środowisko. Oba wydają mi się trochę hokey.Spring: Jak zastąpić komponent bean Environment utworzony w kontekście aplikacji
Ograniczenia:
- Używam najnowszej wersji Spring3.
- Używam konfiguracji opartej na języku Java; nie XML
Dziękuję.
Edycja: tła
Chyba powinienem wyjaśnić, dlaczego chcę to zrobić w przypadku moje myślenie jest błędne. Unikałem tego, aby uniknąć niekonstruktywnego "dlaczego miałbyś to robić?" odpowiedzi.
W fasoli Wiosenne środowisko podczas wyszukiwania wartości właściwości używany jest zestaw źródeł właściwości. Typowym stos wygląda tak (ale nie tylko):
- JNDI
- Właściwości systemu (ustawiany za pomocą -Dmyprop = foo)
- Zmienne środowiskowe
- ...
Ze względów bezpieczeństwa konieczne jest zaszyfrowanie niektórych z tych właściwości (np. Haseł do baz danych). Rozwiązaniem jest użycie Jasiupt do szyfrowania właściwości. Jednak Spring/Jasypt zapewniają tylko środek do umieszczenia nowego źródła własności w środowisku. Więc:
- plik nieruchomości z potencjalnie zaszyfrowanych wartości
- JNDI
- Właściwości systemu (ustawiany za pomocą -Dmyprop = foo)
- Zmienne środowiskowe
- ...
jednak nie jest to idealne, ponieważ oznacza to, że właściwości mogą być przechowywane tylko w jednym pliku, który ma być utrzymywany przez grupę operacyjną, lub że właściwości będą rozłożone między t pliki właściwości, zmienne środowiskowe itp. Ponadto uważam, że właściwości mogą potencjalnie zostać zaszyfrowane bez względu na ich źródło własności.
To doprowadziło mnie do myślenia, że albo trzeba odszyfrować właściwości w moim kodzie, gdziekolwiek próbuję uzyskać do nich dostęp ze środowiska, albo muszę utworzyć własny komponent środowiskowy, który może to zrobić dla mnie.
Zachęcam do wysłuchania wypowiedzi konstruktywnych i alternatywnych.
EDIT: Dodawanie rozwiązanie oparte na odpowiedź od M. Deinum
public class EnvironmentBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
private static final String CONFIGURATION_PROPERTY_PBE_ALGORITHM = "PBE_ALGORITHM";
private static final String CONFIGURATION_PROPERTY_PBE_PASSWORD = "PBE_PASSWORD";
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
StandardEnvironment environment = (StandardEnvironment) beanFactory.getBean("environment");
if (environment != null) {
StringEncryptor encryptor = this.getEncryptor(environment);
MutablePropertySources mutablePropertySources = environment.getPropertySources();
for (PropertySource<?> propertySource : mutablePropertySources) {
mutablePropertySources.replace(
propertySource.getName(),
new EncryptablePropertySourcePropertySource(propertySource.getName(), propertySource, encryptor));
}
}
}
private StringEncryptor getEncryptor(Environment environment) {
StandardPBEStringEncryptor encryptor = new StandardPBEStringEncryptor();
String algorithm = environment.getProperty(CONFIGURATION_PROPERTY_PBE_ALGORITHM);
if (algorithm != null) {
encryptor.setAlgorithm(algorithm);
}
String password = environment.getProperty(CONFIGURATION_PROPERTY_PBE_PASSWORD);
if (password != null) {
encryptor.setPassword(password);
}
return encryptor;
}
private class EncryptablePropertySourcePropertySource extends PropertySource<PropertySource<?>> {
private StringEncryptor stringEncryptor;
private TextEncryptor textEncryptor;
public EncryptablePropertySourcePropertySource(final String name, final PropertySource<?> propertySource, final StringEncryptor encryptor) {
super(name, propertySource);
this.stringEncryptor = encryptor;
}
public EncryptablePropertySourcePropertySource(final String name, final PropertySource<?> propertySource, final TextEncryptor encryptor) {
super(name, propertySource);
this.textEncryptor = encryptor;
}
@Override
public Object getProperty(String name) {
Object value = this.source.getProperty(name);
if (value != null && value instanceof String) {
value = this.decode((String) value);
}
return value;
}
private String decode(String encodedValue) {
if (!PropertyValueEncryptionUtils.isEncryptedValue(encodedValue)) {
return encodedValue;
}
if (this.stringEncryptor != null) {
return PropertyValueEncryptionUtils.decrypt(encodedValue, this.stringEncryptor);
}
if (this.textEncryptor != null) {
return PropertyValueEncryptionUtils.decrypt(encodedValue, this.textEncryptor);
}
throw new EncryptionOperationNotPossibleException(
"Neither a string encryptor nor a text encryptor exist "
+ "for this instance of EncryptableProperties. This is usually "
+ "caused by the instance having been serialized and then "
+ "de-serialized in a different classloader or virtual machine, "
+ "which is an unsupported behaviour (as encryptors cannot be "
+ "serialized themselves)");
}
}
}
Co próbujesz osiągnąć przez zwinięcie własnego "środowiska", którego nie można osiągnąć przy użyciu standardowych wiosennych rzeczy? – geoand
Widzę 'Metoda' setEnvironment() 'AbstractApplicationContext' jest publiczna. Tak więc można uzyskać kontekst aplikacji z komponentem bean implementującym "ApplicationContextAware", a stamtąd można ustawić własne środowisko. Nie próbowałem tego, ale myślę, że to byłaby pierwsza rzecz, którą chciałbym spróbować. –
@geo i zobacz moją edycję. – loesak