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

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

Related

Spring different beans for different consumers

Suppose I have several components that depend on one service:
public interface MyService { ... }
// in package1
#Component
public class Package1Component1 {
#Autowired
private final MyService myService;
}
public class Package1Component2 {
#Autowired
private final MyService myService;
}
// in package 2
public class Package2Component1 {
#Autowired
private final MyService myService;
}
public class Package2Component2 {
#Autowired
private final MyService myService;
}
And I have two implementations of MyService:
#Service
public class MyServiceImpl1 implements MyService { ... }
#Service
public class MyServiceImpl2 implements MyService { ... }
And I want MyServiceImpl2 to be injected into all components in package2 and MyServiceImpl1 everywhere else
I don't want to use #Qualifier to resolve ambiguity as it will require to always specify it when you need to inject MyService and to change a lot of files when I need to switch to single implementation everywhere (MyServiceImpl2 is temporary implementation that should be used only in specific scope).
Is there any way to specify bean for scope (java package?), like in Angular I can override module providers (AuthService in this case):
#NgModule({
declarations: [LoginComponent, UserInfoComponent],
providers: [
{
provide: AuthService,
useClass: FacebookAuthService,
},
],
})
export class AuthModule {}
You can introduce your meta-annotation annotated with #Qualifier and use it.
Once you are ready to change, just change Qualifier on your meta annotation.
I think it's not really correct to co-relate Angular specificities with Spring, as they are simply two radically different infrastructures, in all aspects.
Why don't you want to use #Qualifier? for what reason? because, the problem you describe is exactly why people came up with #Qualifier implementation.
I don't want to use #Qualifier to resolve ambiguity as it will require to always specify it when you need to inject MyService and to change a lot of files when I need to switch to single implementation everywhere.
Not really. You can provide ID for your bean definition, and disregarding of what implementation you'll use later, same bean, with that same ID, will be injected wherever you'll qualify it to be injected. You will only swap the implementation class.
Also, package in Java, is not a scope for Beans. Package is facility for grouping a logically similar classes, and it can be considered as a scope, but for class and its members' accessibility/visibility, not for the beans.
Bean scopes have a different semantics, and you can read about them here.
The is another way to specify, that the bean should qualify as a candidate, if there are more than one implementations of a type you're injecting. It's #Primary; however, this #Primary will always override any other candidates, while with #Qualifier you can leverage more fine-grained control on what to inject where.

Spring How to autowire a component without using #Component or other derivatives

I would like to autowire a component (still using the #Autowired annotation), but not require it to have the #Component (or other similar annotations) on it. How would I do this?
public class A {
#Autowired
private class B b;
}
#Component
public class B {
}
This would be convenient in order to allow autowiring of class A without requiring the creation of A, unless we needed it (in otherwise on the fly by reflection using the class name).
Injection and autowiring do not require #Component. They require beans. #Component states that the annotated type should have a bean generated for it. You can define beans in other ways: with a <bean> declaration in an XML context configuration, with a #Bean method in a #Configuration class, etc.
Your last sentence doesn't make much sense. You can't process injection targets in a bean without creating a bean. You also can't inject a bean without creating it. (Applied to scopes, bean may refer to the target source/proxy and not the actual instance.) Perhaps you want #Lazy.
I don't sure, If I correctly understood to your question. But if you want inject bean B without marking bean A via some annotation, or xml definition, you can use SpringBeanAutowiringSupport
public class A {
#Autowired
private class B b;
public A{
SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
}
}

Placement of #Autowired annotation

I've seen the #Autowired annotation placed just before the constructor of a POJO used as controller.
#Controller
public class LoginController{
private UsuarioService usuarioService;
#Autowired
public void LoginController(UsuarioService usuarioService){
this.usuarioService = usuarioService;
}
// More code
}
This constructor takes as argument the reference to the object we want Spring to inject.However if I place this annotation just before the property declaration the application works just the same.
#Controller
public class LoginController{
#Autowired
private UsuarioService usuarioService;
// More code
}
My question is what is the difference between this two approaches in terms of pros and cons.
My advice to you would be to never use #Autowired on fields (except in Spring #Configuration classes).
The reason is very simple: TESTING!!!!
When you use #Autowired on fields of a class, then that class becomes harder to unit test because you cannot easily use your own (possible mocked) dependencies for the class under test.
When you use constructor injection then is becomes immediately evident what the dependencies of the class are, and creating that class becomes straight forward (simple constructor call).
Some points that need to made:
1) Some might argue that even when #Autowired is used the class can still be unit tested with the use of Mockito's #InjectMocks, or Spring's ReflectionTestUtils.setField, but my opinion is that the creation of a unit under test should be as dead simple as possible.
2) Another point that could be mentioned is that there might be many arguments in the constructor making the manual invocation of the constructor (either in the test or elsewhere) difficult. This however is not a problem regarding the creation of the class, but a problem in the design. When a class has to many dependencies, in most cases it is trying to do too much and needs to broken into smaller classes with fewer dependencies.
#Autowired annotation on setter methods is to get rid of the element in XML configuration file. When Spring finds an #Autowired annotation used with setter methods, it tries to perform byType autowiring on the method
#Autowired annotation on properties is to get rid of the setter methods. When you will pass values of autowired properties using Spring will automatically assign those properties with the passed values or references.
Here is an example of both the usage:
http://www.tutorialspoint.com/spring/spring_autowired_annotation.htm
This Springsource blog post mentions that constructor injection makes it easy to validate required dependencies, if used in combination with contructors assertions that are good practice anyway and would also work if the class is instantiated outside Spring with the new operator:
#Controller
public class LoginController{
private UsuarioService usuarioService;
#Autowired
public void LoginController(UsuarioService usuarioService){
if (usuarioService == null) {
throw new IllegalArgumentException("usuarioService cannot be null.");
}
this.usuarioService = usuarioService;
}
}
This type of assertions are general best practice that is advised to do independently of the class being a Spring bean or not.
For setter or property injection there is also the #Required annotation for validating missing dependencies or #Autowired(required = true). According to the blog post, constructor injection provides this advantage, but for historical reasons setter injection is more frequently used in Spring.

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

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

Categories