Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Self injection with Spring

I tried the following code with Spring 3.x which failed with BeanNotFoundException and it should according to the answers of a question which I asked before - Can I inject same class using Spring?

@Service
public class UserService implements Service{
    @Autowired
    private Service self;
}

Since I was trying this with Java 6, I found the following code works fine:

@Service(value = "someService")
public class UserService implements Service{
    @Resource(name = "someService")
    private Service self;
}

but I don't understand how it resolves the cyclic dependency.

EDIT:
Here's the error message. The OP mentioned it in a comment on one of the answers:

Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [com.spring.service.Service] 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)}

like image 448
Premraj Avatar asked Mar 01 '11 09:03

Premraj


People also ask

Which type of injection is better in spring?

Constructor Injection —enforcing immutability. This is the most straightforward and recommended way of dependency injection. A dependent class has a constructor, where all dependencies are set, they will be provided by Spring container according to XML, Java or annotation based configurations.

How many types of injections are there in spring?

Types of Spring Dependency Injection: There are two types of Spring Dependency Injection. They are: Setter Dependency Injection (SDI): This is the simpler of the two DI methods. In this, the DI will be injected with the help of setter and/or getter methods.


2 Answers

Update: February 2016

Self autowiring will be officially supported in Spring Framework 4.3. The implementation can be seen in this GitHub commit.


The definitive reason that you cannot autowire yourself is that the implementation of Spring's DefaultListableBeanFactory.findAutowireCandidates(String, Class, DependencyDescriptor) method explicitly excludes the possibility. This is visible in the following code excerpt from this method:

for (String candidateName : candidateNames) {
    if (!candidateName.equals(beanName) && isAutowireCandidate(candidateName, descriptor)) {
        result.put(candidateName, getBean(candidateName));
    }
}

FYI: the name of the bean (i.e., the bean that's trying to autowire itself) is beanName. That bean is in fact an autowire candidate, but the above if-condition returns false (since candidateName in fact equals the beanName). Thus you simply cannot autowire a bean with itself (at least not as of Spring 3.1 M1).

Now as for whether or not this is intended behavior semantically speaking, that's another question. ;)

I'll ask Juergen and see what he has to say.

Regards,

Sam (Core Spring Committer)

p.s. I've opened a Spring JIRA issue to consider supporting self-autowiring by type using @Autowired. Feel free to watch or vote for this issue here: https://jira.springsource.org/browse/SPR-8450

like image 69
Sam Brannen Avatar answered Oct 11 '22 11:10

Sam Brannen


This code works too:

@Service
public class UserService implements Service {

    @Autowired
    private ApplicationContext applicationContext;

    private Service self;

    @PostConstruct
    private void init() {
        self = applicationContext.getBean(UserService.class);
    }
}

I don't know why, but it seems that Spring can get the bean from ApplicationContext if is created, but not initialized. @Autowired works before initialization and it cannot find the same bean. So, @Resource maybe works after @Autowired and before @PostConstruct.

But I don't know, just speculating. Anyway, good question.

like image 41
sinuhepop Avatar answered Oct 11 '22 12:10

sinuhepop