Как опубликовать бин статическим методом в Spring - PullRequest
0 голосов
/ 17 мая 2019

Я работаю над унаследованным приложением Spring-Boot, где я хотел бы использовать внедрение зависимостей с некоторым кодом, который существует вне контекста приложения. Одна часть приложения поставляется в виде отдельного JAR-файла и не может быть изменена. Но я могу изменить некоторые классы, которые создаются в этой части. Вот как я планирую это сделать:

class ServiceHolder {
   private static FooService fooService;
   public static FooService getFooService() { return fooService; }
   public static void setFooService(FooService service) { fooService = service; }
}

@Bean
@Profile("production")
FooService fooService() {
   var service = new ProductionFooService();
   ServiceHolder.setFooService(service);
   return service;
}

public class LegacyPojo {
   private final FooService fooService;
   public LegacyPojo() {
       fooService = ServiceHolder.getFooService();
   }
   //.. some business logic
}

Я обеспокоен возможными проблемами видимости, когда различные запросы в отдельных потоках будут вызывать new LegacyPojo() и достигать FooService экземпляра.

Итак, мой вопрос: я должен объявить ServiceHolder#getFooService и ServiceHolder#setFooService synchronized или нет?

Ответы [ 2 ]

0 голосов
/ 20 мая 2019

Это будет работать без какой-либо синхронизации, потому что экземпляр singleton bean будет создан в критической секции внутри блока synchronized.В классе DefaultSingletonBeanRegistry есть метод getSingleton, который, согласно документу:

/**
* Return the (raw) singleton object registered under the given name,
* creating and registering a new one if none registered yet.
* ...
*/

И в самом начале этого метода критический раздел начинается с synchronized (this.singletonObjects).Таким образом, эффект вызова ServiceHolder.setFooService(service) будет виден всем потокам после выхода из критической секции.

0 голосов
/ 17 мая 2019

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

Другая вещь, которую вы можете сделать, это управлять экземплярами FooService, вы можете сделать это как одиночный, объявив его как статическое свойство в ServiceHolder и не иметь setMethod.Я думаю, как вы сказали, вы хотите один экземпляр FooService.

Даже если LegacyPojo Pojo, вам не нужно создавать геттер для FooService.

После использования ServiceHolder.setFooService(service); вы можете сделать реализацию, подобную этой:

class ServiceHolder{
     private static FooService fooService;

     public static void setFooService(FooService newFooService){
          if(fooService== null){
                fooService = newFooService;
          }
     }
}

Таким образом, вы установите только первый экземпляр FOoService, и он не будет изменен, конечно, вы можете выполнить любое условие для setFooService в ServiceHolder

...