2014-02-27 67 views
2

我有一個servlet打包在耳朵文件中,我無法解決@Value註釋的屬性。如何解決Web Servlet中的Spring @Value批註?

該應用程序分爲兩部分:一個打包在一個war文件中的servlet,然後包含在一個ear文件中的不同應用程序中。該應用程序提供了由servlet中的接口定義的類(ResourceManager)的實現,以及包含@Value註釋字段的屬性值的屬性文件。

戰爭文件包含:

的web.xml:

<servlet> 
    <servlet-class>... extends MessageDispatcherServlet</servlet-class> 
    <init-param> 
    <param-name>contextConfigLocation</param-name> 
    <param-value> 
     classpath:/spring-ws.xml 
     classpath:/spring-app.xml 
    </param-value> 
    </init-param> 
</servlet> 

彈簧ws.xml:

<context:annotation-config/> 
<context:property-placeholder location="classpath:/spring-ws.properties"/> 

在spring-ws.properties值從春天直接引用-ws.xml,並且一切正常。

該servlet類包含:

public class MyServlet extends MessageDispatcherServlet 

    @Autowired private ResourceManager resourceManager; // original annotation - got this to work 
    @Value("${app.name:}") private String appName;  // added later - cannot get this to work 

的app.name是可選的,因此尾隨 「:」。

EAR文件添加(封裝在耳lib目錄JAR文件中):

彈簧app.xml中:

<context:property-placeholder location="classpath:/spring-app.properties"/> 

    <bean class="ResourceManagerImpl"> 
    ... 
    </bean> 

spring-app.properties:

app.name=myApp 

我的第一個問題是使用@Autowired註釋:我不確定我是否已經正確使用了底部,但我設法通過將此代碼添加到servlet中來實現它:

@Override 
protected void initFrameworkServlet() throws ServletException { 

    AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor(); 
    bpp.setBeanFactory(getWebApplicationContext().getAutowireCapableBeanFactory()); 
    bpp.processInjection(this); 
} 

這可能不是解決這個問題的最佳方法,但它是我找到的第一個工作,因此我使用它並繼續前進。然後我添加了一個@Value註釋字段,我找不到一種方法來完成這項工作。 AutowiredAnnotationBeanPostProcessor的javadocs表示它也應該處理@Value註釋,但它看起來並不像:appName屬性始終爲空(大概是默認值)。

我有一種變通方法,使用豆類:

@Autowired @Qualifier("appName") private String appName; 

<bean id="appName" class="java.lang.String"> 
    <constructor-arg value="myApp"/> 
</bean> 

但我敢肯定,必須有這樣做的更好的方法。我讀過這篇文章Difference between applicationContext.xml and spring-servlet.xml in Spring Framework,但我不確定它是否適用:我不認爲我在這裏甚至沒有應用程序上下文,只是在(單個)servlet類的web.xml中定義的servlet上下文。

我也看到了這一點:Spring 3.0.5 doesn't evaluate @Value annotation from properties,它看起來像同樣的問題,但解決的辦法有似乎是移動的「<方面:財產佔位>」從應用程序上下文的servlet上下文,而爲我之前說的,我不認爲我連這裏有一個應用程序上下文...

最後,我已經在簡化問題,消除了單獨的應用程序,並在一個戰爭的一切包裝的快速去,但我不認爲這是問題(儘管顯然可能是錯誤的......):spring可以解析應用程序的類路徑。xml文件,因此它必須能夠解析app.properties文件的類路徑。

任何幫助都非常感謝,但我想在這一點上它有點學術興趣,因爲我有一個可行的解決方案(使用豆類)和支付賬單的人並不關心它如何工作作爲只要它有效!我只想知道下次我不需要複製(我認爲是)有缺陷的解決方法。

使用spring-ws-core 2.1.4,它通過maven相關性在spring 3.2.4中引入。

感謝

更新 - 解決

原來的關鍵,解決這個有人M Deinum的評論說,「你也有重複的元素......」。我在同一個上下文中有兩個獨立的PropertyPlaceholderConfigurers,所以第二個被忽略,它的屬性從未使用過。上下文本身(這是一個servlet上下文而不是根上下文)或註釋處理沒有問題。

所以修復是簡單地移除彈簧app.xml的屬性佔位符,並在彈簧ws.xml

<context:property-placeholder 
    location="classpath:/spring-ws.properties, 
       classpath:/spring-app.properties"/> 

TL結合兩種屬性文件;在這裏DR的回答Spring: namespace vs contextConfigLocation init parameters in web.xml也是真棒解釋如何處理不同的上下文!

乾杯,

回答

4

您的servlet不是Spring Servlet bean,它由Servlet容器管理。因此@Autowired之所以不起作用。 Spring只會處理它所知道的bean。

ContextLoaderListener和你的servlet(基本上任何擴展爲FrameworkServlet的servlet)都有自己的ApplicationContext實例。來自ContextLoaderListener的那個被用作servlet中構造的上下文的父代。所以你的servlet中確實有一個ApplicationContext

現在要正確解決此問題,您需要有一個PropertyPlaceHolderConfigurer來解析佔位符。由於PropertyPlaceHolderConfigurer是一個BeanFactoryPostProcessor,它只能在同一上下文中的bean上運行,因此ContextLoaderListener加載/配置的​​那個不會爲與servlet上下文相關的bean執行任何操作。 (因此,您需要將<context:property-placeholder ... />元素添加到servlet上下文中)。

你也有一個重複的元素,一般你想避免這種情況,因爲它會導致問題在同一時間,無論是一個覆蓋另一個,或者你會得到例外,佔位符無法解決任何一個PropertyPlaceHolderConfigurer

您的init代碼也過於複雜,您不需要AutowiredAnnotationBeanPostProcessor只需使用可用的方法。

getWebApplicationContext().getAutowireCapableBeanFactory().autowireBean(this); 

哪一個也只有AutowiredAnnotationBeanPostProcessor做的更多。

+0

謝謝 - 重複PropertyPlaceholderConfigurer是問題 - 請參閱上面的更新。我也按照你的建議更新了init代碼。 – Barney

0

的@Autowired註解,你只需要與那些註釋類:

@Configuration 
@PropertySource("classpath:myFile.properties") 
@ComponentScan("com.company.package") 

的@Configuration是使用Spring來告訴它是一個配置類(它取代你所提到的XML文件,XML的conf文件是春季2,註釋是新與Spring 3和4)

的@ComponentScan管理IOC(@Autowire)

的@PropertySource加載道具文件

那麼該類在啓動時初始化道具文件:

@Component("myFileProperties") 
public class MyFileProperties{ 

@Value("${app.name}") 
private String appName; 

public String getAppName() { 
    return appName; 
} 

public void setAppName(String appName) { 
    this.appName= appName; 
} 
} 

看看這裏,如果你想它可以激發你(在網絡背景下conf文件我開發的):https://github.com/ebrigand/RSSLiker/blob/master/src/main/java/com/mrm/rss/init/WebAppConfig.java

相關問題