Why #Autowired wires by class? - java

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.

Related

How to restrict Injection of Conditional beans which are not created based on #ConditionalOnProperty

In JavaConfig I have defined Conditional Beans using #ConditionalOnProperty like below, so that when couchbase.multiBucket.t1CBProvider is defined in property file then only bean t1CBProvider will be created.
#Bean("t1CBProvider")
#ConditionalOnProperty(prefix = "couchbase.multiBucket", name = "t1CBProvider")
public ICouchbaseDTOProvider provider() {
return new CouchbaseDTOProvider("t1CBProvider");
}
now in one of the Java class ArchiveRepo I have Injected the class as below, so that I can use this. There are various other Bean Injections & Methods are defined in ArchiveRepo class,so I need it even if CouchbaseDTOProvider is not created by JavaConfig.
public class ArchiveRepo{
.
#Inject
#Qualifier("t1CBProvider")
private ICouchbaseDTOProvider t1CBProvider;
...
Now, if couchbase.multiBucket.t1CBProvider value not defined in properties file bean CouchbaseDTOProvider will not be created and we will get No Such Bean Found Exception. How can we restrict the dependency injection of ICouchbaseDTOProvider in such a way that, if bean is not created dependency injection on bean is also restricted or made in-effective and we dont have any issue while creating an object of 'ArchiveRepo` class.
You can either do #Autowired(required = false) as one suggested in the comment or define this variable with optional as you can see below:
public class ArchiveRepo{
.
#Inject
#Qualifier("t1CBProvider")
private optional<ICouchbaseDTOProvider> t1CBProvider;
...

Spring autowire by name with #ComponentScan but without #Autowired on property

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.

Can I instantiate bean programmatically in Spring?

Suppose I have an instance of Class<?> and I am already in Spring. Can I instantiate a bean for Spring in this situation?
I want to simulate situation as if I had the following bean definition:
#Bean
MyClass myBean() {
return new MyClass();
}
i.e. only call no-arg constructor and autowire dependencies.
Is this possible?
Probably this is somehow related with programmatic creation of bean definitions.
This is modification of the following question: Can I inject properties to third-party beans?
UPDATE
I used
bean = getApplicationContext().getAutowireCapableBeanFactory().createBean(klass);
and for now it is apparently working.
Is this correct?

How it work the Spring #Autowired annotation on a constructor?

I am studying Spring framework and I have the following doubt related the #Autowired annotation on the constructor of this example:
#Component
public class TransferServiceImpl implements TransferService {
#Autowired
public TransferServiceImpl(AccountRepository repo) {
this.accountRepository = repo;
}
}
So what exactly mean? That the AccountRepository repo object (definied as a component somewhere) is automatically injected into the TransferServiceImpl() constructor?
How it work this operation? Is it done by type? (because AccountRepository is a singleton for Spring default), or what?
Tnx
Spring will look for the AccountRepository bean in the container. There are multiple possible scenarios:
1- There are zero beans with the type AccountRepository. An exception will be thrown.
2- There is one bean with the type AccountRepository. The bean will be injected when TransferServiceImpl is constructed.
3- There are more than one bean with the type AccountRepository:
Fallback to the bean name. In this case, Spring will look for a bean of type AccountRepository with name repo. If a match is found, it will be injected.
The name fallback fails (multiple beans with the same type and name). An exception will be thrown.
With #Component you tell the scan process that this class is a bean, with #autowire you tell the post processor to search through the spring repository for a bean of type AccountRepository. If the bean is found, it will be used with the annotated constructor. Based on the scope, a new instance will be used (prototype) or an already instanciated bean will be passed (singleton). If in anyway there are two beans matching the constructor argument, an exception will be thrown.

How can I provide a default bean implementation in Spring MVC with xml configuration?

I'm working on some old code base and it's using xml configuration.
Basically it has a basic controller named BaseController and all other controllers inherit that. Now I need to add an extra service bean which all current controllers need to use. The bean definition is like this:
<bean id="myService" class="com.myweb.MyService" scope="singleton"/>
The base controller will also have a field named MyService myService, with a null value now.
Instead of setting the property name in the xml file under each existing controller bean mapping (there are too many), how can I set the singleton MyService instance to all controllers at runtime (like a default value instead of null)?
You can autowire the bean.
Annotate your BaseController MyService field with
#Autowired
private MyService myService;

Categories