Spring automatically injects method parameters - java

I've started to learn spring and I'm a bit confused about this:
If I create a spring #Controller or #RestController and then in the method I ask for different parameters, I've noticed that spring automatically populate those parameters even without having them declared as bean or component.
So on my project I've a Movie class (a simple POJO) and I need to have a singleton instance of RestTemplate too. The first approach was to declare the RestTemplate bean and then ask for it using the #Autowired and that's working fine. After that I've commented out that part of code and put the RestTemplate and Movie as parameters of my method and spring is automatically providing me those instances even though I don't have any bean declaration of them.
I thought spring leverages on bean declaration to do dependency injection so my question is why do I've to declare the bean and use #Autowired if spring already injects whatever I want inside the method? Does spring injects a singleton instance of these parameters? And is this okay to use or better to decalre the bean and go through #Autowired?
Below the classes:
This is my movie model:
import lombok.Data;
import lombok.NoArgsConstructor;
#Data
#NoArgsConstructor
public class Movie {
private String movieId;
private String name;
}
This is my rest controller:
#RestController
#RequestMapping("/catalog")
public class MovieCatalogController {
//#Autowired
//private RestTemplate restTemplate;
#RequestMapping("/{userId}")
public List<Catalog> getCatalog(#PathVariable("userId") String userId, RestTemplate restTemplate, Movie movie){
// todo
return new ArrayList<>();
}
}
And the main spring boot application class:
#SpringBootApplication
public class MovieCatalogServiceApplication {
//#Bean
//public RestTemplate getRestTemplate() {
//return new RestTemplate();
//}
public static void main(String[] args) {
SpringApplication.run(MovieCatalogServiceApplication.class, args);
}
}
Thank you

What you are referring to is called method injection. Any component can be injected as long as there is a single implementation (you can specify what implementation to use when this is not the case with profiles or with #Qualifier annotation)
The number of instances of the class is dictated by the #scope. Singleton is the default scope so you should be ok without needing to use your bean definition.
#autowired is a bit old by now but still has its uses. Although for basic injection it is preferred to use constructor or method injection.
I'm fairly new to Spring myself, so I might be wrong

Related

Spring Boot | Using a separate file for logic

I am writing a small CRUD in Spring and Java. And I want to use a separate file for writing logic, this is very convenient for me, I did this when developing with NestJS. I have a few questions, is it correct to do this in Spring, or should I do everything inside a function in the controller. And if I write logic in a separate file, I should mark the logic class as #Component and the functions inside it as #Bean, right? I am new to Spring and as I understand it, I have to do this in order for the application to work correctly and my functions to be in the application context.
AuthLogic.java
#Component
public class AuthLogic {
#Bean
public void register() {
// code ...
}
}
AuthController.java
#RestController
public class AuthController {
#RequestMapping(value = "/register", method = RequestMethod.POST)
#ResponseStatus(HttpStatus.CREATED)
public void register(#Valid #RequestBody UserDTO newUser) {
// here I call the register function from AuthLogic
}
}
you can mark your logic class with #Service and use that for example you can make a AuthService and use it like
#Service
public class AuthService{
public returnType login(){
//Logic
}
}
and use this like
#RestController
public class AuthController {
AuthService authService;
#RequestMapping(value = "/register", method = RequestMethod.POST)
#ResponseStatus(HttpStatus.CREATED)
public void register(#Valid #RequestBody UserDTO newUser) {
authService.login();
}
}
You can write your business logic in a new separate file at service layer.
Suppose you name it as AuthService and you mark it with annotation #Service.
#Service
public class AuthService{
}
You can then Autowire it in your controller class.
#RestController
public class AuthController {
#Autowired
AuthService authService;
#RequestMapping(value = "/register", method = RequestMethod.POST)
#ResponseStatus(HttpStatus.CREATED)
public void register(#Valid #RequestBody UserDTO newUser) {
// here I call the register function from AuthLogic
}
}
Using separate files, or classes more importantly, is very recommended in Spring, and I assume most other languages.
The #Bean annotation on AuthLogic.java is unneeded and I think may cause startup or compilation errors.
I would change the name of AuthLogic to AuthLogicImpl, create an interface named AuthLogic with the method signature void register(), and have AuthLogicImpl implement AuthLogic. Then you can create a constructor for AuthController which accepts and AuthLogic parameter and sets it to a private field (note using the interface not the implementation in the constructor).
At the core of Spring is the IoC container. This container holds "beans" that can be injected or autowired into other beans. These beans are an instance of their class and can be used by other beans. Remember Spring uses the singleton pattern, so your beans should be stateless. This allows Spring to handle the application startup for you, so you don't need to write a ton of code creating all the different services/classes and wiring them together, it's all automagically done for you.
There are two key annoitations that you appear to be confused about:
#Component Putting this above a class will create an instance of that class (a bean) and put it into the IoC container. Other beans can access this by accepting the original beans interface in its constructor. So if I put #Component above my class FooImpl which implements Foo, then I can create a class, BarImpl with the constructor public BarImpl(Foo foo) {this.foo = foo} and BarImpl can use any public method of Foo (which will use FooImpl's implementation).
#Bean this is to be put on a method of a class that is annotated with #Configuration. This tells Spring that this method should be run at startup, and this method will return a bean that Spring should add to the IoC container. This is a popular way of configuring a bean that requires some parameters, such as the bean that manages the connection to a third party service or datastore, especially when that there is a little bit of logic that needs to go into creating the bean.
Note that the above is very broad, and there are some specifics if you need to dig deep into the spring framework, so there will be more clarification in the Spring documentation or you dig into some established Spring project. However it should suffice to answer the broad question of what is going on with #Component and #Bean.
There is no specific layout or code structure for Spring Boot Projects. However, there are some best practices followed by developers that will help us too. You can divide your project into layers like service layer, entity layer, and repository layer.
We use the entity layer to write all model and POJO classes. We annotate them with #Entity.
We use #Repository to indicate that this is a repository interface that is used to do some basic CRUD operations.
Sidenote:- You don't have to write #Repository for classes that implement or interfaces that extends Repository interfaces provided by Spring Boot framework.
We use #Service to say that this is the service class where your all business logic will be present.
We use the controller layer to receive HTTP requests and send back HTTP Responses or views.
You can learn and understand more from here
You can refer to this Image to understand the structure
project structure

Bean name resolution in Spring using #Bean and #Qualifier annotations

I just found a behaviour of Spring that I cannot understand. I am using Spring Boot 1.5.x.
In a configuration class, I declared two different beans.
#Configuration
class Config {
#Bean("regularRestTemplate")
public RestTemplate regularRestTemplate(String toLog) {
return new RestTemplateBuilder().setConnectTimeout(100)
.setReadTimeout(100)
.additionalInterceptors((request, body, execution) -> {
log.info("Inside the interceptor {}", toLog);
return execution.execute(request, body);
})
.build();
}
#Bean("exceptionalRestTemplate")
public RestTemplate regularRestTemplate() {
return new RestTemplateBuilder().setConnectTimeout(100)
.setReadTimeout(100)
.build()
}
}
Then, I have a class that should use the bean called exceptionalRestTemplate.
#Component
class Client {
private RestTemplate restTemplate;
#Autowired
public Client(#Qualifier("exceptionalRestTemplate") RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
// Code that uses the injected rest template
}
Since I specified the name of the bean I want to be injected using the #Qualifier annotation, I would expect that Spring injects the bean called exceptionalRestTemplate. However, the bean called regularRestTemplate is actually used during the injection process.
It turns out that the problem was in the name of the methods that declare the beans in the configuration class. Both are colled regularRestTemplate. Changing the second method name, solve the problem.
My question is, why? I know that Spring uses the names of classes and methods annotated with the #Bean or with the #Component, #Service, etc... annotations to give a name to Java object inside the resolution map. But, I supposed that giving a name inside these annotations would override this behaviour.
Does anybody tell me what's going on?
Bean qualifier and bean name are different meanings. You qualified new bean but tried to override it (arguments don't matter). In your application, you cannot override beans so you have the only first one.
You can check this 'theory'. Add a parameter in your configuration
spring.main.allow-bean-definition-overriding=true
and start your application again. After that, you will have only a second bean.
This is an explanation of the collision. But the solution is a separation of beans to different configurations.

Unable to Understand how auto wiring is done in the below class

below is the class which has constructor args which gets autoWired, but what i don't understand is that how the constructor gets autowired here without specifying any annotation or without mentioning it in any xml file.
I am kind of baffled with the code.
#Loggable
#Slf4j
public class DefaultDirectPlusService extends AbstractDnBDirectPlusService implements DirectPlusService {
public DefaultDnBDirectPlusService(String baseURL, RestTemplate restTemplate, DnBMetricsRepository dnbMetricsRepository, Environment env) {
super(restTemplate, dnbMetricsRepository, env);
this.baseURL = baseURL;
}
Here the question is how does baseURL gets populated without any annotations or the xml configuration?
As specified in the documentation (https://docs.spring.io/spring/docs/5.1.9.RELEASE/spring-framework-reference/core.html#beans-autowired-annotation), starting with Spring 4.3, if a class has only one constructor, Spring will automatically use that constructor for autowiring.
If you would have more than one constructor (you can try it out), you need to add the #Autowired annotation to the constructor which you want Spring to use.

Spring boot dependency bean not setting value [duplicate]

This question already has answers here:
Why is my Spring #Autowired field null?
(21 answers)
Closed 4 years ago.
In my Spring boot application, I have a dependency Spring project. From my SpringBoot class, I am trying to call a dependency class but the class has no value set.
#CrossOrigin(origins = "*")
#RestController
#Configuration
#ComponentScan(basePackages = "com.dependency.package")
public class BootClass {
private DependencyClass dependencyClass;
public BootClass() {
this.dependencyClass = new DependencyClass();
}
}
My DependencyClass object just gives me an empty object {}. Any ideas?
My Dependency class looks like this:
#Component
public class DependencyClass {
#Value("${jdbc.driver.class.name}")
private String driver;
#Value("${jdbc.url}")
private String url;
}
Thank you,
Julian
This is the classic Spring beginner mistake: calling new to instantiate an object.
You cannot call new if you want Spring to manage beans and provide dependencies. You have to give it to the Spring bean factory to manage. It's all or none.
Yours looks like a perfect case for constructor injection.
#Configuration
#ComponentScan(basePackages = "com.dependency.package")
public class BootClass {
private final DependencyClass dependencyClass;
#Autowired
public BootClass(#Qualifier(name = "dependencyClass") DependencyClass dependencyClass) {
this.dependencyClass = dependencyClass;
}
}
Surely you can think of a better name for DependencyClass. I'd suggest something like DatabaseConfiguration.
That is not to say that every object should be under the control of the bean factory, or that new should never be called. Objects with short scope that aren't shared can certainly be instantiated.
It's objects that require dependency injection that need to be under the control of the bean factory.
Just Mark that with #Autowired Annotation as shown below. That would do.
#Autowired
private DependencyClass dependencyClass;
Extending the answer of #duffymo:
Once you are done what he suggested, also make sure that "jdbc.driver.class.name" and "jdbc.url" are present in your main project properties file. If you are expecting that these values will be populated just because you have it in
properties file of "Dependent" project, you might get disappointed. Check this for more details:
https://stackoverflow.com/a/49564724/3458292

#Inject not injecting and causing NullPointerException using component scanning

My application context XML is simple:
<context:component-scan base-package="com.depressio.spring" />
In that package, I have my configuration:
package com.depressio.spring
#Configuration
#ComponentScan(basePackages = "com.depressio")
public class DepressioConfiguration
{
#Inject private ApplicationContext context;
}
Within com.depressio, there's a repository (DAO):
package com.depressio.dao;
#Repository
public class ParameterDAO
{
public Parameter getParameter(long ID) { ... }
}
... and a service where injection is working just fine (no NPE when parameterDAO is used):
package com.depressio.resource;
#Service
#Path("/depressio/parameters")
public class ParameterResource
{
#Inject private ParameterDAO parameterDAO;
#Path("{id}")
public Response getParameter(long parameterID)
{
return Response.ok(parameterDAO.getParameter(parameterID).legacyFormat()).build();
}
}
However, the legacyFormat() method call there constructs another object. Within that object, I have to inject a different DAO (also annotated with #Repository, though). That injection isn't working.
So, we have the original Parameter object:
package com.depressio.domain;
public class Parameter
{
...
public LegacyParameter legacyFormat()
{
return new LegacyParameter(this);
}
}
... and the LegacyParameter where the injection isn't working:
package com.depressio.domain.legacy;
public class LegacyParameter
{
#Inject private LegacyDAO legacyDAO;
....
public LegacyParameter(Parameter newParameter)
{
// NullPointerException when using the injected legacyDAO.
}
}
I've tried a few things, including:
Using an no-args constructor for LegacyParameter, then calling a populate method so I'm not using the injected DAO until after the object is constructed. This didn't work.
Injecting the LegacyDAO into the ParameterResource and passing it in. This worked, but isn't ideal since I have to pass it around a whole lot (which injection should help avoid, no?). It did prove that LegacyDAO is injectible... just not into LegacyParameter apparently.
Adding a #Service, #Component, or #Named annotation on LegacyParameter. All end up with the NullPointerException on the line I try to reference the injected legacyDAO.
What am I missing?
As Sotirios has pointed out, it can't work since you create a regular Java object and do not give Spring a chance to enhance it.
Either let Spring create objects for which you want to enjoy the Spring 'magic' (like setting #Inject dependencies etc).
Or create your own objects and set the dependencies yourself (yourObject.setDao(dao)).
That said, there are exceptional cases in which you still want to create your objects 'on the fly' by yourself but rely on Spring to inject dependencies to these objects. In this case you should call Spring explicitly:
LegacyParameter p = new LegacyParameter(...);
applicationContext.getAutowireCapableBeanFactory().autowireBean(p);
I don't think you really need it in your case.
(see this link inject bean reference into a Quartz job in Spring? for an example when this is really required).
In addition, I would advice to simplify your configuration.
Why do you use both xml-based and java-based configuration that do actually the same? In your example you could keep only one of them and have the same effect.

Categories

Resources