We can autowire by field, setter, constructor. But we can also define beans only in configuration class and not use autowire at all. What are advanatages of doing so? example config :
#Configuration
class DrawingConfiguration {
#Bean
DrawingFacade drawingFacade(DrawingRepository repository) {
DrawingFactory factory = new DrawingFactory();
return new DrawingFacade(repository, factory);
}
}
If you define a bean in a configuration file you still need to autowire it, but you don't need to annotate it with #Component/#Service/#Repository annotation. It is just way to say that this bean is a #Component.
Related
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();
}
}
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.
Just migrating from xml based config to java based config in Spring 4.3.
In xml we had
<beans ... default-autowire="byName">
<component-scan .../>
...
</beans>
On Java classes we have no #Autowired annotations on fields:
#Component
public class MyService {
private OtherService otherService;
// +setters
....
}
Previously in xml With the default-autowire="byName" autowiring worked pretty well.
Now when moving to JavaConfig I cannot find a way to enable the default autowire mechanism for component scanning.
With autowire by name the wiring works without a #Autowired annotation.
With #Bean(autowire=BY_NAME) i can define a bean to autowire by name, but I would need that mechanism for component scanning. Not to define all beans with #Bean factory method.
Also I try not to add #Autowired annotations to all fields across all classes. Thats just too much to change.
My question now is: How to tell component-scan to autowire found beans by name?
I don't know if I understand what you want to do, but Spring supports #Qualifier and #Resource annotations:
#Resource takes a name attribute, and by default Spring interprets that value as the bean name to be injected. In other words, it follows by-name semantics
One solution would be to update the bean definition with a BeanFactoryPostProcessor to mark all beans to autowire by name like:
public class AutowireScannedByNameBeanPostProcessor implements BeanFactoryPostProcessor {
#Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
Arrays.stream(beanFactory.getBeanDefinitionNames()).forEach(name -> {
BeanDefinition beanDefinition = beanFactory.getBeanDefinition(name);
if (beanDefinition instanceof ScannedGenericBeanDefinition) {
((ScannedGenericBeanDefinition) beanDefinition).setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_NAME);
}
});
}
}
I am still curious if there is a setting in spring that can do this.
I have a Spring Configuration class that looks like:
#Configuration
public class MyDependencyConfig {
#Bean
#Primary
public MyDependency getMyDependency(){
System.out.println("getMyDependency");
return Mockito.mock(MyDependency.class);
}
#Bean
public MyDependency getMyDependency2(){
System.out.println("getMyDependency2");
return Mockito.mock(MyDependency.class);
}
}
And have elsewhere in my code:
#Autowired
MyDependency foo
Why is it when the application context starts up, my console prints
getMyDependency
getMyDependency2
when only the bean from getMyDependency() will be used? I am using spring boot-1.5.1.RELEASE
Thank you kindly,
Jason
The Spring configuration instantiates and loads all declared and required beans in the Spring container at the startup of the Spring context.
So, even if you don't use all beans defined in your configuration, the methods annotated #Bean in your configuration will be all invoked.
The #Primary annotation has another goal.
It indicates that a bean should be given preference when multiple
candidates are qualified to autowire a single-valued dependency. If
exactly one 'primary' bean exists among the candidates, it will be the
autowired value.
It is just a way to not specify systematically the #Qualifier annotation when you have more than one candidate bean.
For example in your case as one of two beans is specified as primary :
#Bean
#Primary
public MyDependency getMyDependency(){
System.out.println("getMyDependency");
return Mockito.mock(MyDependency.class);
}
You don't need to specify the qualifier "getMyDependency" to inject which one specified as primary :
#Autowired
#Qualifier("getMyDependency")
MyDependency foo;
You can directly do that :
#Autowired
MyDependency foo;
While for the second one bean that is not specified as #Primary :
#Bean
public MyDependency getMyDependency2(){
System.out.println("getMyDependency2");
return Mockito.mock(MyDependency.class);
}
You have to specify #Qualifier to clear ambiguities when you want to inject it :
#Autowired
#Qualifier("getMyDependency2")
MyDependency foo;
Loading beans in a lazy way is not advised as it delays the catch of configuration errors. So, it is eager by default.
You have more details in the link provided in your comment.
Now, if you want to prevent this default behavior and define a lazy initialization for a bean, you can alternatively specify the lazy String value in the #Scope annotation of the bean :
#Bean
#Scope("lazy")
public MyDependency getMyDependency(){
...
}
or better you can annotate the bean declaration or all the configuration (if you want that all beans be lazy initialized) with a #Lazy annotation.
For a specific bean :
#Bean
#Lazy
public MyDependency getMyDependency(){
...
}
For all beans of the configuration :
#Lazy
#Configuration
public class MyDependencyConfig {
...
}
If each bean has name, and we have getBean() method, which receives bean name and in XML config we are also injecting beans by name, then why in Java config we are limited to #Autowired annotation which wires by class?
What is conventional way to inject beans into one configuration from another one? Is it possible to refer bean by name and not use #Qualifier?
UPDATE
I found a way to autowire by name between configurations.
First I autowire entire configuration by class:
#Autowired
MySeparateConfig mySeparateConfig;
Then I just call instantiation method from that bean:
#Bean
MyDependentBean myDependentBean() {
MyDependentBean ans = new MyDependentBean();
ans.setProperty( mySeparateConfig.myNamedBeanInDifferentConfig() );
return ans;
}
Configs are of different classes by definition.
Actually, there are several ways to inject bean by annotation.
given that we have this bean
<bean id="standardPasswordEncoder" class="org.springframework.security.crypto.password.StandardPasswordEncoder" />
and in java class we can use following ways to inject it as far as I know
#Autowired // by type
StandardPasswordEncoder standardPasswordEncoder;
#Autowired
#Qualifier("standardPasswordEncoder") // by bean id
StandardPasswordEncoder standardPasswordEncoder;
javax.annotation.#Resource // by bean id
StandardPasswordEncoder standardPasswordEncoder;
javax.inject.#Inject // by type
StandardPasswordEncoder standardPasswordEncoder;
or use spEL
#Value(#{standardPasswordEncoder}) // by bean id
StandardPasswordEncoder standardPasswordEncoder;
However, I don't know the reason why spring autowired default is by type, either, and also wondering why. I think it's dangerous to autowire by type. Hope this would help you.