Does Spring automatically Autowire constructor args in java bean definitions? - java

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.

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();
}
}

Spring why #MockBean can't autowire an interface using profile

I've an interface with two implementations. Which implementaton is to be used depends of the environment (production, development, test, ...). I therefore use Spring profiles. I'm using a configuration file to instantiate the correct implementation.
#Configuration
public class BeanConfiguration {
#Profile({"develop","test-unit"})
#Bean(name = "customerEmailSender")
public CustomerEmailSender emailSenderImpl_1(){
return new EmailSenderImpl_1();
}
#Profile({"prod"})
#Bean(name = "customerEmailSender")
public CustomerEmailSender emailSenderImpl_2(){
return new EmailSenderImpl_2();
}
}
When the Spring container starts (with a specific profile), the correct bean is autowired into the class, and all works fine.
#Component
public class CustomerEmailProcessor {
#Autowire
private CustomerEmailSender customerEmailSender;
...
}
I also have a test class in which I want to autowire the bean. I'm using #Mock for autowiring.
The profile is set to "test-unit" in the test class. So, I'm expecting the spring container to lookup in the config class for the correct bean to be instantiated. But this doesn't happen.
Instead, an Exception is thrown :
Caused by: java.lang.IllegalStateException: Unable to register mock bean .... expected a single matching bean to replace but found [customerEmailSender, emailSenderImpl_1, emailSenderImpl_2]
When using #Autowire annotation, all goes fine. But of course the bean is not mocked anymore and that's what I need to have.
#RunWith(SpringRunner.class)
#ActiveProfiles(profiles = {"test-unit"})
#Import(BeanConfiguration.class)
public class CustomerEmailResourceTest {
#MockBean
private CustomerEmailSender customerEmailSender;
}
I've put a breakpoint in the config class, and I can see that when using #Autowire in the test class, the correct bean is instantiated (breaks at the line "return new EmailSenderImpl_1();".
When using #Mock, no bean at all is instantiated. Spring doesn't break at the line "return new EmailSenderImpl_1();"
Why is it that Spring can find the correct bean when using the #Mock annotation.
The #Mock annotation must be the reason that Spring doesn't use the config class "BeanConfiguration.java". That makes sence after all.

A method with #Bean autowires without #Autowired

In my Java Config file there is
#Bean
public CDPlayer cdPlayer(CompactDisc compactDisc){
return new CDPlayer(compactDisc);
}
My book says that the (singleton) CompactDisc is autowired into the method. Why? Because I do not see #Autowired. How can this work?
About #Bean in Spring
A #Bean annotated method can have an arbitrary number of parameters describing the dependencies required to build that bean
The resolution mechanism is pretty much identical to constructor-based dependency injection, see the relevant section for more details.
Every parameter in a #Bean method will be resolved (injected by Spring container).

Spring autowire list without merging all possible beans

I'm using 4.2.0 spring.
I create two beans:
#Bean
public String sessionAttributeName() {
return "someString";
}
#Bean
public List<String> urlsRequireAuthentication() {
return Lists.newArrayList(
"/auction/*"
);
}
When I try to autowire a list of beans like this:
#Bean
public FilterRegistrationBean someFilterRegistrationBean(List<String> urlsRequireAuthentication) {
...
}
Not only the original list will be autowired as expected ["/auction/*"] but all registered String beans will be merged to one big list like ["/auction/*", "someString"].
I used this feature back in the time and it was useful but for this particular place I really want to only include the content of the urlsRequireAuthentication list. How can I do that?
Just use the method directly instead of injecting the bean as a parameter :
#Bean
public FilterRegistrationBean someFilterRegistrationBean() {
List<String> urlsRequireAuthentication = urlsRequireAuthentication();
}
#Beans documentation :
Typically, #Bean methods are declared within #Configuration classes.
In this case, bean methods may reference other #Bean methods in the
same class by calling them directly. This ensures that references
between beans are strongly typed and navigable. Such so-called
'inter-bean references' are guaranteed to respect scoping and AOP
semantics, just like getBean() lookups would. These are the semantics
known from the original 'Spring JavaConfig' project which require
CGLIB subclassing of each such configuration class at runtime. As a
consequence, #Configuration classes and their factory methods must not
be marked as final or private in this mode. For example:
UPDATE
An other way to do it would be to use the javax #Resource annotation. It does not work with the #Qualifier annotation precisely because of this feature of #Autowired : It is possible to provide all beans of a particular type from the ApplicationContext by adding the annotation to a field or method that expects an array of that type) :
#Configuration
public class ConfigurationClass {
#Resource(name="urlsRequireAuthentication")
private List<String> urlsRequireAuthentication;
#Bean
public FilterRegistrationBean someFilterRegistrationBean() {
urlsRequireAuthentication.size();
}
}
sessionAttributeName and urlsRequireAuthentication should be configuration properties and not beans. Create application.properties in the resources dir and add the following line authentication-urls = /auction/*, /url2/*. Now you can access your properties using the #Value annotation.
#Configuration
#PropertySource("classpath:application.properties")
public class AppConfig {
#Bean
public FilterRegistrationBean someFilterRegistrationBean(#Value("${authentication-urls}") String[] authenticationUrls) {
...
}
}
If you are using spring boot you should check out the docs for externalized configuration.
Use Qualifier annotation:
#Bean
public FilterRegistrationBean someFilterRegistrationBean(#Qualifier("urlsRequireAuthentication") List<String> urlsRequireAuthentication) {
...
}

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

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());
}

Categories