在运行时更改弹簧豆实现

发布于 2025-01-23 21:37:01 字数 813 浏览 2 评论 0原文

我有一个接口和多个实现。我正在自动将界面接线以供使用。我需要在运行时选择不同的实现。

public class Util {
  public void getClient();
}

public class UtilOne implements Util {
  public void getClient() {...}
}

public class UtilTwo implements Util {
  public void getClient() {...}
}

@Configuration
public class AppConfig {
  
  @Autowired
  @Bean
  @Primary
  public Util utilOne() {
    return new UtilOne();
  }

  @Autowired
  @Bean
  public Util utilTwo() {
    return new UtilTwo();
  }

}
@Component
public class DemoService {

  @Autowired
  private Util util;
}

由于某种原因,如果我们无法将客户端进入UTILONE,则我想在不重新启动应用程序的情况下切换到Utiltwo 我想将DemoService中的util对象更改为Utiltwo对象。 属性active.util将来自数据库,我们可以从UI更新。

I have an Interface and multiple implementation. I'm auto wiring the interface in classes for usage. I need to choose different implementation at runtime.

public class Util {
  public void getClient();
}

Implementations

public class UtilOne implements Util {
  public void getClient() {...}
}

public class UtilTwo implements Util {
  public void getClient() {...}
}

@Configuration
public class AppConfig {
  
  @Autowired
  @Bean
  @Primary
  public Util utilOne() {
    return new UtilOne();
  }

  @Autowired
  @Bean
  public Util utilTwo() {
    return new UtilTwo();
  }

}
@Component
public class DemoService {

  @Autowired
  private Util util;
}

For some reason if we are unable to get client in UtilOne, I want to switch to UtilTwo without restarting the app. I want to change the Util object in DemoService to UtilTwo object.
Property active.util will come from DB and can we updated from UI.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

迷离° 2025-01-30 21:37:01

它不起作用 - 如果您有一定的实现UTIRE的实现,例如,class sampleclass(这是单身人士),则不能真正将UTIT的实现更改为不同的事物,而无需重新启动应用程序上下文。

因此,我没有这样做,而是建议替代方案。您说,在某些条件下,在运行时评估您要切换实现。它是什么样的条件?是否可以提取此条件决策逻辑?

如果是这样,您可以自动使用特殊的DynamiCutil,该动态可以保留所有utils的参考,并根据条件将所需的UTIL调用:

// represents all possible business 'runtime' outcomes
enum ConditionOutcome {
   A, B, C 
}
interface ConditionEvaluator {
   ConditionOutcome evaluate(); // when called in runtime will evaluate a condition that currently exists in the system
}

interface Util {
   void foo();
   ConditionOutcome relevantOfOutcome();
}

class Utill1Impl implements Util {
   public void foo() {...}
   public ConditionOutcome relevantOfOutcome() {return ConditionOutcome.A;}
}
class Utill2Impl implements Util {
   public void foo() {...}
   public ConditionOutcome relevantOfOutcome() {return ConditionOutcome.B;}
}
class Utill3Impl implements Util {
   public void foo() {...}
   public ConditionOutcome relevantOfOutcome() {return ConditionOutcome.C;}
}

class DynamicUtil {
   private final Map<ConditionOutcome, Util> possibleImpls;
   private final ConditionEvaluator evaluator;

   public class DynamicUtil(List<Util> allImplementations, ConditionEvaluator evaluator) {
      // create a map by calling the 'relevantOfOutcome' per util impl in a loop
    this.evaluator = evaluator;
   }
   
   public void foo() {
      ConditionOutcome key = evaluator.evaluate();
      // pick the relevant implementation based on evaluated key
      possibleImpls.get(key).foo();
   }
}

现在,使用这样的设计,您可以动态地添加新的可能的结果(以及应该实现它们的utils。您在系统中的课程将必须自动dynamicutil,因此有效地您会引入一个额外的间接级别,但会获得灵活性

class SampleClass { // a business class that will need to work with util capable of being changed during the runtime 
   @Autowired
   private DynamicUtil util;
   ... 
}

It doesn't work this way - if you have a certain implementation of Util wired to, say, class SampleClass (which is a singleton) you can't really change the implementation of the Util to something different without restarting the application context.

So instead of going this way, I suggest an alternative. You say that under certain conditions that evaluate in runtime you want to switch implementations. What kind of condition it is? Is it possible to extract this condition decision logic?

If so, you can autowire a special DynamicUtil that will hold the reference to all the utils and will call the required util depending on the condition:

// represents all possible business 'runtime' outcomes
enum ConditionOutcome {
   A, B, C 
}
interface ConditionEvaluator {
   ConditionOutcome evaluate(); // when called in runtime will evaluate a condition that currently exists in the system
}

interface Util {
   void foo();
   ConditionOutcome relevantOfOutcome();
}

class Utill1Impl implements Util {
   public void foo() {...}
   public ConditionOutcome relevantOfOutcome() {return ConditionOutcome.A;}
}
class Utill2Impl implements Util {
   public void foo() {...}
   public ConditionOutcome relevantOfOutcome() {return ConditionOutcome.B;}
}
class Utill3Impl implements Util {
   public void foo() {...}
   public ConditionOutcome relevantOfOutcome() {return ConditionOutcome.C;}
}

class DynamicUtil {
   private final Map<ConditionOutcome, Util> possibleImpls;
   private final ConditionEvaluator evaluator;

   public class DynamicUtil(List<Util> allImplementations, ConditionEvaluator evaluator) {
      // create a map by calling the 'relevantOfOutcome' per util impl in a loop
    this.evaluator = evaluator;
   }
   
   public void foo() {
      ConditionOutcome key = evaluator.evaluate();
      // pick the relevant implementation based on evaluated key
      possibleImpls.get(key).foo();
   }
}

Now with such a design you can dynamically add new possible outcomes (along with utils that should implement them. You classes in the system will have to autowire DynamicUtil though, so effectively you'll introduce one additional level of indirection but will gain flexibility

class SampleClass { // a business class that will need to work with util capable of being changed during the runtime 
   @Autowired
   private DynamicUtil util;
   ... 
}
强者自强 2025-01-30 21:37:01

您可以尝试使用委派代理进行接近。拥有一个主util bean,它只是围绕实际实现包装,并允许在运行时更改其内部代表。此外,您可以创建类似的经理/助手类,该类别持有对所有实际实现bean的参考,以简化它们之间的切换。

@Component
@Primary
public class DelegatingUtil implements Util {
  private Util delegate;

  public void setDelegate(Util delegate){ this.delegate = delegate; }
  public Util getDelegate(){ return delegate; }

  public void getClient() {
    return delegate.getClient();
  }
}

在适用切换逻辑的地方:

  // Use @Named or @Qualifier or any other way to obtain references to actual implementations 
  private Util defaultImpl;
  private Util fallbackImpl;

  @Autowired
  private DelegatingUtil switcher;

  public void switchToFallback(){
    this.switcher.setDelegate(this.fallbackImpl);
  }

请注意,这只是示意图的示例,您应该注意诸如豆类创建订单,预选器注入(也许是条件),初始化等细节。

You can try approach with delegating proxy. Have a primary Util bean that is just wrapper around actual implementation and allow to change its internal delegate at runtime. In addition you can create something like manager/helper class that holds references to all actual implementation beans to simplify switching between them.

@Component
@Primary
public class DelegatingUtil implements Util {
  private Util delegate;

  public void setDelegate(Util delegate){ this.delegate = delegate; }
  public Util getDelegate(){ return delegate; }

  public void getClient() {
    return delegate.getClient();
  }
}

And where switching logic applies:

  // Use @Named or @Qualifier or any other way to obtain references to actual implementations 
  private Util defaultImpl;
  private Util fallbackImpl;

  @Autowired
  private DelegatingUtil switcher;

  public void switchToFallback(){
    this.switcher.setDelegate(this.fallbackImpl);
  }

Note, this is only schematic example, you should take care about details like bean creation order, injection with qualifiers (maybe conditional), initialization and so on.

翻身的咸鱼 2025-01-30 21:37:01

这是根据您的情况进行的简单方法。主要想法是读取active.util propertyservice tb的属性,并将您的utils包装到route> outeutil

@Component
public class RouteUtil {

    @Autowired
    private PropertyService propertyService;  

    @Qualifier("one")
    @Autowired
    private Util utilOne;

    @Qualifier("two")
    @Autowired
    private Util utilTwo;

    public void getClient() {
        if ("one".equals(propertyService.read("active.util"))) {
            utilOne.getClient();
        } else {
            utilTwo.getClient();
        }
    }
}

in demoService中:

@Service
public class DemoService {

  @Autowired
  private RouteUtil util;

  // RouteUtil.getClient() ...
}

您可以更改<<<<<<< :代码> Active.util 要在不重新启动应用程序的情况下选择哪个UTIT在运行时使用。

Here is a simple approach based on your situation. The main idea is that read active.util property from DB by PropertyService and wrap your Utils into RouteUtil:

@Component
public class RouteUtil {

    @Autowired
    private PropertyService propertyService;  

    @Qualifier("one")
    @Autowired
    private Util utilOne;

    @Qualifier("two")
    @Autowired
    private Util utilTwo;

    public void getClient() {
        if ("one".equals(propertyService.read("active.util"))) {
            utilOne.getClient();
        } else {
            utilTwo.getClient();
        }
    }
}

and in DemoService:

@Service
public class DemoService {

  @Autowired
  private RouteUtil util;

  // RouteUtil.getClient() ...
}

You can change active.util to select which Util will be used at runtime without restarting the app.

夜声 2025-01-30 21:37:01

春季为您提供了我个人不喜欢的解决方案。您可以做的是声明一个

@MyInterface
List<MyIntercase> myimpls

myinterface是您的接口,列表将包含所有实现。但是,我(由于我不喜欢这种解决方案)编写了自己的解决方案,在那里您可以拥有一个由所有实现的静态工厂。因此,您不必注入所有实现,而是按班级名称或自定义的名称从工厂中选择它们。另一个优势是,自定义的名称必须是每个工厂唯一的。因此,可以说您有一些分阶段的过程,在每个阶段,您都有自己的界面和自己的工厂。因此,您可以具有相同的自定义名称,以实现不同的接口。假设您使用文本格式XML,JSON和CSV,并为SAVE-1阶段2阶段3具有一个接口(和相关工厂)。因此,对于每个阶段-X iNteface,您可以使用命令命名JSONXMLcsv,因此您要做的就是具有一个称为<<的变量Code> CurrentType 将保存值之一 - JSONXMLcsv,对于每个阶段,您都可以使用工厂要获得适当的实现:

Stage1Handler handler = stage-1-factory.getInstance(currentValue);
Stage2Handler handler = stage-2-factory.getInstance(currentValue);
Stage3Handler handler = stage-3-factory.getInstance(currentValue);

其中阶段[x]处理程序是您的接口。但这只是一个额外的兴趣。我的解决方案可在开源Mgntutils库中获得。有关此特定锻炼的文章可以在此处找到:春季框架中对“孤儿”豆的非侵入式访问另外,我在图书馆中描述了此功能Javadoc 在这里。可以找到该库为 maven trifact “ https://github.com/michaelgantman/mgnt/releases” rel =“ nofollow noreferrer”> github 包括源代码和javadoc

Spring provides you a solution which I personally didn't like. What you can do is declare a

@MyInterface
List<MyIntercase> myimpls

Where MyInterface is your interface and list will contain all the implementations. However, I (since I didn't like this solution) wrote my own solution, where you can have a static factory that is self-populated by all implementations. So you don't have to inject all your implementations but choose them at run-time from a factory either by class name or by custom-defined name. An additional advantage is that the custom-defined name must be unique per factory. So lets say you have some staged process and for each stage you have your own interface and your own factory. So you can have the same custom defined names for your implementations of different interfaces. Say you working with text formats XML, JSON and CSV and have an interface (and related factory) for say stage-1 stage-2 stage-3. So for each stage-X inteface you can have implemetations named JSON, XML and CSV so all you have to do is have a variable called currentType that will hold one of the values - JSON, XML and CSV and for each stage you can use the factory to get the appropriate implementation:

Stage1Handler handler = stage-1-factory.getInstance(currentValue);
Stage2Handler handler = stage-2-factory.getInstance(currentValue);
Stage3Handler handler = stage-3-factory.getInstance(currentValue);

where Stage[X]Handler is your interface. But this is just an additional benifit. My solution is available in Open-source MgntUtils library. The article about this particular fiture could be found here: Non-intrusive access to "Orphaned" Beans in Spring framework Also, I describe this feature in my library javadoc here. The library could be found as Maven artifact and on Github including source code and Javadoc

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文