#java #spring #spring-ioc #private-constructor
#java #весна #весна-ioc #private-constructor
Вопрос:
Имея AppConfig.java
без сканирования аннотаций из-за безопасности и без настройки через an app-config.xml
из-за более жесткой привязки, я создаю экземпляры spring-beans, подобные этому:
@Configuration
public class AppConfig {
@Bean
public AddressService addressService(){
return new AddressService();
}
}
Все работает отлично, но что, если я хочу запретить другим создавать экземпляр AddressService
? Обычно я объявляю конструктор закрытым, но компилятор выдает мне ошибку, из-за которой я больше не могу получить доступ к закрытому конструктору AddressService
в AppConfig
!
Для полноты картины это AddressService
:
public final class AddressService {
private AddressService(){}
}
Ответ №1:
Это рабочее решение.
@Configuration
public class AppConfig {
public static class AddressService {
private AddressService() {}
}
@Bean
public AddressService addressService() {
return new AddressService();
}
}
Ответ №2:
Создайте общедоступный интерфейс и частный пакет класса реализации. Означает AddressingService
, что это общедоступный интерфейс и AddressingServiceImpl
просто частный пакет с @Service
аннотацией. Теперь никто не сможет создать экземпляр вашего spring-bean, и только один экземпляр будет доступен для других в зависимости от области вашего компонента. Вы можете автоматически подключить компонент как @Autowired AddressingService
.
Пример тестового примера junit для проверки, AddressingServiceImpl
используется ли он непосредственно в любом классе в том же пакете.
В этом случае классы находятся в пакете src /main / java /com / address . и тестовый класс создается в src/test/java/com/address .
package com.address;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.util.Arrays;
import org.junit.Test;
import org.junit.*;
public class BeansInitTest {
@Test
public void test() {
File[] files = new File("src/main/java/com/address").listFiles((File dir, String name) -> {
return name.endsWith(".java") amp;amp; !name.equals(AddressServiceImpl.class.getSimpleName() ".java");
}
);
Arrays.asList(files)
.stream().forEach(clazz -> checkInstanceCreation(clazz, AddressServiceImpl.class.getSimpleName()));
}
private void checkInstanceCreation(File clazz, String name) {
try (BufferedReader reader = new BufferedReader(new FileReader(clazz))){
reader.lines().forEach(l -> {
Assert.assertFalse(l.contains(name));
});
}catch(Exception e){
throw new RuntimeException(e);
}
}
}
Пожалуйста, обратите внимание, что это всего лишь образец и может быть обобщен в зависимости от необходимости.
Комментарии:
1. Почему интерфейс? Почему бы не объявить конструктор package-private?
2. На самом деле, что это меняет? операционная система не может (предпочитает не использовать) сканирование аннотаций. Значит, он все еще должен иметь возможность выполнять «new AddressingService», что означает, что конструктор виден и другим?
3. @Alex Конструктор будет виден в том же пакете, он сказал
package-private
, что такоеdefault
илиprotected
.4. Я понимаю, просто подумал, что это недостаточно ограничительно (т. Е. Не Приватно), но если это хорошо для вас, тогда это хорошо 😉
5. Я не уверен, почему голосование против. Это решение, которое работает. попробуйте это перед голосованием.