Нам приходится иметь дело с унаследованным кодом, даже когда мы хотим использовать самые лучшие и новейшие доступные технологии. Представьте, что новый код написан с использованием новейших технологий Spring Framework, а унаследованный код вообще не написан на Spring. Затем использование управляемых bean-компонентов Spring в неуправляемых объектах Spring — один из шаблонов, с которыми нам приходится иметь дело. Унаследованный код содержит неуправляемые объекты Spring, а код, на который мы хотим сослаться, — это управляемый компонент Spring. Как мы решаем эту проблему?
Создать бобов весны
Предположим, у нас есть управляемый Spring Bean под названием TaxService
и объект с именем LegacyObject
. LegacyObject
— это унаследованный код, из которого мы могли бы сделать ссылку на метод LegacyObject
в управляемом Spring Bean.
TaxService
01
02
03
04
05
06
07
08
09
10
11
12
13
|
package com.jdriven; import org.springframework.stereotype.Service; @Service public class TaxServiceImpl implements TaxService { @Override public Double calculateTax(Double price) { return new Double(price * 0.21 ); } } |
Интерфейс с мостовыми методами обслуживания
Мы определяем интерфейс, который содержит список методов. Каждый из этих методов возвращает управляемый компонент Spring. Мы создаем метод getTaxService
для возврата только что созданного TaxService
.
SpringContextBridgedServices
1
2
3
4
5
6
7
8
|
package com.jdriven; /** * This interface represents a list of Spring Beans (services) which need to be referenced from a non Spring class. */ public interface SpringContextBridgedServices { TaxService getTaxService(); } |
Реализуйте Spring Context Bridge
Далее мы создаем реализацию для интерфейса SpringContextBridgedServices
. Давайте назовем этот класс SpringContextBridge
сделаем его Spring Bean и добавим в класс следующую функциональность.
- Этот класс также должен реализовывать интерфейс
ApplicationContextAware
из Spring. Единственный аргумент в методе, который нам нужно реализовать из интерфейса, — это аргументApplicationContext
. Мы храним этот аргумент в статической переменной-члене. - Создайте статический метод для возврата
SpringContextBridgedServices
и дайте этому методу вернутьSpringContextBridgedServices
которым управляет Spring. ИспользуйтеapplicationContext.getBean(SpringContextBridgedServices.class)
чтобы вернуть его. - Автоматически подключите
TaxService
и верните его в методе, который нам нужно реализовать из методаSpringContextBridgedServices
.
SpringContextBridge
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
|
package com.jdriven; import org.springframework.beans.BeansException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.stereotype.Component; /** * Register this SpringContextBridge as a Spring Component. */ @Component public class SpringContextBridge implements SpringContextBridgedServices, ApplicationContextAware { private static ApplicationContext applicationContext; @Autowired private TaxService taxService; //Autowire the TaxService @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this .applicationContext = applicationContext; } /** * A static method to lookup the SpringContextBridgedServices Bean in * the applicationContext. It is basically an instance of itself, which * was registered by the @Component annotation. * * @return the SpringContextBridgedServices, which exposes all the * Spring services that are bridged from the Spring context. */ public static SpringContextBridgedServices services() { return applicationContext.getBean(SpringContextBridgedServices. class ); } @Override public TaxService getTaxService() { return taxService; //Return the Autowired taxService } } |
- Примечание 1: есть возможность вернуть управляемый бин Spring в самом статическом методе. Я предпочитаю этого не делать, поэтому у меня меньше статических методов, и я могу позже смоделировать некоторые службы ссылок.
- Примечание 2: В конце концов вы хотели бы разделить две функции. Один, содержащий
ApplicationContext
и возвращающийSpringContextBridgedServices
. Другой — самSpringContextBridgedServices
. В этой короткой демонстрации я просто поместил их в один и тот же компонент.
Возьми меня на мост
Теперь пришло время позвонить на мост. Это так просто, как показано в коде ниже.
LegacyObject
01
02
03
04
05
06
07
08
09
10
11
12
|
package com.jdriven; public class LegacyObject { private Double price; public Double doTheCalculation() { //Get the Service from the Bridge TaxService taxService = SpringContextBridge.services().getTaxService(); return taxService.calculateTax( this .price); } } |
Гибкая, но не ограниченная альтернатива
Это способ, которым список связанных служб ограничен. Только сервисы, упомянутые в интерфейсе SpringContextBridgedServices
будут соединены мостом. Если вы хотите более гибкий, но менее контролируемый способ, вы можете переписать SpringContextBridgedServices
.
SpringContextBridgedServicesAlternative
1
2
3
4
5
6
|
package com.jdriven; public interface SpringContextBridgedServicesAlternative { <T> T getService(Class<T> serviceType); } |
Теперь мы можем получить сервис, вызвав SpringContextBridge.services().getService(TaxService.class)
. В этой альтернативе у нас нет контроля над тем, какой управляемый бин Spring может быть соединен.
Ссылка: | Использование Spring Bean в неуправляемом объекте от нашего партнера по JCG Виллема Чейзу из блога JDriven . |