最近,我遇到了一個我從未遇到過的問題:引入了基于運行時引入的配置來重新連接Bean內部的功能。 這對于簡單的配置更改或交換掉諸如Strategy或Factory類之類的東西非常有價值,而不是重建應用程序上下文的復雜部分。
我能夠找到一些有關如何執行此操作的注釋,但是我認為有些人可能會發現我的注釋和代碼示例很有用,特別是因為我可以確認該技術在Spring 1.2.6之前的版本中可以使用。 不幸的是,并不是我們所有人都有幸成為每個圖書館中最新最好的圖書館。
問題范圍
我將概述的方法主要是針對單個bean的更改,盡管可以輕松擴展此代碼以更改多個bean。 可以通過JMX或向管理員公開的其他UI調用它。
它沒有涉及的一件事是在整個應用程序中重新布線單例–可以想到,這可以通過對當前應用程序上下文的某種反射和檢查來完成,但是在大多數應用程序中,除非它們具有某種臨時關閉或關閉的方式,否則可能不安全。在整個應用程序中進行更改時,將一段時間內的所有處理都阻塞。
編碼
這是示例代碼。 它將獲取一個包含bean定義的字符串列表,并將它們連接到新的臨時Spring上下文中。 您將看到可以提供父上下文,這在您的新bean定義需要引用應用程序中已經配置的bean時很有用。
public static <T> Map<String, T> extractBeans(Class<T> beanType,List<String> contextXmls, ApplicationContext parentContext) throws Exception {List<String> paths = new ArrayList<String>();try {for (String xml : contextXmls) {File file = File.createTempFile("spring", "xml");// ... write the file using a utility methodFileUtils.writeStringToFile(file, xml, "UTF-8");paths.add(file.getAbsolutePath());}String[] pathArray = paths.toArray(new String[0]);return buildContextAndGetBeans(beanType, pathArray, parentContext);} finally {// ... clean up temp files immediately if desired}
}private static <T> Map<String, T> buildContextAndGetBeans(Class<T> beanType,String[] paths, ApplicationContext parentContext) throws Exception {FileSystemXmlApplicationContext context =new FileSystemXmlApplicationContext(paths, false, parentContext) {@Override // suppress refresh events bubbling to parent contextpublic void publishEvent(ApplicationEvent event) { }};try {// avoid classloader errors in some environmentscontext.setClassLoader(beanType.getClassLoader());context.refresh(); // parse and load contextMap<String, T> beanMap = context.getBeansOfType(beanType);return beanMap;} finally {try {context.close();} catch (Exception e) {// ... log this}}
}
如果查看buildContextAndGetBeans() ,您將看到它通過使用提供的XML bean定義文件構建Spring上下文來完成大部分工作。 然后,它返回所請求類型的構造bean的映射。
注意:由于臨時Spring上下文已被破壞,因此請確保您的bean沒有生命周期方法,該方法會導致它們在停止或破壞時處于無效狀態。
這是一個Spring上下文的示例,可用于重新連接組件。 想象一下,我們有一個電子商務系統,可以進行欺詐檢查,但是可以使用多種策略來檢查欺詐。 我們可能希望從服務類中交換這些內??容,而不必停止并重新配置應用程序,因為這樣做會造成業務損失。 也許我們正在發現對該系統的特定濫用,可以通過更改用于定位欺詐性訂單的策略來更好地解決。
這是一個示例XML定義,可用于重新連接我們的FraudService 。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans><bean id="fraudStrategy" class="com.example.SomeFraudStategory"><!-- example of a bean defined in the parent application context that we can reference --><property name="fraudRuleFactory" ref="fraudRuleFactory"/></bean>
</beans>
這是您可以使用對定義的欺詐策略的引用來重新連接Bean的代碼,假設您已將其包含在名為SpringUtils的實用工具類中:
public class FraudService implements ApplicationContextAware {private ApplicationContext context;// volatile for thread safety (in Java 1.5 and up only)private volatile FraudStrategy fraudStrategy;@Override // get a handle on the the parent contextpublic void setApplicationContext(ApplicationContext context) {this.context = context;}public void swapFraudStategy(String xmlDefinition) throws Exception {List<Sting> definitions = Arrays.asList(xmlDefinition);Map<String, FraudStrategy> beans =SpringUtils.extractBeans(FraudStrategy.class, definitions, context);if (beans.size() != 1) {throw new RuntimeException("Invalid number of beans: " + beans .size());}this.fraudStrategy = beans.values().iterator().next();}}
在那里,您擁有了! 可以適當地擴展此示例以滿足您的需求,但是我認為它展示了如何動態創建Spring上下文并使用其bean重新配置應用程序而無需停機的基礎知識。
參考:在Carfey Software博客上 ,我們的JCG合作伙伴提供了在運行時交換Spring Bean配置的信息 。
- 零XML的Spring配置
- Spring依賴注入技術的發展
- Spring MVC3 Hibernate CRUD示例應用程序
- 使用Spring AOP進行面向方面的編程
- Spring MVC開發–快速教程
翻譯自: https://www.javacodegeeks.com/2011/09/swapping-out-spring-bean-configuration.html