Some doubts about Java Configuration of the Spring Application Context (dependency injection) - java

I am studying for Spring Core certification.
I know that in Spring I can configure the dependency injection using 3 way:
Java Configuration
Classes annotations
XML Configuration
I have some doubt related to how to use the first kind of dependency injection configuration.
For example I have something like this:
1) A class named TransferServiceImpl:
public class TransferServiceImpl implements TransferService {
public TransferServiceImpl(AccountRepository ar) {
this.accountRepository = ar;
}
...
...
...
}
This class contain the TransferServiceImpl() constructor that take an AccountRepository object as input paramether, so AccountRepository is a dependency that have to be injected into TransferServiceImpl().
2) This is the implementation of the previous AccountRepository class:
public class JdbcAccountRepository implements AccountRepository {
public JdbcAccountRepository(DataSource ds) {
this.dataSource = ds;
}
...
...
...
}
So the constructor of this class thake a DataSource object that have to be injected into the JdbcAccountRepository class.
Then I have a configurations class that contains the dependency injection configuration:
#Configuration
public class ApplicationConfig{
#Bean public TransferService transferService(){
return new TransferServiceImpl(accountRepository());
}
#Bean public AccountRepository accountRepository(){
return JdbcAccountRepository(dataSoruce());
}
#Bean public DataSource dataSource(){
DataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName("org.postgresql.Driver");
...................................
...................................
...................................
}
}
So it seems to me that it work in the following way:
I have my 2 implemented beans named TransferServiceImpl and JdbcAccountRepository and the configuration class named ApplicationConfig.
Into the configuration class I say that when someone ask to the factory to create a TransferService object it automatically build its implementation TransferServiceImpl creating and injecting automatically a JdbcAccountRepository into the TransferServiceImpl constructor.
In the same way when a JdbcAccountRepository is created it is injected a DataSource object into its constructor.
Is it right?
If it is right I have the following doubts:
1) Into the ApplicationConfig class I also declare the DataSource bean but I don't implement this class. Is it a class provided by Spring and I have only to set its properties values?
2) When are created the bean definied into the ApplicationConfig class? At the application startup? I think that, in the previous example, if I annotate a constructor using #Bean it is created as singleton at the application startup. Is it right or am I missing something?
Tnx

1) Into the ApplicationConfig class I also declare the DataSource bean
but I don't implement this class. Is it a class provided by Spring and
I have only to set its properties values?
Yes. There are a number of DataSource implementations provided by Spring. For example: DriverManagerDataSource, SingleConnectionDataSource, and more.
2) When are created the bean definied into the ApplicationConfig
class? At the application startup? I think that, in the previous
example, if I annotate a constructor using #Bean it is created as
singleton at the application startup. Is it right or am I missing
something?
By default beans are created when Spring container is instantiated (usually at startup if the app is wired as such). You can change this behavior, however, by using the #Lazy annotation where the bean will only be created when explicitly requested.
#Bean #Lazy public TransferService transferService(){
return new TransferServiceImpl(accountRepository());
}

Related

Spring : creating beans with #Bean

I have an issue with beans creations :
#Bean
Service carService() {
return new Service(new CarRepository(), "car");
}
My issue is that CarRepository class has a dependency to EntityManager em variable (with #PersistenceContext)
So if I use new operator, I'm missing this dependency (because I'm instanciating myself the bean).
Also I have many services (CarService, BikeService etc...) and many repositories too (CarRepository, BikeRepository etc...). So using annotations directly in classes seems difficult.
So any solutions ?
Simple. Pass your repository as dependency into your Bean factory function:
#Bean
Service carService(final CarRepository carRepository) {
return new Service(carRepository, "car");
}
The repository needs to exist as a bean itself. You can create the repository bean in another bean method of a configuration class, or by annotating the class and having it created during component scanning.
I think you need to annotate every repository class with #Repository
annotation. And every service class with #Service.
In Spring you should not use the new operator for Services. Use the annotation
#Service
public classSomeClass {
or
#Component
public classSomeClass {
and your class can be injected via depnendency Injection.
If you want to create a new custom bean that can be used via dependencyInjection This is what the #Configuration annotation is for.
#Configuration
public class ConfigurationClass{
#Bean
public SomeClass createSomeClass(){
return new SomeClass();
}
}

why are #Configuration classes wraped by the cglib proxy with the ConfigurationClassEnhancer class

when i read and debug spring source, I find that the #configuration classes are wraped by the cglib proxy with the ConfigurationClassEnhancer class, I don`t understand the reason of the design, thanks
To handle situations like below.
#Configuration classes contains bean definitions via #Bean
annotations
Many of the beans have collaborators, so we inject those
collaborators(which are also beans) using standard java method
semantics
So, every time datasource() is called, spring does not create new
instance(since it is Singleton).
This happens because #Configuartion class is proxied and it contains
the logic to check if beans are already in ApplicationContext
#Configuration
public class MyConfig{
#Bean
public MyDao1 Dao1(){
MyDao1 d1 = new MyDao1();
d1.setDataSource(datasource());
return d1;
}
#Bean
public MyDao2 Dao2(){
MyDao1 d2 = new MyDao2();
d2.setDataSource(datasource());
return d2;
}
#Bean
public Datasource datasource(){
DataSource ds = new DataSource();
return ds;
}
}
Note: #Component classes can also define beans via #Beans, but scenario like above will definitely cause problems since bean calls don't get intercepted via proxy in that case.

Spring Boot #Autowired MessageSource works in one classes and doesn't in another

I'm learning Spring boot framework (version 2.0.7.RELEASE) for developing web application. When I try to autowire MessageSource class it works for one classes, but doesn't for another:
Here is my WebConfig class:
package net.local.mis.phog.config;
#Configuration
public class WebConfig implements WebMvcConfigurer {
[...]
#Bean
public MessageSource messageSource() {
// This is the only place around application where messageSource is created
ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
messageSource.setBasename("classpath:messages");
messageSource.setDefaultEncoding("UTF-8");
return messageSource;
}
[...]
}
Everything works fine in controller classes, for example:
package net.local.mis.phog.controller;
#Controller
#Transactional
public class AlbumController {
[...]
#Autowired
private MessageSource messageSource; (works fine)
[...]
}
But when I try to inject messagSource in model classes it failes:
package net.local.mis.phog.model;
#Component
public class AlbumModel {
[...]
#Autowired
private MessageSource messageSource; (null)
[...]
}
In spring - component autowired in one class but not in another Balaji Krishnan says: "You are not using spring to obtain Account instance - so spring did not get a chance to autowire it". Perhaps I should do something of the kind, but I cannot understand how.
Can anybody please help me.
Thank you, Mikhail.
For spring to leverage dependency injection, the beans must all be managed by spring. The AlbumModel object creation should be managed by spring, so that the MessageSource can be autowired. If AlbumModel should not be managed by spring and you want to create the object yourself (which I doubt because you annotated it with #Component) then you could also use constructor injection.
Whereas you can have something like this:
package net.local.mis.phog.model;
#Component
public class AlbumModel {
[...]
private MessageSource messageSource;
[...]
#Autowired
public AlbumModel(MessageSource messageSource) {
this.messageSource = messageSource;
}
}
With the solution above, when you manually create an AlbumModel, you could pass in the MessageSource object, which is already autowired by the calling class (for example the controller or any service layer class). But also when AlbumModel creation is manage by spring it is advisable to use constructor injection. Read more about it on an article by a Spring contributor
Thank you guys for your answers.
Amit Bera, I create AlbumModel object just by calling its constructor:
package net.local.mis.phog.controller;
#Controller
#Transactional
public class AlbumController {
[...]
#Autowired
private JenreDao jenreDao;
#Autowired
private MessageSource messageSource;
[...]
#RequestMapping(value={"/album"},method=RequestMethod.GET)
public String albumShowHandler(Model model,
HttpServletRequest request,
#RequestParam(value="jenreIdSelected") Long jenreIdSelected,
#CookieValue(value="thumbnailOrder",defaultValue="ordDefault") String thumbnailOrder,
[...]) {
[...]
ThumbnailOrderAux thumbnailOrderAux = new ThumbnailOrderAux(thumbnailOrder);
JenreAux jenreAux = new JenreAux(jenreDao.getLstJenreModel(null,jenreIdSelected),jenreIdSelected);
AlbumModel albumModel = new AlbumModel(jenreAux,thumbnailOrderAux);
[...]
model.addAttribute("albumModel",albumModel);
return "album";
}
[...]
}
And here is code of AdminModel constructors:
package net.local.mis.phog.model;
#Component
public class AlbumModel {
private JenreAux jenreAux;
private ThumbnailAux thumbnailAux;
[...]
public AlbumModel() {
super();
}
public AlbumModel(JenreAux jenreAux,ThumbnailOrderAux thumbnailOrderAux) {
super();
this.jenreAux = jenreAux;
this.thumbnailOrderAux = thumbnailOrderAux;
}
[...]
}
Nazeem, I added #Component annotation to AlbumModel class in hope that MessageSource bean would be injected. Unfortunately it was not.
I could pass MessageSource as argument and it works even if I don't annotate constructor #Autowired. If I understand it right MessageSource bean is injected to AlbumController because it managed by Spring, and it isn't injected to AlbumModel because it doesn't managed by Spring. Right? If so, is there any way I make Spring manage AlbumModel object?
I had the same problem on a spring 3.1.1-RELEASE old application. In my case during debug I've got two different MessageResource objects as if the wold have been instanziated twice.
I've solved moving the bean definition:
<bean id="messageSource"
class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
from dispatcher-servlet.xml xml-based configuration file to the applicationContext.xml ones.
In other words, there exists two contexts: the application context and the dispatcher servlet contexts. The application context is the parent of the dispatcher servlet context (I guess that many servlet contexts may exists under the same application context if your application consists of many servlet).
Thus, beans defined in the application context are visible to the servlet context, but not vice versa. While the servlet context contains those beans that are specifically related to MVC, the application context is used to define broader beans like services.
Since #Controller annotation is a #Component annotated ones:
#Component
public #interface Controller
i guess Spring autowires beans in #Controller and #Component differently, looking for beans in the two different contexts mentioned above.

Spring Boot: #Autowired is not working for one of the class

I am developing OAuth implementation with Jwt tokens.
It's kind of weird but for class TokenAuthenticationService When I try to Autowired this class in a different package, I get
Consider defining a bean of type 'com.company.security.TokenAuthenticationService' in your configuration.
I did a workaround and added #Bean TokenAuthenticationService in that class.Now when I am trying to initialize an interface in the TokenAuthenticationService class, it gives the same type of error for that interface.
Consider defining a bean of type 'com.company.security.UserService' in your configuration.
ComponentScan annotation is configured like #ComponentScan({"com.company"})
What I am missing here and why?
You have two ways to define beans for autowiring in your project.
With classes defined by you, you can use the #Component annotation (or, for service classes, #Service annotation) this way:
#Service
public class TokenAuthenticationService { ... }
If you are using third party classes, you can configure them in a configuration class:
#Configuration
public MyProjectConfig {
#Bean
public ThirdPartyClass serviceClass() { new ThirdPartyClass(); }
}
(Using #Bean annotation is not a workround. You just need to understand its purpose...)
This way autowiring should work...
Pay attention to difference between #Component and #Bean annotations.

Does Spring automatically Autowire constructor args in java bean definitions?

Let's say I have the following bean definitions
#Bean
public Beehive beehive(ArrayList<Bee> bees) {
return new Beehive(bees);
}
#Bean
public ArrayList<Bee> bees() {
return new ArrayList<Bee>();
}
Would the bees in the beehive bean method be Autowired in?
I am asking because I have an application that is behaving like this without using the #Autowired annotation, and want be make sure I understand what's going on.
Does Spring automatically Autowire constructor args in java bean definitions?
Yes, it does. You can refer here from the Spring doc which I have added below (emphasis mine).
A #Bean annotated method can have an arbitrary number of parameters
describing the dependencies required to build that bean. For instance
if our TransferService requires an AccountRepository we can
materialize that dependency via a method parameter:
#Configuration
public class AppConfig {
#Bean
public TransferService transferService(AccountRepository accountRepository) {
return new TransferServiceImpl(accountRepository);
}
}
The resolution mechanism is pretty much identical to constructor-based
dependency injection.

Categories