If I have a #Configuration class where I have a bean like below, will the dataMap be resolved in the constructor of the DataService class. What type of dependency injection is this? Is it by type because the name for sure doesn't match?
#Bean
public Map<String, List<Data>> data() {
final Map<String, List<Data>> dataMap = new HashMap<>();
readings.put("1", new Data());
return dataMap;
}
and a class
#Service
public class DataService {
private final Map<String, List<Data>> information;
public DataService(Map<String, List<Data>> information) {
this.information = information;
}
}
#Configuration annotation serves as a placeholder to mention that whichever classes annotated with #Configuration are holding the bean definitions!
When Spring application comes up, spring framework will read these definitions and create beans (or simply objects) in IOC (Inversion of control) container These would be Spring managed objects/beans !
To answer your question, it should create a bean and this is a setter based injection!
However, your #Bean must be some user defined or business entity class in ideal scenarios!
Few links for you to refer to:
https://www.codingame.com/playgrounds/2096/playing-around-with-spring-bean-configuration
https://www.linkedin.com/pulse/different-types-dependency-injection-spring-kashif-masood/
Related
public interface CourseRepo extends CrudRepository<Course, Long> {
}
#Getter
#Setter
#AllArgsConstructor
#NoArgsConstructor
public class UnitOfWork {
CourseRepo courses;
StudentRepository students;
StudyProgramRepository studyPrograms;
StudySchemeRepo studySchemes;
FeeStructureRepository feeStructures;
}
#RestController
public class TestController {
#Autowired
UnitOfWork uow;
#GetMapping("/addcr")
public String addCourse() {
Course cr = new Course();
cr.setTitle("DingDong course");
uow.getCourses().save(cr);
return "course Added..!!" ;
}
APPLICATION FAILED TO START
***************************
Description:
Field uow in com.srs.TestController required a bean of type 'com.srs.uow.UnitOfWork' that could not be found.
The injection point has the following annotations:
- #org.springframework.beans.factory.annotation.Autowired(required=true)
Action:
Consider defining a bean of type 'com.srs.uow.UnitOfWork' in your configuration.
if i remove autowired and add a bean
#RestController
public class TestController {
#Bean
public UnitOfWork uow() {
return new UnitOfWork();
}
#GetMapping("/addcr")
public String addCourse() {
Course cr = new Course();
cr.setTitle("DingDong course");
uow().getCourses().save(cr);
return "course Added..!!" ;
}
java.lang.NullPointerException: Cannot invoke "com.srs.jpa.CourseRepo.save(Object)"
because the return value of "com.srs.uow.UnitOfWork.getCourses()" is null
i tried both autowired and in this case how can i use autowired or bean properly ?
Your class need to be annotated with #Component to be used with DI provider by #Autowired annotation
For the same reason each repository of your class need to be annotated with #Autowired
The Error Message gives the answer.
Field uow in com.srs.TestController required a bean of type 'com.srs.uow.UnitOfWork' that could not be found.
spring is searching for a bean from type UnitOfWork. You have to add this class to the application context from spring boot. To accomplish this you have to annotate the class UnitOfWork with #bean or #Data if you use lombok.
After this the spring application can find the Class UnitOfWork and auto wire it.
Since UnitOfWork (a somewhat misleading name in the JPA context) autowires data repositories, it has to be a Spring Bean itself.
The easiest and most common way is to annotate the class with one of the annotations #Service, #Component or #Bean, depending on the semantic of the class. There are also other ways, like the #Bean on method-level as you used.
To use the fully initialized bean you need to autowire it where you want to use it, not calling the create method. E.g. calling uow() as in your sample, bypasses the Spring Bean mechanism and creates a new instance, which hasn't been fully initialized (thus the NullPointerException).
Usually, the beans are autowired as fields, sometimes they are autowired in mehtod parameters (especially when working with #Bean on method-level in the same class).
E.g.
#Component
#Getter
#RequiredArgsConstructor
public class UnitOfWork {
private final CourseRepo courses;
private final StudentRepository students;
private final StudyProgramRepository studyPrograms;
private final StudySchemeRepo studySchemes;
private final FeeStructureRepository feeStructures;
}
This question already has answers here:
Injecting beans into a class outside the Spring managed context
(8 answers)
Closed 3 years ago.
Introduction
I have some business logic properties in the application.yml file.
They are loaded into the application via a #ConfigurationProperties annotated class.
How could I use these properties in a class which is not a Spring Bean? It cannot be a singleton, because many objects of it must be created during run-time.
Example
application.yml
business.foo: 2
BusinessProperties.java
#ConfigurationProperties("business")
#Getter // lombok
#Setter // lombok
public class BusinessProperties {
private int foo;
}
TypicalBean.java
#Component
public class TypicalBean {
private final BusinessProperties properties;
#Autowired
public TypicalBean(BusinessProperties properties) {
this.properties = properties;
}
#PostConstruct
public void printFoo() {
System.out.println("Foo: " + properties.getFoo()); // "Foo: 2"
}
}
NonBean.java
public class NonBean {
public void printFoo() {
System.out.println("Foo: ???"); // How to access the property?
}
}
Is there some way to create a non-singleton class, which can have access to configuration (or even other Spring beans) but otherwise works the same as a regular java class? Meaning that I can control its creation, it is collected by the garbage collector if not used anymore, etc.
You can still define the NonBean.class as a Component with Scope.Prototype
#Component
#Scope(value = BeanDefinition.SCOPE_PROTOTYPE)
public class NonBean {
#Autowired
public TypicalBean(BusinessProperties properties) {
this.properties = properties;
}
public void printFoo() {
System.out.println("Foo: " + properties.getFoo());
}
}
The trick is how you create an instance of NonBean.class. In the code where you'll be creating an instance of NonBean.class, use Spring's ObjectFactory<T>
private final ObjectFactory<NonBean> nonBeanFactory;
...
NonBean nonBean = nonBeanFactory.getObject();
The instantiated nonBean object will have been autowired.
All spring-beans creates by SpringApplicationContext. Bean - it's simple POJO-object, but created by Spring and saved in his container. If you want to get access to bean from outside of container - see this:
Getting Spring Application Context
Spring beans are really meant to be used within the application context but you might be able to achieve what you want by autowiring the properties to a static field in a Spring bean.
#Component
public class BusinessPropertiesUtils {
public static BusinessProperties INSTANCE;
#Autowired
public setBusinessProperties(BusinessProperties properties) {
this.INSTANCE = properties;
}
}
And then:
public class NonBean {
public void printFoo() {
System.out.println("Foo: " + BusinessPropertiesUtils.INSTANCE.getFoo());
}
}
PS: this is very hacky and definitely not the "Spring way".
You can configure beans with the prototype scope, which will give you a new instance of the bean every time it's requested.
From the Spring documentation:
In contrast to the other scopes, Spring does not manage the complete lifecycle of a prototype bean. The container instantiates, configures, and otherwise assembles a prototype object and hands it to the client, with no further record of that prototype instance.
...
In some respects, the Spring container’s role in regard to a prototype-scoped bean is a replacement for the Java new operator. All lifecycle management past that point must be handled by the client.
Example of how you can convert the TypicalBean class to a prototype scoped bean:
#Component
#Scope("prototype")
public class TypicalBean {
...
}
Another alternative is to manually instantiate the bean class (or any POJO) and injecting the dependencies (configuration, spring beans, etc.) through the constructor or setter methods, if you have them available or can get them from the Spring Context.
new TypicalBean(properties);
From spring boot documentation, #ConfigurationProperties will
generate your own configuration metadata file from items annotated
with #ConfigurationProperties
I tried use #Configuration and #ConfigurationProperties separately on my configuration class.
#Component
//#Configuration
#ConfigurationProperties
#EnableSpringDataWebSupport
#EnableAsync
public class AppConfig {
...
}
I didn't see any noticable difference.
What's the usage of #ConfigurationProperties or #Configuration?
#Configuration is used to create a class the creates new beans (by annotating its methods with #Bean):
#Configuration
public class CustomConfiguration {
#Bean
public SomeClass someClass() {
return new SomeClass();
}
}
#ConfigurationProperties binds external configuration into the fields of the class which it annotates. It's common to use it with a #Bean method to create a new bean that encapsulates configuration which can be controlled externally.
Here's a real world example of how we've used it. Consider a simple POJO that holds some values related to connecting to ZooKeeper:
public class ZookeeperProperties
{
private String connectUrl;
private int sessionTimeoutMillis = (int) TimeUnit.SECONDS.toMillis(5);
private int connectTimeoutMillis = (int) TimeUnit.SECONDS.toMillis(15);
private int retryMillis = (int) TimeUnit.SECONDS.toMillis(5);
private int maxRetries = Integer.MAX_VALUE;
// getters and setters for the private fields
}
Now we can create a bean of type ZookeeperProperties and automatically populate it using external configuration:
#Configuration
public class ZooKeeperConfiguration {
#ConfigurationProperties(prefix = "zookeeper")
#Bean
public ZookeeperProperties zookeeperProperties() {
// Now the object we create below will have its fields populated
// with any external config that starts with "zookeeper" and
// whose suffix matches a field name in the class.
//
// For example, we can set zookeeper.retryMillis=10000 in our
// config files, environment, etc. to set the corresponding field
return new ZookeeperProperties();
}
}
The benefit of this is that it's less verbose than adding #Value to every field of ZookeeperProperties. Instead, you provide a single annotation on the #Bean method and Spring automatically binds any external configuration it finds with the matching prefix to the fields of that class.
It also lets different users of my class (i.e. anyone who creates a bean type of ZookeeperProperties) use their own prefix to configure the class.
The use case of ConfigurationProperties is for externalizing configuration.
#Configuration
Indicates that a class declares one or more #Bean methods and may be processed by the Spring container to generate bean definitions and service requests for those beans at runtime.
#ConfigrationProperties
-- Is added to a class definition or a #Bean method in a #Configuration class if you want to bind and validate some external Properties (e.g. from a .properties file).
See the screenshot to differentiate #Value from #ConfigurationProperties.
https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html#boot-features-external-config-typesafe-configuration-properties
It might be a very simple question for you.But I read lots of documents and I am totally confused.We can use #Component instead of #Bean or #Bean instead of #Component(as well as #Repository #Service #Controller) ?
Cheers
Component
#Component also for #Service and #Repository are used to auto-detect and auto-configure beans using classpath scanning.
As long as these classes are in under our base package or Spring is aware of another package to scan, a new bean will be created for each of these classes
Bean and Component are mapped as one to one i.e one bean per Class.
These annotations (#Component, #Service, #Repository) are Class level annotations.
Example:
Lets Say we have a UserService Class which contains all methods for User Operation.
#Service
public class UserService {
#Autowired
private UserRepository userRepository;
#Override
public User findByUsername( String username ) throws UsernameNotFoundException {
User u = userRepository.findByUsername( username );
return u;
}
public List<User> findAll() throws AccessDeniedException {
List<User> result = userRepository.findAll();
return result;
}
}
Spring will create a Bean for UserService and we can use this at multiple location/classes.
#Bean
#Bean is used to declare a single bean, rather than letting Spring do it automatically as in case of Component.
It decouples the declaration of the bean from the class definition, and lets you create and configure beans exactly how you choose.
#Bean are used at method level and can be configured as required
eg:
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Bean
public SpringTemplateEngine springTemplateEngine()
{
SpringTemplateEngine templateEngine = new SpringTemplateEngine();
templateEngine.addTemplateResolver(htmlTemplateResolver());
return templateEngine;
}
#Bean
public SpringResourceTemplateResolver htmlTemplateResolver()
{
SpringResourceTemplateResolver emailTemplateResolver = new SpringResourceTemplateResolver();
emailTemplateResolver.setPrefix("classpath:/static/template/");
emailTemplateResolver.setSuffix(".html");
emailTemplateResolver.setTemplateMode("HTML");
emailTemplateResolver.setCharacterEncoding(StandardCharsets.UTF_8.name());
return emailTemplateResolver;
}
...
Read more about Stereotype Annotations here.
#Bean is used to define a method as a producer, which tells Spring to use that method to retrieve an object of the method return type and inject that object as a dependency whenever it's required.
#Component is used to define a class as a Spring component, which tells Spring to create an object (if it's Singleton) from and take care of it's lifecycle and dependencies and inject that object whenever it's required.
#Service and #Repository are basically just like #Component and AFAIK they are just for better grouping of your components.
#Service for Defining your service classes where you have your business logic, and #Repository for Defining your repository classes where you interact with an underlying system like database.
#Component
If we mark a class with #Component or one of the other Stereotype annotations these classes will be auto-detected using classpath scanning. As long as these classes are in under our base package or Spring is aware of another package to scan, a new bean will be created for each of these classes.
package com.beanvscomponent.controller;
import org.springframework.stereotype.Controller;
#Controller
public class HomeController {
public String home(){
return "Hello, World!";
}
}
There's an implicit one-to-one mapping between the annotated class and the bean (i.e. one bean per class). Control of wiring is quite limited with this approach since it's purely declarative. It is also important to note that the stereotype annotations are class level annotations.
#Bean
#Bean is used to explicitly declare a single bean, rather than letting Spring do it automatically like we did with #Controller. It decouples the declaration of the bean from the class definition and lets you create and configure beans exactly how you choose. With #Bean you aren't placing this annotation at the class level. If you tried to do that you would get an invalid type error. The #Bean documentation defines it as:
Indicates that a method produces a bean to be managed by the Spring container.
Typically, #Bean methods are declared within #Configuration classes.We have a user class that we needed to instantiate and then create a bean using that instance. This is where I said earlier that we have a little more control over how the bean is defined.
package com.beanvscomponent;
public class User {
private String first;
private String last;
public User(String first, String last) {
this.first = first;
this.last = last;
}
}
As i mentioned earlier #Bean methods should be declared within #Configuration classes.
package com.beanvscomponent;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
#Configuration
public class ApplicationConfig {
#Bean
public User superUser() {
return new User("Partho","Bappy");
}
}
The name of the method is actually going to be the name of our bean. If we pull up the /beans endpoint in the actuator we can see the bean defined.
{
"beans": "superUser",
"aliases": [],
"scope": "singleton",
"type": "com.beanvscomponent.User",
"resource": "class path resource
[com/beanvscomponent/ApplicationConfig.class]",
"dependencies": []
}
#Component vs #Bean
I hope that cleared up some things on when to use #Component and when to use #Bean. It can be a little confusing but as you start to write more applications it will become pretty natural.
I'm a beginner at Spring and beginning to understand how beans work. I want to declare a 3rd party class as a Service or a Bean. How do I do this? Should I just extend the class and annotate that?
example:
#Service
public class MyService { public MyService(ThirdPartyClass thirdPartyClass){..}....}
Here I cannot annotate ThirdPartyClass as a Service or otherwise
If your aren't the owner of the class that you would like to use as a bean, you can create the bean declaration in one of application's configuration classes:
#Configuration
public class YourConfig {
#Bean
public ThirdPartyClass thirdPartyClass() {
return new ThirdPartyClass();
}
}
Spring will instantiate an appropriate object based on that description and expose it via container to other beans.
You can add the class which is out of your control as #Bean
#Configuration
public class ApplicationConfig {
#Bean
public ClassName methodName() {
return new ClassName();
}
}
At the time of initializing the application, spring will call this method and register ClassName object to spring context and will be made available where you #Autowired this bean.