spring
Tworzenie i używanie fasoli
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:
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(); } }
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>
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:
- Użyj iniekcji metodą wyszukiwania
- Pobierz
javax.inject.Provider
bean ojavax.inject.Provider
prototypowym za pośrednictwemjavax.inject.Provider
- Pobierz fasolę o
org.springframework.beans.factory.ObjectFactory
prototypu za pośrednictwemorg.springframework.beans.factory.ObjectFactory
(odpowiednik # 2, ale z klasą specyficzną dla Spring) - 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);
}
}