2013-02-04 59 views
2


我有一個需求,其中我在Spring項目中定義了一個合同,並希望在實現合同(接口集)的部署期間自動調用外部JAR。我不想強制外部JAR依賴於Spring,因此它儘可能靈活。在我的Spring項目中無法使用外部JAR中的類作爲我使用我的合同接口的自動裝填替換?讓我用一個例子解釋:如何爲來自外部非彈簧項目的類設置自動裝配

Spring project: 
@Controller 
public class MyController { 
    @Autowired 
    private MyInterface interface; 
} 

現在實施合同接口的JAR可以由客戶提供,我可能不知道前手包的名稱,它甚至可以是一個非Spring項目,所以它可能不能用@Component註解聲明。

例如

public class CustomerClass implements MyInterface { 
} 

現在在我的春天項目,有沒有辦法在地方MyInterface的的注入CustomerClass?我希望我的問題很清楚。

感謝

回答

2

@ Paddy, 關於您是否可以用傳統的XML方式來實現相同的目標。以下是顯示如何實現它的示例代碼。注意:接口MyInterface不能以這種方式動態化,因爲控制器正在持有MyInterface

Spring應用程序上下文配置:

<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> 
    <property name="locations" value="classpath:test.properties" /> 
</bean> 
<bean id="myInterface" class="${myinterface.impl}"></bean> 

MyInterface的兩個不同的實現類

package au.net.test; 

public interface MyInterface { 

    public String getMessage(); 
} 

public class MyClass1 implements MyInterface{ 

    public String getMessage(){ 
     return "message from class 1"; 
    } 
} 

public class MyClass2 implements MyInterface{ 

    public String getMessage() { 
     return "message from class 2"; 
    } 
} 

測試。性能下的classpath文件(可以使用Ant腳本和Maven資料,以更改屬性值)

myinterface.impl=au.net.test.MyClass2 

網絡層控制器(可以基於動態豆候選人注入實現類)

@Autowired 
private MyInterface myInterface; 
+0

此屬性方法對我的情況看起來不錯,我打算使用它。再次感謝@spiritwalker – Paddy

+0

@ Paddy請足夠承認並接受帖子作爲答案,至少您可以爲海報花費時間回答您的問題 – Sudhakar

0

你可以用工廠方法一起使用工廠豆

<bean id="serviceProvider" class="package.ServiceProvider"> 

<bean id="myInterface" 
     factory-bean="serviceProvider" 
     factory-method="createMyInterfaceInstance"/> 
//it might or might not to be a singleton factory, depending on your requirement. 
public class ServiceProvider{ 
    private static MyInterface myInterface= new CustomerClass(); 

    private ServiceProvider() {} 

    public MyInterface createMyInterfaceInstance() { 
    return myInterface; 
    } 
} 

所以基本上這裏的想法是,你必須創建用於創建例如,根據自己的工廠類和工廠方法在您的工廠,它可能會創建單身或原型。然後把剩下的工作留給春天的容器。

+0

嗨,
如果我的理解錯誤,請糾正我,但在您所示的示例中,class屬性指示包,在我的情況下,可能在編譯時不知道包。 JAR文件路徑可以在'ant package'或'maven install/deploy'期間作爲屬性提供。所以我可能無法用這種方式宣佈,不是嗎?
謝謝,Paddy – Paddy

+0

「package.ServiceProvider」與JAR文件路徑無關,它只是**完全限定的類名**。我不確定在你的情況下,在運行時如何得到**完全限定的類名**。如果類名無法解析,您如何在客戶端代碼中引用它? – spiritwalker

+0

可能不是有效的用例,但我只是試圖通過給JAR提供路徑來查看客戶端JAR是否可以與我的項目集成。換句話說,我希望有一個項目,您可以將一個客戶JAR附加到一個客戶JAR中,該JAR實現了我所知道的合同,並在不知道客戶JAR包結構的情況下開始使用它。然後,我的項目將成爲一個模板項目(或稱之爲模板產品),可以與任何客戶端實現集成,而無需瞭解客戶端JAR的具體細節(包括包名稱)。不知道這是否有效/可能? – Paddy

1

好吧,我明白了你的意思。如果是這樣的話,你的問題標題應該是如何通過Spring容器注入動態類的類現在讓我們來討論解決方案。首先,你需要有一些屬性來保存完全合格的類名。然後,您可以在運行時將自定義bean註冊到spring容器中。

ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:/applicationContext*"); 
     DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) applicationContext.getBeanFactory(); 
      //register your bean at runtime 
     beanFactory.registerBeanDefinition("myClass", BeanDefinitionBuilder.rootBeanDefinition("au.net.test.DynamicClass").getBeanDefinition()); 
      //retrieve you bean from spring container 
     Object myBean = applicationContext.getBean("myClass"); 
      //cast to the type of your bean class or interface (be really careful) 
     System.out.println(((DynamicClass)myBean).getMessage()); 


package au.net.test; 
//this is the bean gets looked up and injected at runtime 
public class DynamicClass { 
    //simple method to verify it is working 
    public String getMessage(){ 
     return "this is testing message"; 
    } 
} 

在上面的代碼中,您只需要使「au.net.test」屬性值被驅動而不是硬編碼。

+0

謝謝你的解釋。老實說,更好的標題並沒有打動我。有沒有一個上下文的xml方法來做上面的第一個代碼片段而不是Java代碼?如果Java代碼是唯一的方法,那麼我在哪裏(意思是哪一類)放置了這段代碼?爲了在每個需要特定合約界面的控制器類中都有這樣的代碼,我猜可能不是一個更好的方法。 – Paddy

+0

你不必重複每一個代碼。您可以將代碼集中到單獨的類中,併爲您的控制器提供一個公共方法來獲取bean。順便說一句,** MyInterface **會是動態的還是靜態的? – spiritwalker

+0

感謝您的澄清。當然MyInterface是靜態的:) – Paddy