In Spring Autowiring Using @Autowired Annotation we have already seen how container can automatically resolve collaboration among beans (bean dependencies) by annotating the dependencies with @Autowired annotation. As an alternative you can use @Inject annotation for autowiring in Spring.
@Inject and @Named annotations in Spring
Spring 3.0 added support for JSR-330 (Dependency Injection for Java) annotations contained in the javax.inject
package such as @Inject and @Named.
- @Inject is used for autorwiring, it gives you a chance to use standard annotations rather than Spring specific annotation like @Autowired.
- @Named annotation is used for conflict resolution if there are multiple candidates of the same type.
To use these annotations javax.inject library is needed, Maven dependency for the same is as follows.
<dependency> <groupId>javax.inject</groupId> <artifactId>javax.inject</artifactId> <version>1</version> </dependency>
Using @Inject annotation
- You can apply the @Inject annotation to constructors.
- You can apply the @Inject annotation to setter methods.
- You can apply @Inject to fields.
We’ll see examples of @Inject annotation using all the above options.
Using @Inject annotation on setter
@Inject annotation on a setter method is equivalent to autowiring="byType" in autowiring using configuration file.
In the example there is a class to place order called OrderService and purchase can be done from a Store. In OrderService class dependency for store has to be autowired.
public interface OrderService { public void buyItems(); }
import javax.inject.Inject; import org.springframework.stereotype.Service; @Service public class OrderServiceImpl implements OrderService { private IStore store; // Autowiring on Setter @Inject public void setStore(IStore store) { this.store = store; } public void buyItems() { store.doPurchase(); } }
In the class Autowiring on the setter method is done using @Inject annotation.
public interface IStore { public void doPurchase(); }
import org.springframework.stereotype.Service; @Service public class RetailStore implements IStore { public void doPurchase() { System.out.println("Doing purchase from Retail Store"); } }Configuration
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <context:component-scan base-package="com.knpcode.springproject.service" /> </beans>
Since JSR-330 standard annotations are scanned in the same way as the Spring annotations so component-scan is able to scan @Inject and @Named annotations too.
You can use the following class with main method to read the configuration and call the bean method.
public class App { public static void main( String[] args ){ // create context using configuration ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("appcontext.xml"); OrderService order = context.getBean(OrderServiceImpl.class); order.buyItems(); // close the context context.close(); } }Output
17:34:09.769 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'orderServiceImpl' 17:34:09.806 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'retailStore' Doing purchase from Retail Store
Using @Inject annotation on constructor
@Inject annotation on a bean's constructor is equivalent to autowiring="constructor" when autowiring using configuration file.
@Service public class OrderServiceImpl implements OrderService { private IStore store; // Autowiring on constructor @Inject public OrderServiceImpl(IStore store){ this.store = store; } public void buyItems() { store.doPurchase(); } }
Using @Inject annotation on field
@Inject annotation on a field is equivalent to autowiring="byType" in autowiring using configuration file.
@Service public class OrderServiceImpl implements OrderService { // Autowiring on a field @Inject private IStore store; public void buyItems() { store.doPurchase(); } }
@Inject annotation with java.util.Optional or @Nullable
@Inject can also be used with java.util.Optional
or @Nullable
. Since @Inject does not have a required attribute so the
scenario where dependency can not be satisfied under some circumstances has to be taken care of by using either Optional
or @Nullable otherwise UnsatisfiedDependencyException will be thrown at the time of bean creation itself.
For example using @Nullable annotation to declare that annotated elements can be null under some circumstance.
@Service public class OrderServiceImpl implements OrderService { private IStore store; // Autowiring on Setter @Inject public void setStore(@Nullable IStore store) { this.store = store; } public void buyItems() { store.doPurchase(); } }
By using @Nullable bean initialization will be done but later Null pointer excpetion is thrown if the required dependency is not found.
Using Optional to declare that annotated elements can be null under some circumstance.
@Service public class OrderServiceImpl implements OrderService { private IStore store; // Autowiring on Setter @Inject public void setStore(Optional<IStore> store) { if(store.isPresent()) this.store = store.get(); } public void buyItems() { store.doPurchase(); } }
Conflict resolution using @Named with @Inject
Using @Named annotation you can use a qualified name for the dependency that should be injected.
When autowiring by type there may be multiple candidates of the same type in such scenario Spring container won't be able to decide which bean to autowire and throw NoUniqueBeanDefinitionException.
For example if there two stores RetailStore and OnlineStore of type IStore.
@Service public class OnlineStore implements IStore { public void doPurchase() { System.out.println("Doing purchase from Online Store"); } }
Then our example will fail as it won’t be able to determine which store to autowire.
Exception in thread "main" org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'orderServiceImpl': Unsatisfied dependency expressed through method 'setStore' parameter 0; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.knpcode.springproject.service.IStore' available: expected single matching bean but found 2: onlineStore,retailStore
Using @Named annotation for conflict resolution in such scenario by qualifying a bean for autowiring.
@Service public class OrderServiceImpl implements OrderService { private IStore store; @Inject @Named("retailStore") public void setStore(IStore store) { this.store = store; } public void buyItems() { store.doPurchase(); } }
In the class qualified name is used for the dependency that should be injected using @Named annotation
That's all for the topic Spring Autowiring Using @Inject and @Named Annotations. If something is missing or you have something to share about the topic please write a comment.
You may also like
- Spring Autowiring Using @Autowired Annotation
- Spring XML Configuration Example
- CountDownLatch Vs CyclicBarrier in Java
- HashSet Vs LinkedHashSet Vs TreeSet in Java
- Java Variables - Declaration, Initialization And Types
- GZIP Multiple Files in Java Creating Tar Archive
- Exception Propagation in Java
- Data Compression in Hadoop Framework
No comments:
Post a Comment