2017-04-05 75 views
0

我有一個域類,我想從外部配置中自動填充。這裏是我的域類:Autowire在單元測試中工作,但不在主java類中

@Data 
@Configuration 
@PropertySource("classpath:application.properties") 
public class StudioVo { 

    @Value("${studio.code}") 
    private code; 

    @Bean 
    public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() { 
     return new PropertySourcesPlaceholderConfigurer(); 
    } 
} 

這裏是我的上下文XML:

<bean class="org.springframework.batch.core.scope.StepScope" /> 
<bean id="ItemReader" class="com.sdm.studio.reader.StudioReader" scope="step"> 
    <property name="studioVo" ref="StudioVo" /> 
</bean> 

<bean id="StudioConfigVo" class="com.sdm.studio.domain.StudioVo" /> 

</bean> 

這裏就是我想用VO類:當我運行它

@Slf4j 
@Data 
public class StudioReader implements ItemReader<List<Studio>> { 

    private StudioVo studioVo; 

    public List<Studio> read() throws Exception { 

     System.out.println("getCode: " + studioVo.getCode()); //code is null here 

     return null; 
    } 

} 

然而通過自動裝配進行單元測試,它運行良好。就像這樣:

@RunWith(SpringRunner.class) 
@SpringBootTest 
public class StudioTest { 

    @Autowired 
    private StudioVo studioVo; 

    @Test 
    public void testAutoPopulationOfStudio(){ 
     System.out.println("getCode: "+ studioVo.getCode()); // works! 
     // Assert.assertTrue(studioVo.getCode().equals("102")); 
    } 
} 

不知道是怎麼回事就在這裏 - 我與包裹在春季啓動(舊Spring Batch的應用程序工作,所以有基於XML和基於Java的配置的混合 - 並且可以是這個問題的原因)。我錯過了什麼?

回答

0

在你StudioTest,你是自動裝配StudioReader那裏,你錯過了你的StudioReader代碼@Autowired,所以將其添加如下圖所示:

@Slf4j 
@Data 
public class StudioReader implements ItemReader<List<Studio>> { 

    @Autowired //add this so that studioVo can be injected 
    private StudioVo studioVo; 

    //add other code 
} 
+0

看看context.xml - 它是在那裏定義的。如果我Autowire,它發現不止一個bean,不能autowire。 – Yana

0

請一定要注意,使用@Autowire需要的鏈彈簧管理的豆子,無論你在哪裏使用它包括你正在使用@Autowire的類。這是因爲Spring需要先例引用來匹配對象引用層次結構。也就是說,在業務邏輯層ClassA中,你想要@Autowire一個字段。 ClassA本身需要是一個託管bean。此外,如果您想要@Autowire的字段包含對其他對象具有參照依賴性的對象(並且大部分都是這樣),則這些對象也必須由Spring管理。

例如,下面的工作:

package com.example.demo; 

import org.springframework.context.annotation.AnnotationConfigApplicationContext; 


public class MessageRunner { 

private static SetterMessage setterMessage; 

public static void main(String[] args) { 
    setterMessage = (SetterMessage) (new AnnotationConfigApplicationContext(DemoConfiguration.class)).getBean("setterMessage"); 
    setterMessage.setMessage("Finally it works."); 
    p(setterMessage.getMessage()); 
} 

private static void p(String s) { 
    System.out.println(s); 
} 

} 

DemoConfiguration.java看起來是這樣的:

package com.example.demo; 

import org.springframework.context.annotation.ComponentScan; 
import org.springframework.context.annotation.Configuration; 

@Configuration 
@ComponentScan(basePackages = "com.example.demo") 
public class DemoConfiguration { 
} 

SetterMessage.java,這樣的:

package com.example.demo; 

import org.springframework.beans.factory.annotation.Autowired; 
import org.springframework.context.annotation.Scope; 
import org.springframework.stereotype.Service; 

@Service 
@Scope("prototype") 
public class SetterMessage { 

private String message = null; 

@Autowired 
private SetterMessage2 setterMessage2; 

public String getMessage(){ 
    return message+setterMessage2.getSubMessage(); 
} 

public void setMessage(String message) { 
    this.message = message; 
    setterMessage2.setSubMessage("("+message+")"); 
} 

} 

SetterMessage2.java:

package com.example.demo; 

import org.springframework.context.annotation.Scope; 
import org.springframework.stereotype.Service; 


@Service 
@Scope("prototype") 
public class SetterMessage2 { 

private String subMsg = ""; 

public void setSubMessage(String msg) { 
    subMsg = msg; 
} 

public String getSubMessage() { 
    return subMsg; 
} 

} 

請注意,SetterMessage2.java註釋爲Component(@Service),但其中沒有字段是自動裝配的。那是因爲它是對象引用鏈的結尾。但是因爲它是一個組件,所以它可以自動裝入SetterMessage.java。然而看看MessageRunner.java的main()方法和字段聲明。請注意,類字段SetterMessage不是自動裝配的。如果註釋爲@Autowired,則main()在運行時會失敗,並在main()中引用setterMessage引用的NPE。這是因爲MessageRunner.java沒有標記爲某種組件。所以我們需要從應用程序上下文中獲取一個有效的MessageSetter實例並使用它。

要強調的是,MessageRunner.java的main()方法將失敗以下版本,拋出NPE,如果MessageRunner.java是這樣的:

... 
public class MessageRunner { 

@Autowired // <-- This will not do the job for us 
private static SetterMessage setterMessage; 

public static void main(String[] args) { 
    setterMessage.setMessage("Finally it works."); // NPE here on ref to setterMessage 
    p(setterMessage.getMessage()); 
} 
... 

這是人們新的春天真正gotchya 。事實上,我將它列入五大春季新手勸阻者和一個非常邪惡的,有害的細節,導致新的春季程序員無數小時的加重和谷歌搜索。所以我希望在這裏注意到這個現象至少可以節省一些新手時間和高血壓的高峯。

注意:如果您要在IDE中創建上述類,請記住這些是在啓用Spring Boot的情況下開發的。

相關問題