73

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)}

naXa stands with Ukraine
  • 35,493
  • 19
  • 190
  • 259
Premraj
  • 7,802
  • 8
  • 45
  • 66
  • 5
    bonus question: what s the purpose of self injection here? – Orkun Mar 05 '18 at 13:11
  • 3
    @OrkunOzen Simple use case: you want `@Transactional` annotations to work properly on invocations of another method of the same class from within. Calling `this.myMethod()` would ignore the transaction, but `self.myMethod()` should have the transaction created. See [Section 5.1. Potential Pitfalls - Transactions and Proxies](https://www.baeldung.com/transaction-configuration-with-jpa-and-spring#1-transactions-and-proxies). – Snackoverflow Apr 16 '21 at 08:53
  • @Snackoverflow, another bonus question : How does **this.myMethod()** ignore the transaction ? – GB11 May 27 '21 at 21:41
  • 3
    @GB11 AFAIK when the method is annotated with `@Transactional` and the class is `@Autowired` as a dependency, then Spring actually injects a Proxy instance which wraps your class instance, and in the proxy implementation the method is also wrapped by a proxy method with transaction logic. If you use `this.myMethod()` directly, you are doing it from within *your class instance* code, referencing *your class instance method* directory, and not calling the injected proxy with the transaction logic. https://spring.io/blog/2012/05/23/transactions-caching-and-aop-understanding-proxy-usage-in-spring – Snackoverflow May 28 '21 at 06:59
  • 1
    @GB11 Here is another source; [Spring documentation: 8.6 Proxying mechanisms](https://docs.spring.io/spring-framework/docs/3.0.0.M3/reference/html/ch08s06.html) (it is a short read) – Snackoverflow May 28 '21 at 07:09

8 Answers8

66

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

Sam Brannen
  • 29,611
  • 5
  • 104
  • 136
  • 1
    This explains why @Autowired does not work but doesn't explain how and why @Resource works. Anyone? – Andy Dufresne May 21 '11 at 07:40
  • 2
    @Amit - this does explain!! they are only excluding autowired candidates and not checking for other ones like @Resource and etc. – Premraj May 21 '11 at 14:25
  • 4
    I think something like this can be very usefull on certain occasions, e.g. there are times when you need to have a method been wraped by a transactional proxy (espesially with requires_new) which may be self-invoked. Having to "separate" such functionality often leads to antipatterns and poor design in genertal – nvrs Feb 22 '13 at 16:36
  • 7
    Agree with nvrs, same-class `@Transactional` proxying is what led me here. "Use AspectJ instead of CGLib" isn't a useful answer when you have a mature codebase. Using `@Resource` will probably solve my problem but `@Autowired` would be preferable as that is our standard. – Noah Yetter May 10 '13 at 20:52
  • Just for anyone who's waiting for Spring 4.3. I'm now using it. But self-reference only get more exception description, and is still not allowed, at least by default set-up. – Xiangyu Jun 26 '16 at 09:25
  • @Xiangyu, that's not true. Self injection via `@Autowired` works fine with Spring Framework 4.3 as long as there is a single candidate bean of the autowired type. And... if there is more than one such candidate, `@Qualifier` can be used to disambiguate. I just verified this. – Sam Brannen Jun 26 '16 at 12:19
  • @SamBrannen In my case there is bean inheritance, so I believe it is possible that self injection is rejected because of more than one candidate. – Xiangyu Jul 04 '16 at 16:54
  • 2
    @Xiangyu, Juergen Hoeller just documented this three days ago: https://github.com/spring-projects/spring-framework/commit/c6752e6023c4948c0f2c007c166ab8ecf677d7b6 – Sam Brannen Jul 05 '16 at 18:06
  • 7
    Remember to add `@Lazy` – OrangeDog Mar 02 '17 at 17:37
43

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.

naXa stands with Ukraine
  • 35,493
  • 19
  • 190
  • 259
sinuhepop
  • 20,010
  • 17
  • 72
  • 107
  • 9
    Cool, injecting context into your application bean. It's best practice ever! – Andrii Andriichuk Nov 03 '15 at 12:52
  • 6
    @avrilfanomar: Well, if a class needs to be conscious that there is a proxy of itself you are breaking DI abstraction anyway, so I think that accessing your container is not much worse. – sinuhepop Nov 03 '15 at 14:06
  • 1
    Why does it break DI? I see no evil in injecting self e.g. for using transactional method as it should be. – Andrii Andriichuk Nov 04 '15 at 07:01
  • I tried same thing above with more fields in UserService class. but when I do self.morefield.xxx. it throws NPE – ssbh Nov 26 '20 at 00:29
  • Not sure if sarcasm or not, @AndriiAndriichuk. Users stumbling upon this question (like, me) usually aren't too well-versed in best practices. – T Tse Jul 28 '21 at 18:15
  • 2
    @TTse Injecting application context into service bean (which is not related to spring customization) is a wrong approach. – Andrii Andriichuk Jul 29 '21 at 07:28
  • @sinuhepop Damn, I have the same setup Class implementing Interface), but no matter what I do, I get a NullPointerException when I try to call a method on the "self" variable – ennth Nov 13 '21 at 03:44
3

Get AOP proxy from the object itself question suggests alternative hacky approach with AopContext.currentProxy() that may be suitable for special cases.

Community
  • 1
  • 1
Vadzim
  • 24,954
  • 11
  • 143
  • 151
1

Given above code I don't see a cyclic dependency. You injecting some instance of Service into UserService. The implementation of the injected Service does not necessarily need to be another UserService so there is no cyclic dependency.

I do not see why you would inject a UserService into UserService but I'm hoping this is a theoretic try out or such.

Taryn
  • 242,637
  • 56
  • 362
  • 405
Stijn Geukens
  • 15,454
  • 8
  • 66
  • 101
  • I have only One implementation of Service and thats UserService :).. Same code fails with Spring @Autowired but works with @Resource – Premraj Mar 01 '11 at 09:43
  • 5
    Wiring a bean into itself could be useful if the service uses a spring cache proxy around it and you want the internal calls to benefit from this cache. – Shamu Feb 10 '12 at 15:53
1

By the way, the more elegant solution to the self-invocation problem is to use AspectJ Load-Time Weaving for your transactional proxies (or whatever AOP-introduced proxy you're using).

For example, with annotation-driven transaction management, you can use the "aspectj" mode as follows:

<tx:annotation-driven mode="aspectj" />

Note that the default mode is "proxy" (i.e., JDK dynamic proxies).

Regards,

Sam

Sam Brannen
  • 29,611
  • 5
  • 104
  • 136
  • Can aspectj work with JDK proxies? I guess it needs CGLib right? – Premraj Mar 11 '11 at 07:12
  • Well aspectj deals with self-invocation but creates other problems, also last time i checked it is not recommended SpringSource docs. – nvrs Feb 22 '13 at 16:39
1

Just another aproach:

@EnableAsync
@SpringBootApplication
public class Application {

    @Autowired
    private AccountStatusService accountStatusService;

    @PostConstruct
    private void init() {
        accountStatusService.setSelf(accountStatusService);
    }
}

@Service
public class AccountStatusService {
    private AccountStatusService self;

    public void setSelf(AccountStatusService self) {
        this.self = self;
    }
}

with this your service will be in proxy. I did this to work with async methods inside itself.

I have tryied @sinuhepop solution:

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

It did a injection but the service wasn't inside proxy and my methods wasn't running on a new thread. With that aproach it works as i would like.

Gilson
  • 478
  • 7
  • 14
  • tried everything , could not get this to work. Not sure if its because I have a concrete class implementing an Interface in another module (multi-module maven project) and I also have the data types for some of the Methods in my class generated by the SwaggerCodeGenPlugin – ennth Nov 13 '21 at 04:31
  • Without known what you build is hard to guess what is happening on your side. Also, this code above, from 3 years ago, is something that I would avoid today. If you seems to needs self injection, probably you have an architect problem. You can separate things where each concept belongs to its own class and then you will no need to self inject anymore. – Gilson Nov 14 '21 at 14:51
0

It looks like spring creates and configures an object and then places it in the bean look up context. But, in the case of Java, I think it creates the object and ties it to the name and the during configuration when the object is looked up by the name it is found in the context.

Krishna
  • 1,871
  • 14
  • 26
0

This is my solution for small to medium sized projects. No AspectJ or application context magic, it works with singletons and constructor injection and is very easy to test.

@Service
@Scope(proxyMode = ScopedProxyMode.TARGET_CLASS)
class PersonDao {

    private final PersonDao _personDao;

    @Autowired
    public PersonDao(PersonDao personDao) {
        _personDao = personDao;
    }
}
Mario Eis
  • 2,724
  • 31
  • 32
  • For some reason this is not working for me. Even setting a special flag not working. What is working though is to use field injection instead of constructor injection and mark self injected bean with both `@Autowired` and `@Lazy` annotations – chill appreciator May 12 '23 at 11:22