Self injection with Spring - java

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

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

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.

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

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.

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

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.

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.

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

Related

Does Spring's #RequestScope automatically handle proxying when injected in singleton beans?

I'm using a Java8/Spring Boot 2 application. I want to inject a request-scoped bean into a singleton bean. The official documentation highlights that either a proxy or ObjectFactory/Provider should be used to ensure always getting the correctly scoped bean at runtime in the singleton bean. However, the #RequestScope annotation seems to "automatically" set some kind of proxy, as explained in the answer to this question.
I'm now wondering if the following three implementations are in fact identical and which one is preferred?
Approach 1: explicitly using objectFactory<>
#Component
#RequestScope
public class MyRequestScopedBean{...}
#Component
public class MySingletonBean{
#Autowired
private ObjectFactory<MyRequestScopedBean> myRequestScopedBean
}
Approach 2: inject normally, assuming the request scoped bean is proxied automatically?
#Component
#RequestScope
public class MyRequestScopedBean{...}
#Component
public class MySingletonBean{
#Autowired
private MyRequestScopedBean myRequestScopedBean
}
Approach 3: using #Configuration and #Bean because I don't know the difference and I'm worried they behave differently.
#Comfiguration
public class myBeanConfig{
#Bean
#RequestScope
public MyRequestScopedBean getRequestScopedBean(){return new MyRequestScopedBean();}
}
#Component
public class MySingletonBean{
#Autowired
private MyRequestScopedBean myRequestScopedBean
}
I would prefer approach 2, because it is concise and handles the scoping/proxying automatically.
Would the answer change if my #Autowired bean is declared as a final field? I'm worried making it final somehow prevents the proxy from fetching the correctly fetching the new bean every request.
I have been using the 2nd approach in my projects and I have zero issues so far. The documentation does not mention it's a MUST to use ObjectFactory too. Don't think too much. If you run into any problems, you will see the error very clearly in the console. There's no reason to be afraid until you have an actual issue to deal with.
Yes, with #RequestScope the proxy is already default activated, the effect exactly equal to #Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyModel = ScopedProxyMode.TARGET_CLASS)

The bean could not be injected as a 'Type' because it is a JDK dynamic proxy that implements: reactor.fn.Consumer

My Spring 4 application, which uses Reactor 2, fails to start with:
***************************
APPLICATION FAILED TO START
***************************
Description:
The bean 'orderHandlerConsumer' could not be injected as a 'fm.data.repository.OrderHandlerConsumer' because it is a JDK dynamic proxy that implements:
reactor.fn.Consumer
Action:
Consider injecting the bean as one of its interfaces or forcing the use of CGLib-based proxies by setting proxyTargetClass=true on #EnableAsync and/or #EnableCaching.
The OrderHandlerConsumer is really simple:
#Service
#Order(Ordered.HIGHEST_PRECEDENCE)
public class OrderHandlerConsumer implements Consumer<Event<OrderEnvelope>> {
#Override
public void accept(Event<OrderEnvelope> event) {
event.getData().getLatch().countDown();
}
}
Any ideas what might be going awry?
In your application class file where you define it as Spring application, add underneath it.
#SpringBootApplication
#EnableCaching(proxyTargetClass = true)
While the accepted answer will solve this issue, I think it will be more appropriate for me to explain why appling proxyTargetClass = true will fix this.
First of all, Spring, as a framework, utilizes proxing in order to supply the bean with some extended functionality, such as declaritive transactions via #Transactional, or caching by the means of #Cacheable and e.t.c. There are, in general, 2 ways(*) Spring can create proxy on top of your bean:
Jdk dynamic proxing
CGLib proxing
Offical documentation on this, in case you are interested.
Spring can create jdk dynamic proxy of the bean (in case proxing is required for this bean of course) if original class of the bean implements at least one interface. So spring basically create another implementation of this interface at runtime with some additional logic on top of original class.
What is the problem: if the bean is proxied by the means of jdk dynamic proxing , then you cannot inject this bean via its original class. So something like this:
#SpringBootApplication
#EnableTransactionManagement(proxyTargetClass = false)
public class StackoverflowApplication {
#Autowired private SomeService service;
public static void main(String[] args) {
SpringApplication.run(StackoverflowApplication.class, args);
}
}
#Service
class SomeService implements SomeInterface {
#Override
#Transactional
public void handle() { }
}
interface SomeInterface {
void handle();
}
wont work. Why? Well, becuase #Transactional tells Spring that it needs to create proxy of SomeService at runtime, and within #EnableTransactionManagement I specifically asked Spring to make it by the means of jdk dynamic proxy - spring will succeed, since jdk dynamic proxy can be created, but the problem is at runtime there is not bean of type SomeService, there is only a bean of type SomeInterface (by the way, if you inject service here not by the class, but by the interface - it will work, I assume you understand the reason by reading explaination above).
Solution: by applying #EnableTransactionManagement(proxyTargetClass = true) (notice true value here) you force spring to create CGlib proxy (this rule is applicable only for beans that utilize declarative transaction management, i.e. via annotations). In case of CgLib proxing, Spring will try to extend the original class, and add additional functionality at runtime in the generated child class. And in this case injection by class will work - because the bean extends class SomeService, so
#Autowired
private SomeService someService;
will work perfectly fine. But, in general, if possible, inject bean by interface, not by class. In this case both Cglib and jdk dynamic proxy will work. So, be aware of proxing mechanisms spring can use. Hope it helped, have a nice day.
You can assign a bean name to your OrderHandlerConsumer class so that Autowire resolution will be easier, Moreover, Instead of Autowiring with the concrete class, try to auto-wire with the interface. So that you can change #Service annotation to,
#Service(value="orderHandlerConsumer")
and try to Autowire with the interface type,
#Autowire
reactor.fn.Consumer orderHandlerConsumer;
Please try autowiring as below
class Test{
#Autowired
private Consumer orderHandlerConsumer;
}
If the target object to be proxied implements at least one interface
then a JDK dynamic proxy will be used. All of the interfaces
implemented by the target type will be proxied. If the target object
does not implement any interfaces then a CGLIB proxy will be created.
https://docs.spring.io/spring-framework/docs/3.0.0.M3/reference/html/ch08s06.html
You can call it two ways.
1st way is without mentioning the proxy [with default proxy], you can Autowire it by the interface like below.
#Autowired
private Consumer orderHandlerConsumer;
Spring AOP will create an instance for OrderHandlerConsumer.
2nd way is, mention the proxy in the bean as ScopedProxyMode.TARGET_CLASS.
then you can Autowire an instance without the interface [based on the class].
#Service
#Order(Ordered.HIGHEST_PRECEDENCE)
#Scope(value = ConfigurableBeanFactory.SCOPE_SINGLETON, proxyMode = ScopedProxyMode.TARGET_CLASS)
public class OrderHandlerConsumer implements Consumer<Event<OrderEnvelope>> {
#Override
public void accept(Event<OrderEnvelope> event) {
event.getData().getLatch().countDown();
}
}
and Autowire by the class like below.
#Autowired
private OrderHandlerConsumer orderHandlerConsumer;

Preferable way to use a bean in self-initialized objects in Spring

I've been working around Java and Spring(Batch, Boot), and have a question.
I created beans by Spring for generating a service class. I bind it with #Autowired annotation like this:
#Component
public class MyTaskRunner {
#Autowired
private MyService myService;
public void run() {
List<SomeObject> someObjects = myService.getSomeObjects();
// Do some tasks
}
}
Here, I also want to use such a bean in SomeObject which are deserialized from a database(meaning, not from Spring). I've looked for solutions here and am going to try them, but most of them seem elaborate, just for injecting a bean.
My question is: Is it so unusual usage of bean that it needs some work?
Thank you in advance! Any comments would be appreciated.

How does Spring 3+ autowire beans, which use each other?

For example, I have
#Service
public class UserSerice {
#Autowired
private HouseService houseService;
}
and
#Service
public class HouseService {
#Autowired
private UserSerice userService;
}
How will Spring autowire this?
And is this a good practice to configure beans this way?
Circular dependencies (spring-framework-reference):
For example: Class A requires an instance of class B through
constructor injection, and class B requires an instance of class A
through constructor injection...throws a
BeanCurrentlyInCreationException.
it is not recommended...
One possible solution is to edit the source code of some classes to be
configured by setters rather than constructors...
PLUS:
I debugged the circular dependencies in setter way. The sequence seems that:
-> Start to create bean A
-> Start to create bean B
-> Inject A to B, although A is not created fully from perspective of Spring lifecycle
-> Bean B creation finish
-> Inject bean B to A
-> Bean A created
Since it's not a constructor injection, spring can safely instantiate both objects and then satisfy their dependencies. Architecture-wise such case is so called 'code smell'. It's the sign that something is wrong in the composition. Maybe you need to move logic, maybe you need to introduce third class, it depends.
Google for these terms
Flyweight pattern
Circular dependency in java
Just like 2 java objects can refer each other , it is perfectly valid to have such configuration.
Keep calm and use #Lazy
you can break the circular dependency using the #Lazy annotation()
#Service
public class UserSerice {
#Autowired
#Lazy
private HouseService houseService;
}
you can use the HouseService as it is (no change :) )
#Service
public class HouseService {
#Autowired
private UserSerice userService;
}
further solutions : https://www.baeldung.com/circular-dependencies-in-spring#2-use-lazy

Can #Autowire #Service beans but not members of a class instantiated with "new" keyword - even with context scanning configured

I have an app that's been working well with #Autowired #Service beans.
Now I'm adding a Validator class which is instantiated in the Controller:
BlueValidator validator = new BlueValidator(colors);
validator.validate(colorBlend, bindResult);
In the BlueValidator class I'm trying to #Autowire the blendService which is working as an #Autowired field elsewhere in the app:
public class BlueValidator implements Validator {
#Autowired
private BlendService blendService;
private Colors colors;
But for some reason after instantiating the BlueValidator, I keep getting NullPointerExceptions for the blendService.
Of course I've added the necessary context scanning:
<context:component-scan
base-package="com.myapp.controllers, com.myapp.services, com.myapp.validators" />
I also tried adding the#Autowired annotation to the constructor but that didn't help:
#Autowired
public BlueValidator(Colors colors) {
this.colors = colors;
}
Should I just pass the blendService to the BlueValidator and forget about the Autowiring or is there something obvious missing here?
If you just instantiate an object with new, Spring is not involved, so the autowiring won't kick in. Component scanning looks at classes and creates objects from them - it doesn't look at objects you create yourself.
This can be made to work, using Spring's AspectJ support, but it takes some effort.
Otherwise, you need to let Spring instantiate your objects if you wan autowiring to work.
Should I just pass the blendService to the BlueValidator and forget about the Autowiring
In your situation, I'd say yes, this is the least effort solution.
When you instantiate objects spring cannot do anything for them, so it does not get the dependencies injected (article).
In your case, you have a couple of options:
pass dependencies to the validator from the controller (where you can inject them)
make the validator a spring bean and inject it, instead of instantiating it
use #Configurable, which, via AspectJ, enables spring injection even in objects created with new
#Autowired is being used by Spring's ApplicationContext to populate those fields on creation. Since the ApplicationContext is not the one creating these beans (you are because of the keyword 'new'), they are not being autowired. You need to pass it in yourself if you are creating it.
Don't create validator manually -- allow to Spring do this work for you:
#Controller
class Controller {
#Autowired
BlueValidator validator;
void doSomething() {
...
validator.validate(colorBlend, bindResult);
...
}
}
Also pay attention that adding package com.myapp.validators to context:scan-packages not enough, you also should annotate your validator class with #Component annotation:
#Component
public class BlueValidator implements Validator {
#Autowired
private BlendService blendService;
(BTW this solution works in my project.)

Categories