Let's look at the following example
#Service
class AServiceImpl{
#Autowired
BService bservice
}
#Service
class BServiceImpl{
#Autowired
AService aservice
}
I know the Spring uses three-level cache to solve Circular Dependency issues. When A is being initialized and B is being injected, Spring begins to initialize B, which needs bean of A to be injected. But A is not fully initialized yet, so B just get a reference to a non-fully initialized bean of A from cache.
But in Spring, if AService is with a #Transactional annotation, Spring will construct an proxy Bean for A using BeanPostProcessor, and this process happens after #Autowired. This means, although B have a a reference to a non-fully initialized bean of A from cache, the reference is not pointing to the proxy bean, which doesn't seem to be correct. Is there anything wrong with my reasoning?
There is a saying the #Lazy could solve spring Circular Dependencies problem. According to my understanding, there are two types of usage of this annotation.
#Lazy
#Service
class AServiceImpl{
#Autowired
BService bservice
}
or
#Service
class BServiceImpl{
#Lazy
#Autowired
AService aservice
}
Some explanation of this annotation says that the annotated bean will be initialized if it is referenced by another bean. But I think whether with it or without it, "the annotated bean will always be initialized if it is referenced by another bean", so how can it solve the circular dependency problem?
Some other explanation says that the annotated bean will be initialized if its methods are invoked, this sound reasonable, but I tried and it seems to me that even if none of methods in AService is called, B can still hold the reference to the final proxy bean of AService, what is wrong with my try?
Another way is inside a constructor
#Autowired
public AService(#Lazy BService bservice) {
this.bservice = bservice;
}
instead of fully initializing the bean, it will create a proxy to inject it into the other bean. The injected bean will only be fully created when it’s first needed.
Related
Please any one tell me the difference between
#Autowired
CustomerService cService;
And
CustomerService cService=new CustomerService();
And
private static ApplicationContext applicationContext;
DefaultValueBean defaultValueBean = (DefaultValueBean) applicationContext.getBean("defaultValue");
The difference between doing CustomerService cService=new CustomerService(); and the other two statements is that in the later two statements, Spring will manage the lifecyle of the created object and it's dependencies whereas in the former case, you will have to manage the lifecycle of your object and all the dependencies it needs.
The difference between doing #Autowired CustomerService cService; and DefaultValueBean defaultValueBean = (DefaultValueBean) applicationContext.getBean("defaultValue"); is that in the former case,Spring will look for a bean depending on the autowiring mode where as in the later, you ask Spring to look for a bean whose idis configured as defaultValue
You can go through the Spring documentation on dependency injection for a more detailed explanation.
From what I understand when you declare a bean using Autowire in spring, you are accessing an instance of that object that would be available from the systems start up. So if you were to access it in two different classes you would be accessing the same object.
CustomerService cService=new CustomerService();
is declaring a completely new instance of that object so if you were to do this in two different classes then they would both be totally separate objects.
for example
public class Class1(){
#Autowired
CustomerService cService;
}
public class Class2(){
#Autowired
CustomerService cService;
}
public class Class3(){
CustomerService cService=new CustomerService();
}
Class1 and Class2 are both accessing exactly the same object whereas Class3 is accessing a completely new instance of this object.
Your final way of declaring the bean like Chetan Kinger explains does the same as the Autowiring in that the lifecycle is managed by spring the only difference is in how the bean is being located.
this site helped me a lot when I first came across spring (may bee helpful to you too) http://www.tutorialspoint.com/spring/index.htm
I am studying Spring framework and I have the following doubt related the #Autowired annotation on the constructor of this example:
#Component
public class TransferServiceImpl implements TransferService {
#Autowired
public TransferServiceImpl(AccountRepository repo) {
this.accountRepository = repo;
}
}
So what exactly mean? That the AccountRepository repo object (definied as a component somewhere) is automatically injected into the TransferServiceImpl() constructor?
How it work this operation? Is it done by type? (because AccountRepository is a singleton for Spring default), or what?
Tnx
Spring will look for the AccountRepository bean in the container. There are multiple possible scenarios:
1- There are zero beans with the type AccountRepository. An exception will be thrown.
2- There is one bean with the type AccountRepository. The bean will be injected when TransferServiceImpl is constructed.
3- There are more than one bean with the type AccountRepository:
Fallback to the bean name. In this case, Spring will look for a bean of type AccountRepository with name repo. If a match is found, it will be injected.
The name fallback fails (multiple beans with the same type and name). An exception will be thrown.
With #Component you tell the scan process that this class is a bean, with #autowire you tell the post processor to search through the spring repository for a bean of type AccountRepository. If the bean is found, it will be used with the annotated constructor. Based on the scope, a new instance will be used (prototype) or an already instanciated bean will be passed (singleton). If in anyway there are two beans matching the constructor argument, an exception will be thrown.
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);
}
}
I am using Spring Framework 4.
I have a class (say ClassA) in which another class (say ClassB) is been used. ClassA's member variables are getting value from ClassB. ClassB has a static method which read data from properties file. In ClassB a static member variable ApplicationContext is been injected using #Autowired annotation.
What I want is, I want to make sure that when ClassA uses's its member variable it should get all set with values read from properties file. And for that ClassB should get ApplicationContext all set to read from MessageSource.
As ClassA is marked as #Component, Spring loads ClassA, but when it tries to initialize member variables, it is getting NullPointerException, as ApplicationContext is not yet initialized.
So my question here is, Is there any way available to let Spring tell that some bean should be initialized at some order or something like that. I tried using #DependsOn annotation and specified #Bean to the getter method of ApplicationContext. But it gives below exception:
Caused by: org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'applicationContext': Requested bean is currently in creation: Is there an unresolvable circular reference?
Any idea on this issue?
Thanks
Thanks for comments.
I found the solution in one of the annotations supplied by Spring Framework.
Solution of #DependsOn annotation worked. Actually when I was using #Bean above getter method of ApplicationContext it was firing exception as mentioned in the question. Then I read the documentation of #DependsOn annotation. It states that this annotation is applicable on #Bean and #Component. As the class in which ApplicationContext was being injected, I've made ClassA #DependsOn the #Component class where ApplicationContext is being injected and it works.
Thanks again for your comments.
If your purpose is to use a MessageSource, use the built-in support, as explained here.
In general, don't #Autowire static fields, use #Value and PropertySourcePlaceholderConfigurer for properties.
Here a good example for the solution given by #Parth Bhagat.
https://www.baeldung.com/spring-depends-on
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.)