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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With