AppConfig.java вернуть компонент с помощью частного конструктора?

#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. Я не уверен, почему голосование против. Это решение, которое работает. попробуйте это перед голосованием.