Szukaj…


Automatyczna instalacja wszystkich ziaren określonego typu

Jeśli masz wiele implementacji tego samego interfejsu, Spring może automatycznie przypisać je wszystkie do obiektu kolekcji. Użyję przykładu z wykorzystaniem wzorca Validator 1

Klasa Foo:

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

Berło:

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

Nazwa Walidator Klasa:

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

Klasa walidatora e-mail:

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

Możesz teraz automatycznie korzystać z tych walidatorów indywidualnie lub razem w klasie.

Berło:

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

Klasa:

@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);               
       }
    }   
}

Warto zauważyć, że jeśli masz więcej niż jedną implementację interfejsu w kontenerze Spring IoC i nie określisz, którego chcesz użyć z adnotacją @Qualifier , Spring zgłosi wyjątek podczas próby uruchomienia, ponieważ wygrał „ t wiedzieć, którego wystąpienia użyć.

1: To nie jest właściwy sposób na przeprowadzanie tak prostych weryfikacji. Jest to prosty przykład dotyczący automatycznego zasilania. Jeśli potrzebujesz pomysłu na znacznie łatwiejszą metodę sprawdzania poprawności, sprawdź, jak Spring dokonuje sprawdzania poprawności za pomocą adnotacji.

Deklarowanie fasoli

Aby zadeklarować @Bean bean, po prostu @Bean adnotacji metody za pomocą adnotacji @Bean lub adnotacji klasy za pomocą adnotacji @Component (można również użyć adnotacji @Service , @Repository , @Controller ).

Gdy JavaConfig napotka taką metodę, wykona tę metodę i zarejestruje zwracaną wartość jako komponent beanFactory. Domyślnie nazwa komponentu bean będzie nazwą metody.

Możemy stworzyć fasolę na jeden z trzech sposobów:

  1. Korzystanie z konfiguracji opartej na Javie : W pliku konfiguracyjnym musimy zadeklarować komponent bean za pomocą adnotacji @bean

    @Configuration
    public class AppConfig {
        @Bean
        public TransferService transferService() {
            return new TransferServiceImpl();
        }
    }
    
  2. Korzystanie z konfiguracji opartej na XML : W przypadku konfiguracji opartej na XML musimy utworzyć deklarację bean w konfiguracji XML aplikacji tj

     <beans>
         <bean name="transferService" class="com.acme.TransferServiceImpl"/>
     </beans>
    
  3. Komponent sterowany adnotacjami: W przypadku komponentów sterowanych adnotacjami musimy dodać adnotację @Component do klasy, którą chcemy zadeklarować jako komponent bean.

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

Teraz wszystkie trzy BeanFactory bean z nazwą transferService są dostępne w BeanFactory lub ApplicationContext .

Podstawowy system automatycznego przypisywania adnotacji

Berło:

public interface FooService {
    public int doSomething();
}

Klasa:

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

Należy zauważyć, że klasa musi zaimplementować interfejs, aby Spring mógł autoryzować tę klasę. Istnieje metoda pozwalająca Springowi na autowire samodzielne klasy przy użyciu tkania czasu ładowania, ale nie jest to możliwe w tym przykładzie.

Możesz uzyskać dostęp do tego @Autowired bean w dowolnej klasie utworzonej przez kontener Spring IoC za pomocą adnotacji @Autowired .

Stosowanie:

@Autowired([required=true])

Adnotacja @Autowired podejmie najpierw próbę automatycznego uruchomienia według typu, a następnie powróci do nazwy fasoli w przypadku niejasności.

Adnotację tę można zastosować na kilka różnych sposobów.

Wtrysk konstruktora:

public class BarClass() {
    private FooService fooService         

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

Iniekcja w terenie:

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

Zastrzyk setera:

public class BarClass() {
    private FooService fooService;

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

Używanie FactoryBean do dynamicznego tworzenia instancji komponentu bean

Aby dynamicznie decydować, które ziarna należy wstrzyknąć, możemy użyć FactoryBean . Są to klasy, które implementują fabryczny wzorzec metody, zapewniając wystąpienia ziaren dla kontenera. Są rozpoznawane przez wiosnę i mogą być używane w przejrzysty sposób, bez potrzeby wiedzieć, że fasola pochodzi z fabryki. Na przykład:

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";
    }
}

Konfiguracja:

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

Zdobycie fasoli:

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

Aby uzyskać rzeczywisty FactoryBean, użyj przedrostka ampersand przed nazwą fasoli:

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

Należy pamiętać, że można używać tylko zakresów prototype lub singleton - aby zmienić zakres na zastąpienie prototype isSingleton metodę isSingleton :

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

    // other methods omitted for readability reasons
}

Należy pamiętać, że zakres odnosi się do rzeczywistych tworzonych instancji, a nie do samej fasoli fabrycznej.

Wtryskuj fasolę o prototypowym zasięgu do singletonów

Kontener tworzy fasolę singleton i wstrzykuje do niej współpracowników tylko raz. Nie jest to pożądane zachowanie, gdy fasola singleton ma współpracującego prototypu, ponieważ fasola o prototypowym zasięgu powinna być wstrzykiwana za każdym razem, gdy jest uzyskiwany dostęp poprzez akcesor.

Istnieje kilka rozwiązań tego problemu:

  1. Użyj iniekcji metodą wyszukiwania
  2. Pobierz javax.inject.Provider bean o javax.inject.Provider prototypowym za pośrednictwem javax.inject.Provider
  3. Pobierz fasolę o org.springframework.beans.factory.ObjectFactory prototypu za pośrednictwem org.springframework.beans.factory.ObjectFactory (odpowiednik # 2, ale z klasą specyficzną dla Spring)
  4. Poinformuj kontener singleton bean, implementując interfejs ApplicationContextAware

Podejścia nr 3 i 4 są ogólnie odradzane, ponieważ mocno wiążą aplikację z frameworkiem Spring. Dlatego nie są one objęte tym przykładem.

Wstrzyknięcie metody wyszukiwania za pomocą konfiguracji XML i metody abstrakcyjnej

Klasy 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>

Wstrzyknięcie metody wyszukiwania poprzez konfigurację Java i @Component

Klasy 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();
    }
}

Konfiguracja 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();
    }
}

Wstrzyknięcie metody ręcznego wyszukiwania poprzez konfigurację Java

Klasy 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
}

Konfiguracja 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();
            }
        };
    }
}

Wstrzyknięcie fasoli o javax.inject.Provider do singletonu przez javax.inject.Provider

Klasy 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>

Te same podejścia można zastosować również w przypadku innych zakresów (np. Do wstrzykiwania fasoli o określonym zakresie do singletonu).

Autouruchamianie określonych instancji komponentów bean za pomocą @Qualifier

Jeśli masz wiele implementacji tego samego interfejsu, Spring musi wiedzieć, która powinna zostać automatycznie przypisana do klasy. W tym przykładzie użyję wzorca walidatora. 1

Klasa Foo:

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

Berło:

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

Nazwa Walidator Klasa:

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

Klasa walidatora e-mail:

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

Możesz teraz automatycznie przypisać te weryfikatory do klasy.

Berło:

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

Klasa:

@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);
    }   
}

Warto zauważyć, że jeśli masz więcej niż jedną implementację interfejsu w kontenerze Spring IoC i nie określisz, którego chcesz użyć z adnotacją @Qualifier , Spring zgłosi wyjątek podczas próby uruchomienia, ponieważ wygrał „ t wiedzieć, którego wystąpienia użyć.

1: To nie jest właściwy sposób na przeprowadzanie tak prostych weryfikacji. Jest to prosty przykład dotyczący automatycznego zasilania. Jeśli potrzebujesz pomysłu na znacznie łatwiejszą metodę sprawdzania poprawności, sprawdź, jak Spring dokonuje sprawdzania poprawności za pomocą adnotacji.

Automatyczne okablowanie określonych wystąpień klas przy użyciu ogólnych parametrów typu

Jeśli masz interfejs z ogólnym parametrem typu, Spring może go użyć tylko do implementacji autowire, które implementują określony parametr typu.

Berło:

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

Klasa Foo Validator:

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

Bar Validator Class:

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

Możesz teraz automatycznie przeprowadzić walidację tych walidatorów za pomocą parametrów typu, aby zdecydować, która instancja ma być autowire.

Berło:

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

Klasa:

@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
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow