after my teammates merged her changes (implements #EnableFeignClients for our SpringBootApplication and created some feign clients, properties and configs from the main branch), when boot the application it will pop up the The dependencies of some of the beans in the application context from a cycle: xxx
To resolve this issue I deleted some #Autowired from some involved controller/service classes and make them private and then the application can be boot successfully:
before my change:
#Autowired
MyUtil myUtil; //#Component
#Autowired
MyConfig myConfig; //#Component
#Autowired
MyApi myApi; //Interface class
public void myFunction(){
String id = myUtil.getId();
String name = myConfig.getNameById(id);
myApi.sendInfo(id, name);
}
after my change:
private MyUtil myUtil; //#Component
private MyConfig myConfig; //#Component
private MyApi myApi; //#Component
public void myFunction(){
String id = myUtil.getId();
String name = myConfig.getNameById(id);
myApi.sendInfo(id, name);
}
Spring version:
<groupID>org.springframework.boot</groupID>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.11</version>
and here are my concerns:
Will there be any impact after my changes (functional, performance, etc.)?
In my case (or in most scenarios in the future development), should i use #Autowired? When need to? When doesn't need to?
TL DR. You cannot delete #Autowired directly.
#Autowired is used by Spring in order to do dependency injection ( I know this is a fancy word)
#Autowired
ChickenService chickenService
#Autowired is almost equivalent to ChickenService chickenService = new ChickenService();
After your change,private MyConfig myConfig; //#Component myConfig will be null and therefore you introduced a bug.
Suppose that you have an EggService
#Service
public class ChickenService {
#Autowired
private EggService eggService;
}
The chicken holds a reference to the egg
#Service
public class EggService {
#Autowired
private ChickenService;
}
Now you have a chicken and egg problem.
https://www.baeldung.com/circular-dependencies-in-spring
#Autowired help the spring to find where it should inject classes.
The impact is that spring will not create objects of the classes where you removed the annotation.
Additional way to create objects in spring are with setter or constructor injection.
Example of constructor injection will be something like:
public YourClassName(MyUtil myUtil, MyConfig myConfig, MyApi myApi){
this.myUtil = myUtil;
this.myConfig = myConfig;
this.myApi = myApi;
}
I think also good idea as well to check why #Autowired not working. Can you provide full error? Does your class annotated with #Service or something
Related
I am learning Spring while I like the idea of using #Component and #Autowired to let Spring manage the dependent bean. For example, I have a Service class and Builder Class I can do with
// SomeService.java
#Service
public class SomeService {
// SomeBuilder is a #Component class
#Autowired
SomeBuilder someBuilder;
}
// SomeController.java
#Component
public class SomeController {
#Autowired
SomeService someSerivce;
}
Spring would take care of the creation of from SomeController to SomeService to SomeBuilder with the usage of #Autowired. However, now my SomeService class needs a private field which is NOT a Component class, just a plain context object, for example
// SomeService.java
#Service
public class SomeService {
#Autowired
SomeBuilder someBuilder;
private SomeContext someContext;
// Plan A: Using constructor to initiate the private field. However, I cannot use #Autowired to initiate SomeService in SomeController anymore as it requires a parameterless constructor
// Plan B: using #Autowired on constructor level, I cannot use this because SomeContext is not a #Component class
//public SomeService(SomeContext someContext) {
//this.someContext = someContext;
//}
// Plan C: This seems work but I kinda feel it's not the right way, as usually private field are initiated through constructor
//public void init(SomeContext someContext) {
// this.someContext = someContext;
//}
// demo usage of someContext
public someAnswer realMethod() {
System.out.println(someContext.getName());
}
}
Now I have no idea how to inject the someContext now, I used
plan A: Assign the private field using class constructor
plan B: Using #Autowired on constructor level
plan C: Using a wired method to assign the private field.
but I am not satisfied and don't have a clear way of doing the right approach.
First lets take a look at your plans and bust some myths/misunderstandings.
Plan A: Using constructor to initiate the private field. However, I cannot use #Autowired to initiate SomeService in SomeController anymore as it requires a parameterless constructor
Great plan, and the way to go. #Autowired doesn't depend on having a default constructor. It only indicates that you want the field to be injected with an object of that type. How that object comes to live (default constructor, constructor with arguments) doesn't matter for #Autowired. So that part of your understanding is just wrong.
using #Autowired on constructor level, I cannot use this because SomeContext is not a #Component class
If there is just a single constructor in a bean Spring will automatically use that to satisfy the dependencies. So in this case you don't need #Autowired. A bean doesn't have to be an #Component, a bean is just an instance of a class available to the application context. One way of achieving that is by marking it as an #Component but there are other ways as well. Like defining an #Bean method in in an #Configuration class to construct the bean.
#Configuration
#ComponentScan("your.base.package")
public class YourConfiguration {
#Bean
public SomeContext someContext() {
return new SomeContext();
}
}
Something along those lines. It will detect the #Component annotated classes through the #ComponentScan and will create a bean of type SomeContext for use as a bean.
Plan C: This seems work but I kinda feel it's not the right way, as usually private field are initiated through constructor
All your fields should be private not just the ones initialized in a constructor, so also the #Autowired ones. You don't want those fields to be, easily, accessible from the outside so they can be modified. So make them private.
That all being said, go with constructor injection over field injection or setters/methods for injection. It is clearer and less hidden than field injection and the way to go for mandatory dependencies (for optional dependencies you can use a setter/method).
So using the above config and below classes, it should "just work (tm)".
// SomeService.java
#Service
public class SomeService {
// SomeBuilder is a #Component class
private final SomeBuilder someBuilder;
private final SomeContext someContext;
public SomeService(SomeBuilder someBuilder, SomeContext someContext) {
this.someBuilder=someBuilder;
this.someContext=someContext;
}
}
// SomeController.java
#Component
public class SomeController {
private final SomeService someSerivce;
public SomeController(SomeService someService) {
this.someService=someService;
}
}
This question already has answers here:
Why is my Spring #Autowired field null?
(21 answers)
Closed 5 years ago.
I've created a utilities class that will house some functionality that doesn't belong in standard controllers, such as syncing and ingesting API data. I have a very simple Repository class that extends CrudRepository:
//TransactionCategoryRepository.java
#Repository
public interface TransactionCategoryRepository extends CrudRepository<TransactionCategory, Integer> {
}
Then I have a service class which is also very straightforward at the moment:
//TransactionCategoryService.java
#Service
public class TransactionCategoryService {
private TransactionCategoryRepository transactionCategoryRepository;
#Autowired
public TransactionCategoryService(TransactionCategoryRepository repository) {
this.transactionCategoryRepository = repository;
}
public void saveTransactionCategory(TransactionCategory transactionCategory) {
transactionCategoryRepository.save(transactionCategory);
}
My utilities class leverages the TransactionCategoryService and I've attempted to include it with #Autowired:
//Utilities.java
#Controller
public class PlaidUtilities {
private Logger logger = LoggerFactory.getLogger(PlaidUtilities.class.getSimpleName());
private PlaidClient mPlaidClient;
#Autowired
TransactionCategoryService mTransactionCategoryService;
#Autowired
TransactionRepository mTransactionCategoryRepository;
....
When I use mTransactionCategoryService to save a new entity, I get the null pointer exception. IntelliJ previously threw warnings on my #Autowired annotations that the member classes needed to be declared in spring beans. Adding the #Controller annotation made these go away, though I'm not sure if that is the right thing to do; I tried this because this is the only difference between this class and another class which #Autowires in exactly the same way but does not have this problem.
The other classes that use Autowired in this way are in a package called controllers which is in the root directory. This Utilities class is in a package called util which is also in the root directory.
What have I done wrong in this setup/configuration?
You forget to autowire the repository in your service layer.
//TransactionCategoryService.java
#Service
public class TransactionCategoryService {
#Autowired //MISSING THIS
private TransactionCategoryRepository transactionCategoryRepository;
#Autowired
public TransactionCategoryService(TransactionCategoryRepository repository) {
this.transactionCategoryRepository = repository;
}
public void saveTransactionCategory(TransactionCategory transactionCategory) {
transactionCategoryRepository.save(transactionCategory);
}
I came across this code
#Singleton
#Controller
#Autowire(mode = AutowireMode.BY_NAME)
#Path("/")
public class RootResource {
}
I have seen #Autowire on fields,
It means autowiring by type, and class with this field will get bean with particular type.
But in above code I am not sure who is using this RootResource bean?
This is Spring-jersey Rest project.
What I understand is spring will create bean of RootResource and Some class will use this bean to set its property. (I cant see any explicit configuration for this bean)
My question is,
1) Who is this class?
2) Here Autowiring by name is done, Can I replace #Autowired with #Resource ?
The use of #Autowire in this case is to instruct the Spring container to inject dependencies into RootResource by using beans with names matching property names in RootResource.
This is similar to that autowire attribute of the bean element using XML configuration. Assuming RootResource has
#Singleton
#Controller
#Autowire(mode = AutowireMode.BY_NAME)
#Path("/")
public class RootResource{
private SomeService someService;
private AnotherService anotherService;
public void setSomeService(SomeService someService){
this.someService = someService;
}
public void setAnotherService(AnotherService anotherService){
this.anotherService = anotherService;
}
}
The container will attempt to find beans named someService and anotherService and will try to set the corresponding properties. Take note you don`t require any dependency inject annotations the property or field level.
You can use #Resource / #Autowired to achieve the same thing. However you have to annotate the fields or setters in this case. And also injection will fail if the dependency is not found in the container
#Singleton
#Controller
#Autowire(mode = AutowireMode.BY_NAME)
#Path("/")
public class RootResource{
private SomeService someService;
private AnotherService anotherService;
#Resource
public void setSomeService(SomeService someService){
this.someService = someService;
}
#Resource
public void setAnotherService(AnotherService anotherService){
this.anotherService = anotherService;
}
}
#Resource will use bean name and fall back to type matching whilst #Autowired always uses type matching
Also note that #Autowire and #Autowired have different behaviour. The RootResource bean does not need to be explictly configured in the application context. It will be auto detected by the component scanner as it has a stereotype annotation i.e #Controoler
I have Spring Java Services class with a lot of beans:
#Service ("employeeManager")
public class EmployeeManagerImpl implements EmployeeManager
{
#Autowired
EmployeeDAO employeedao;
#Autowired
Workerdao workerdao;
#Autowired
SallaeryDao sallaeryDao
#Autowired
TaxDao taxDao
#Autowired
HouresDao houresDao
#Autowired
*****Dao
public EmployeeDTO createNewEmployee()
{
return dao.createNewEmployee();
}
}
Can I clean the Service class code without a lot of bean declare in my class that I will have only one bean? I have a lot of bean and I don't want to declare them in the class with
I'm developing a web app using the Spring 3 framework.
So, I have the next hierachy level in my controllers package:
#Controller
public class BaseController {
#Autowired
#Qualifier("problemService")
protected ProblemService problemservice;
#Autowired
#Qualifier("codeService")
protected CodeService codeservice;
#Autowired
#Qualifier("userService")
protected UserService userservice;
#Autowired
#Qualifier("sessionRegistry")
protected SessionRegistry session;
.....
}
with children
#Controller
public class CodeController extends BaseController{
...
}
#Controller
public class ProblemController extends BaseController{
...
}
What i want is all these service of BaseController available to the children, but more like static resources, that is, all children share an unique instance of the father's services, and not a new instance of each as inheritance does.
In that way, I tried this for each resource in BaseController:
#Autowired
#Qualifier("problemService")
protected static ProblemService problemservice;
but Spring throws a NullPointerException.
So, is my idea at least correct? I mean, i do want to do what i said, but i dont know if it is a good approach at least.