Поиск…


Автообработка всех бобах определенного типа

Если у вас есть несколько реализаций одного и того же интерфейса, Spring может автоматически их перевести в объект коллекции. Я собираюсь использовать пример, используя шаблон Validator 1

Foo Класс:

public class Foo {
     private String name;
     private String emailAddress;
     private String errorMessage;
     /** Getters & Setters omitted **/
}

Интерфейс:

public interface FooValidator {
    public Foo validate(Foo foo);
}

Класс имени валидатора:

@Component(value="FooNameValidator")
public class FooNameValidator implements FooValidator {
    @Override
    public Foo validate(Foo foo) {
        //Validation logic goes here.
    }
}

Класс валидатора Email:

@Component(value="FooEmailValidator")
public class FooEmailValidator implements FooValidator {
    @Override
    public Foo validate(Foo foo) {
        //Different validation logic goes here.
    }
}

Теперь вы можете авторизовать эти валидаторы отдельно или вместе в классе.

Интерфейс:

public interface FooService {
    public void handleFoo(Foo foo);
}

Учебный класс:

@Service
public class FooServiceImpl implements FooService {
    /** Autowire all classes implementing FooValidator interface**/
    @Autowired
    private List<FooValidator> allValidators;

    @Override
    public void handleFoo(Foo foo) {
       /**You can use all instances from the list**/
       for(FooValidator validator : allValidators) {
           foo = validator.validate(foo);               
       }
    }   
}

Стоит отметить, что если у вас есть несколько реализаций интерфейса в контейнере Spring IoC и не указывайте, какой из них вы хотите использовать с аннотацией @Qualifier , Spring будет генерировать исключение при попытке запустить, t знать, какой экземпляр использовать.

1: Это неправильный способ сделать такие простые проверки. Это простой пример об автоподготовке. Если вы хотите получить более простой метод проверки, посмотрите, как Spring делает валидацию с аннотациями.

Объявление бина

Чтобы объявить компонент, просто аннотируйте метод с @Bean аннотации @Bean или аннотируйте класс с @Component аннотации @Component (аннотации @Service , @Repository , @Controller могут быть использованы).

Когда JavaConfig встречает такой метод, он выполнит этот метод и зарегистрирует возвращаемое значение как bean-компонент в BeanFactory. По умолчанию имя компонента будет именем имени метода.

Мы можем создать bean-компонент, используя один из трех способов:

  1. Использование конфигурации на основе Java : в файле конфигурации нам нужно объявить bean-компонент, используя аннотацию @bean

    @Configuration
    public class AppConfig {
        @Bean
        public TransferService transferService() {
            return new TransferServiceImpl();
        }
    }
    
  2. Использование конфигурации на основе XML : для конфигурации на основе XML нам нужно создать декларацию bean-компонента в конфигурации приложения XML, т. Е.

     <beans>
         <bean name="transferService" class="com.acme.TransferServiceImpl"/>
     </beans>
    
  3. Компонент, связанный с аннотацией. Для компонентов, связанных с аннотациями, нам нужно добавить аннотацию @Component к классу, который мы хотим объявить как bean.

     @Component("transferService")
     public class TransferServiceImpl implements TransferService {
         ...
     }
    

Теперь все три компонента с именем transferService доступны в BeanFactory или ApplicationContext .

Автообслуживание базовой аннотации

Интерфейс:

public interface FooService {
    public int doSomething();
}

Учебный класс:

@Service
public class FooServiceImpl implements FooService {
    @Override
    public int doSomething() {
        //Do some stuff here
        return 0;
    }
}

Следует отметить, что класс должен реализовывать интерфейс Spring, чтобы иметь возможность autwire этого класса. Существует метод, позволяющий Spring автоматически создавать автономные классы с использованием времени загрузки во времени, но для этого примера это выходит за рамки.

Вы можете получить доступ к этому компоненту в любом классе, который @Autowired экземпляром Spring IoC с помощью @Autowired аннотации.

Использование:

@Autowired([required=true])

Аннотации @Autowired сначала попытаются выполнить аутоуверию по типу, а затем вернуться к имени бина в случае двусмысленности.

Эта аннотация может применяться несколькими различными способами.

Инъекция конструктора:

public class BarClass() {
    private FooService fooService         

    @Autowired
    public BarClass(FooService fooService) {
        this.fooService = fooService;
    }
}

Полевая инъекция:

public class BarClass() {
    @Autowired
    private FooService fooService;
}

Сетчатая инъекция:

public class BarClass() {
    private FooService fooService;

    @Autowired
    public void setFooService(FooService fooService) {
        this.fooService = fooService;
    }
}

Использование FactoryBean для создания динамического компонента

Чтобы динамически решить, какие бобы для инъекций, мы можем использовать FactoryBean s. Это классы, которые реализуют шаблон фабричного метода, предоставляя экземпляры бобов для контейнера. Они распознаются весной и могут использоваться прозрачно, без необходимости знать, что фасоль поступает с завода. Например:

public class ExampleFactoryBean extends AbstractFactoryBean<String> {
    // This method determines the type of the bean for autowiring purposes
    @Override
    public Class<?> getObjectType() {
        return String.class;
    }

    // this factory method produces the actual bean
    @Override
    protected String createInstance() throws Exception {
        // The thing you return can be defined dynamically,
        // that is read from a file, database, network or just
        // simply randomly generated if you wish.
        return "Something from factory";
    }
}

Конфигурация:

@Configuration
public class ExampleConfig {
    @Bean
    public FactoryBean<String> fromFactory() {
        return new ExampleFactoryBean();
    }
}

Получение компонента:

AbstractApplicationContext context = new AnnotationConfigApplicationContext(ExampleConfig.class);
String exampleString = (String) context.getBean("fromFactory");

Чтобы получить фактический FactoryBean, используйте префикс ampersand перед именем bean-компонента:

FactoryBean<String> bean = (FactoryBean<String>) context.getBean("&fromFactory");

Обратите внимание, что вы можете использовать только prototype или singleton области - для изменения области действия на prototype переопределения isSingleton :

public class ExampleFactoryBean extends AbstractFactoryBean<String> {
    @Override
    public boolean isSingleton() {
        return false;
    }

    // other methods omitted for readability reasons
}

Обратите внимание, что область охвата относится к фактическим создаваемым экземплярам, ​​а не к фактору фабрики.

Вставить прототип-фасоли в однотонные

Контейнер создает одноэлементный компонент и вставляет в него коллабораторов только один раз. Это не является желательным поведением, когда одноэлементный компонент имеет совместимый с прототипом коллаборатор, так как компонент с прототипом должен быть инъецирован каждый раз, когда к нему обращаются через accessor.

Существует несколько решений этой проблемы:

  1. Использовать метод поиска методом
  2. javax.inject.Provider фасоль с прототипом с помощью javax.inject.Provider
  3. org.springframework.beans.factory.ObjectFactory компонент с прототипом с помощью org.springframework.beans.factory.ObjectFactory (эквивалент №2, но с классом, специфичным для Spring)
  4. Сделать контейнер с одним контейнером, используя интерфейс ApplicationContextAware

Подходы №3 и №4 обычно обескуражены, поскольку они сильно привязывают приложение к платформе Spring. Таким образом, они не рассматриваются в этом примере.

Инициализация метода поиска с помощью XML-конфигурации и абстрактного метода

Java-классы

public class Window {
}

public abstract class WindowGenerator {

    public Window generateWindow() {
        Window window = createNewWindow(); // new instance for each call
        ... 
    }

    protected abstract Window createNewWindow(); // lookup method
}

XML

<bean id="window" class="somepackage.Window" scope="prototype" lazy-init="true"/>

<bean id="windowGenerator" class="somepackage.WindowGenerator">
    <lookup-method name="createNewWindow" bean="window"/>
</bean>

Ввод метода поиска через конфигурацию Java и @Component

Java-классы

public class Window {
}

@Component
public class WindowGenerator {

    public Window generateWindow() {
        Window window = createNewWindow(); // new instance for each call
        ...
    }

    @Lookup
    protected Window createNewWindow() {
        throw new UnsupportedOperationException();
    }
}

Конфигурация Java

@Configuration
@ComponentScan("somepackage") // package where WindowGenerator is located
public class MyConfiguration {

    @Bean
    @Lazy
    @Scope(scopeName = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
    public Window window() {
        return new Window();
    }
}

Ввод метода ручного поиска через конфигурацию Java

Java-классы

public class Window {
}

public abstract class WindowGenerator {

    public Window generateWindow() {
        Window window = createNewWindow(); // new instance for each call
        ...
    }

    protected abstract Window createNewWindow(); // lookup method
}

Конфигурация Java

@Configuration
public class MyConfiguration {

    @Bean
    @Lazy
    @Scope(scopeName = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
    public Window window() {
        return new Window();
    }

    @Bean
    public WindowGenerator windowGenerator(){
        return new WindowGenerator() {
            @Override
            protected Window createNewWindow(){
                return window();
            }
        };
    }
}

Инъекция фасоли с javax.inject.Provider в одноэлемент через javax.inject.Provider

Классы Java

public class Window {
}

public class WindowGenerator {

    private final Provider<Window> windowProvider;

    public WindowGenerator(final Provider<Window> windowProvider) {
        this.windowProvider = windowProvider;
    }

    public Window generateWindow() {
        Window window = windowProvider.get(); // new instance for each call   
        ...
    }
}

XML

<bean id="window" class="somepackage.Window" scope="prototype" lazy-init="true"/>

<bean id="windowGenerator" class="somepackage.WindowGenerator">
    <constructor-arg>
        <bean class="org.springframework.beans.factory.config.ProviderCreatingFactoryBean">
            <property name="targetBeanName" value="window"/>
        </bean>
    </constructor-arg>
</bean>

Те же самые подходы могут быть использованы и для других областей (например, для инъекции компонента с привязкой к запросу в одноэлементный).

Автоустановка конкретных экземпляров компонента с помощью @Qualifier

Если у вас есть несколько реализаций одного и того же интерфейса, Spring должен знать, какой из них он должен использовать в классе. В этом примере я собираюсь использовать шаблон Validator. 1

Foo Класс:

public class Foo {
     private String name;
     private String emailAddress;
     private String errorMessage;
     /** Getters & Setters omitted **/
}

Интерфейс:

public interface FooValidator {
    public Foo validate(Foo foo);
}

Класс имени валидатора:

@Component(value="FooNameValidator")
public class FooNameValidator implements FooValidator {
    @Override
    public Foo validate(Foo foo) {
        //Validation logic goes here.
    }
}

Класс валидатора Email:

@Component(value="FooEmailValidator")
public class FooEmailValidator implements FooValidator {
    @Override
    public Foo validate(Foo foo) {
        //Different validation logic goes here.
    }
}

Теперь вы можете автоматически авторизовать эти валидаторы в классе.

Интерфейс:

public interface FooService {
    public void handleFoo(Foo foo);
}

Учебный класс:

@Service
public class FooServiceImpl implements FooService {
    /** Autowire validators individually **/
    @Autowired
    /* 
     * Notice how the String value here matches the value 
     * on the @Component annotation? That's how Spring knows which 
     * instance to autowire.
     */
    @Qualifier("FooNameValidator")
    private FooValidator nameValidator;

    @Autowired
    @Qualifier("FooEmailValidator")
    private FooValidator emailValidator;

    @Override
    public void handleFoo(Foo foo) {
        /**You can use just one instance if you need**/
        foo = nameValidator.validate(foo);
    }   
}

Стоит отметить, что если у вас есть несколько реализаций интерфейса в контейнере Spring IoC и не указывайте, какой из них вы хотите использовать с аннотацией @Qualifier , Spring будет генерировать исключение при попытке запустить, t знать, какой экземпляр использовать.

1: Это неправильный способ сделать такие простые проверки. Это простой пример об автоподготовке. Если вы хотите получить более простой метод проверки, посмотрите, как Spring делает валидацию с аннотациями.

Автоустановка конкретных экземпляров классов с использованием параметров типового типа

Если у вас есть интерфейс с параметром generic type, Spring может использовать это только для аутсорсинга реализаций, которые реализуют заданный вами параметр типа.

Интерфейс:

public interface GenericValidator<T> {
    public T validate(T object);
}

Foo Validator Класс:

@Component
public class FooValidator implements GenericValidator<Foo> {
    @Override
    public Foo validate(Foo foo) {
        //Logic here to validate foo objects.
    }
}

Класс валидатора баров:

@Component
public class BarValidator implements GenericValidator<Bar> {
    @Override
    public Bar validate(Bar bar) {
        //Bar validation logic here
    }
}

Теперь вы можете автоувеличивать эти валидаторы, используя параметры типа, чтобы решить, какой экземпляр для autwire.

Интерфейс:

public interface FooService {
    public void handleFoo(Foo foo);
}

Учебный класс:

@Service
public class FooServiceImpl implements FooService {
    /** Autowire Foo Validator **/
    @Autowired
    private GenericValidator<Foo> fooValidator;

    @Override
    public void handleFoo(Foo foo) {
        foo = fooValidator.validate(foo);
    }   
}


Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow