Reputation: 2159
I have two classes Uploader and UploadTask. Using Spring 4.
@Service
public class Uploader{
@Autowired
private UploadTask task;
}
@Component
public class UploadTask implements Runnable{
@Async
public void soso(){
}
public void run(){
}
}
On application startup I get the following exception:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'uploader': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.xx.uploading.UploadTask com.xx.uploading.Uploader.task; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.xx.uploading.UploadTask] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true), @org.springframework.beans.factory.annotation.Qualifier(value=uploadTask)}
I think this may be because UploadTask is a Runnable. When I removed the @Async annotation then it does not throw any Exception. Is there an explanation?
Update: When I saw the logs I found that the UploadTask class bean is being created alright. It is not being found during autowiring.
Upvotes: 5
Views: 3734
Reputation: 510
I have run this code successfully. please see my code below.
@Service
public class Uploader{
@Autowired
private UploadTask task;
public void display(){
task.run();
task.soso();
}
}
@Component
public class UploadTask implements Runnable{
@Async
public void soso(){
System.out.println("Upload task running---");
}
public void run(){
System.out.println("Running the class UploadTask---------");
}
}
Spring.xml
<mvc:annotation-driven/>
<context:component-scan base-package="com.exp" />
Below is my test class
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"classpath*:/META-INF/spring/spring.xml"})
public class TestScope {
@Autowired
Uploader uploader = null;
@Test
public void testScope()
{
uploader.display();
}
}
Below is my Pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>SpringAsync-Exmp</groupId>
<artifactId>SpringAsync-Exmp</artifactId>
<version>0.0.1-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.3.2.RELEASE</version>
</parent>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.9</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
When i run the test class , it successfully print the sysout in UploadTask.
UPDATE I have modified the coded to run with @EnableAsync. Please see below the modified code.
Uploader class
@EnableAsync
@Service
public class Uploader{
@Autowired
private UploadTask uploadTask;
public UploadTask getUploadTask() {
return uploadTask;
}
public void setUploadTask(UploadTask uploadTask) {
this.uploadTask = uploadTask;
}
public void display(){
uploadTask.run();
uploadTask.soso();
}
}
UploadTask interface
@Component
public interface UploadTask extends Runnable{
@Async
public void soso();
public void run();
}
UploadTaskImpl class
public class UploadTaskImpl implements UploadTask{
public void soso()
{
System.out.println("Inside the class----");
}
public void run()
{
System.out.println("Inside the class--run--");
}
}
All others are same. This time I have created UploaderTask as an interface and write a new class to implement that. This solves the problem.
I think @EnableAsync is converting any component using @Async to proxy implementing same interfaces used by this component class, so when make autowire with concrete class will face type conflict between this concrete class and proxy.
Upvotes: 1
Reputation: 84
configure your service classes in the context.xml file.
like the below codes.
<bean id="Uploader" class="packageName.Uploader">
<property name="task" ref="task"/>
</bean>
<bean id="task" class="packageName.UploadTask ">
<property name="xxx" ref="xxx"/>
</bean>
change xxx with your datasource name.
Upvotes: -1
Reputation: 12582
Use @EnableAsync at class level.
@Component
@EnableAsync
public class UploadTask implements Runnable{
@Async
public void soso(){
}
public void run(){
}
}
Upvotes: 0
Reputation: 353
Have a public setter for private UploadTask task; and test.
Upvotes: -1