2016-07-14 141 views
0

我在簡單的Spring Boot應用程序上工作,並希望在其上使用併發線程。爲了實現這一點,我在服務方法上使用@Async註釋,但是當我添加@Async註釋時,彈簧DI崩潰。它在一個線程內沒有@Async的情況下工作沒有問題。要調用服務方法,我創建了jUnit測試。錯誤日誌顯示DI不起作用,並且沒有爲服務類找到這樣的bean。請幫助在Spring上使用@Async運行多個線程。爲什麼Spring Boot應用程序使用@Async註釋方法崩潰


編輯 我試圖把我的測試類@Autowired服務接口,而不是它的實現和@Async方法在其他線程運行之後。我應該如何測試我的服務的不同實現?

當時和崩潰:

@Autowired 
CatalogPageServiceImpl catalogPageServiceImpl; 

現在,而不是崩潰:

@Autowired 
CatalogPageService catalogPageService; 

我的服務接口:

public interface CatalogPageService { 
    public void processPagesList(List<CatalogPage> catalogPage); 
    public void processPage(CatalogPage catalogPage); 
} 

測試類:

@RunWith(SpringJUnit4ClassRunner.class) 
@SpringApplicationConfiguration(classes = CLApplication.class) 
@TestPropertySource(locations="classpath:test.properties") 
public class CatalogPageServiceImplTest { 

    @Autowired 
    CatalogPageServiceImpl catalogPageServiceImpl; 

    @Test 
    public void processPageTest(){ 
     for (int i=0; i<20; i++){ 
      catalogPageServiceImpl.processPage(
        new CatalogPage("test url string "+Integer.toString(i))); 
     } 
    } 
} 

應用類:

@SpringBootApplication 
@EnableAsync 
@ComponentScan(basePackages = {"org.cl, org.cl.service.location "}) 
public class CLApplication { 

    private static final Logger log = LoggerFactory.getLogger(CLApplication.class); 

    @Bean 
    public TaskExecutor locationPageExecutor() { 
     ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); 
     executor.setCorePoolSize(20); 
     executor.setMaxPoolSize(20); 
     executor.setQueueCapacity(20); 
     return executor; 
    } 

    public static void main(String[] args) { 
     log.info("Application main method call"); 
     try{ 
      SpringApplication.run(CLApplication.class, args); 
     }catch(Throwable t){ 
      log.error("Unexpected error: ",t); 
     } 
     log.info("Application main method exit"); 
    } 
} 

服務類:

@Service 
public class CatalogPageServiceImpl implements CatalogPageService { 

    @Override 
    public void processPagesList(List<CatalogPage> catalogPageList) { 
     for (CatalogPage catalogPage:catalogPageList){ 
      processPage(catalogPage); 
     } 
    } 

    @Override 
    @Async("locationPageExecutor") 
    public void processPage(CatalogPage catalogPage) { 
     try { 
      Thread.sleep((new Random()).nextInt(1000)); 
     } catch (InterruptedException e) { 
      e.printStackTrace(); 
     } 
     System.out.println("print from Async method "+catalogPage.getUrl()); 
    } 
} 

錯誤日誌:

org.springframework.beans.factory.BeanCreationException: Error creating bean wit 
h name 'org.cl.service.CatalogPageServiceImplTest': Injection of autowired depen 
dencies failed; nested exception is org.springframework.beans.factory.BeanCreati 
onException: Could not autowire field: org.cl.service.location.CatalogPageServic 
eImpl org.cl.service.CatalogPageServiceImplTest.catalogPageServiceImpl; nested e 
xception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No 
qualifying bean of type [org.cl.service.location.CatalogPageServiceImpl] found f 
or dependency: expected at least 1 bean which qualifies as autowire candidate fo 
r this dependency. Dependency annotations: {@org.springframework.beans.factory.a 
nnotation.Autowired(required=true)} 
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProc 
essor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:334) ~ 
[spring-beans-4.2.7.RELEASE.jar:4.2.7.RELEASE] 
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory 
.populateBean(AbstractAutowireCapableBeanFactory.java:1214) ~[spring-beans-4.2.7 
.RELEASE.jar:4.2.7.RELEASE] 
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory 
.autowireBeanProperties(AbstractAutowireCapableBeanFactory.java:385) ~[spring-be 
ans-4.2.7.RELEASE.jar:4.2.7.RELEASE] 
    at org.springframework.test.context.support.DependencyInjectionTestExecutionLis 
tener.injectDependencies(DependencyInjectionTestExecutionListener.java:118) ~[sp 
ring-test-4.2.7.RELEASE.jar:4.2.7.RELEASE] 
    at org.springframework.test.context.support.DependencyInjectionTestExecutionLis 
tener.prepareTestInstance(DependencyInjectionTestExecutionListener.java:83) ~[sp 
ring-test-4.2.7.RELEASE.jar:4.2.7.RELEASE] 
    at org.springframework.test.context.TestContextManager.prepareTestInstance(Test 
ContextManager.java:228) ~[spring-test-4.2.7.RELEASE.jar:4.2.7.RELEASE] 
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(S 
pringJUnit4ClassRunner.java:230) [spring-test-4.2.7.RELEASE.jar:4.2.7.RELEASE] 
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflect 
iveCall(SpringJUnit4ClassRunner.java:289) [spring-test-4.2.7.RELEASE.jar:4.2.7.R 
ELEASE] 
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.j 
ava:12) [junit-4.12.jar:4.12] 
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(
SpringJUnit4ClassRunner.java:291) [spring-test-4.2.7.RELEASE.jar:4.2.7.RELEASE] 
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(Spr 
ingJUnit4ClassRunner.java:249) [spring-test-4.2.7.RELEASE.jar:4.2.7.RELEASE] 
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(Spr 
ingJUnit4ClassRunner.java:89) [spring-test-4.2.7.RELEASE.jar:4.2.7.RELEASE] 
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) [junit-4.12.jar: 
4.12] 
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) [junit-4.12. 
jar:4.12] 
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) [junit-4.1 
2.jar:4.12] 
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) [junit-4.12. 
jar:4.12] 
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) [junit-4.12 
.jar:4.12] 
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbac 
ks.evaluate(RunBeforeTestClassCallbacks.java:61) [spring-test-4.2.7.RELEASE.jar: 
4.2.7.RELEASE] 
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallback 
s.evaluate(RunAfterTestClassCallbacks.java:70) [spring-test-4.2.7.RELEASE.jar:4. 
2.7.RELEASE] 
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363) [junit-4.12.jar:4. 
12] 
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJU 
nit4ClassRunner.java:193) [spring-test-4.2.7.RELEASE.jar:4.2.7.RELEASE] 
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestRef 
erence.java:86) [.cp/:na] 
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:3 
8) [.cp/:na] 
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRu 
nner.java:459) [.cp/:na] 
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRu 
nner.java:675) [.cp/:na] 
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner. 
java:382) [.cp/:na] 
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner 
.java:192) [.cp/:na] 
Caused by: org.springframework.beans.factory.BeanCreationException: Could not au 
towire field: org.cl.service.location.CatalogPageServiceImpl org.cl.service.Cata 
logPageServiceImplTest.catalogPageServiceImpl; nested exception is org.springfra 
mework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [ 
org.cl.service.location.CatalogPageServiceImpl] found for dependency: expected a 
t least 1 bean which qualifies as autowire candidate for this dependency. Depend 
ency annotations: {@org.springframework.beans.factory.annotation.Autowired(requi 
red=true)} 
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProc 
essor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:573 
) ~[spring-beans-4.2.7.RELEASE.jar:4.2.7.RELEASE] 
    at org.springframework.beans.factory.annotation.InjectionMetadata.inject(Inject 
ionMetadata.java:88) ~[spring-beans-4.2.7.RELEASE.jar:4.2.7.RELEASE] 
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProc 
essor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:331) ~ 
[spring-beans-4.2.7.RELEASE.jar:4.2.7.RELEASE] 
    ... 26 common frames omitted 
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No q 
ualifying bean of type [org.cl.service.location.CatalogPageServiceImpl] found fo 
r dependency: expected at least 1 bean which qualifies as autowire candidate for 
this dependency. Dependency annotations: {@org.springframework.beans.factory.an 
notation.Autowired(required=true)} 
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNo 
SuchBeanDefinitionException(DefaultListableBeanFactory.java:1373) ~[spring-beans 
-4.2.7.RELEASE.jar:4.2.7.RELEASE] 
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResol 
veDependency(DefaultListableBeanFactory.java:1119) ~[spring-beans-4.2.7.RELEASE. 
jar:4.2.7.RELEASE] 
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolve 
Dependency(DefaultListableBeanFactory.java:1014) ~[spring-beans-4.2.7.RELEASE.ja 
r:4.2.7.RELEASE] 
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProc 
essor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:545 
) ~[spring-beans-4.2.7.RELEASE.jar:4.2.7.RELEASE] 
    ... 28 common frames omitted 
+0

顯示你的web.xml。 –

+0

我沒有web.xml,因爲根本不使用web(servlet)服務器。我的test.properties包含:spring.main.web-environment = false – Pavlo

+0

你解決了你的問題嗎? –

回答

1

@ComponentScan註釋上CLApplicationbasePackages屬性是錯誤的:

@ComponentScan(basePackages = {"org.cl, org.cl.service.location "}) 

這應該是:

@ComponentScan(basePackages = {"org.cl", "org.cl.service.location"}) 

兩個包應被指定爲兩個分開的字符串,而不是作爲一個字符串與由逗號分隔包名。

你也可以只指定org.cl,因爲春天還會看在所有子包,所以org.cl.service.location也將被掃描,如果你指定org.cl

@ComponentScan(basePackages = "org.cl") 

事實上,因爲它是一個春天啓動的應用程序,你可以完全刪除@ComponentScan註釋,因爲@SpringBootApplication註釋已經自動包含它(它將掃描包和CLApplication所屬的所有子包)。

+0

是的,謝謝我改變了它,儘管當@Async註解存在時應用程序仍然崩潰在DI上 – Pavlo