Статьи

Использование Spring Bean в неуправляемом объекте

Нам приходится иметь дело с унаследованным кодом, даже когда мы хотим использовать самые лучшие и новейшие доступные технологии. Представьте, что новый код написан с использованием новейших технологий 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 и добавим в класс следующую функциональность.

  1. Этот класс также должен реализовывать интерфейс ApplicationContextAware из Spring. Единственный аргумент в методе, который нам нужно реализовать из интерфейса, — это аргумент ApplicationContext . Мы храним этот аргумент в статической переменной-члене.
  2. Создайте статический метод для возврата SpringContextBridgedServices и дайте этому методу вернуть SpringContextBridgedServices которым управляет Spring. Используйте applicationContext.getBean(SpringContextBridgedServices.class) чтобы вернуть его.
  3. Автоматически подключите 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 .