[Spring]: Java Annotation
spring
09/11/2019
Methods to create a spring container
- Full XML Config
- Java Annotation (Partial XML; scanning)
- Java Configuration Class (No XML needed)
Java Annotation (with XML scanning)
- Java annotation is a more preferred than xml only configuration; fully xml config is used for legacy
- Uses xml file to scan the annotations in the sourcecode such as @Component, @Autowired, @Qualifier, etc
- With Java annotations, we don't need to define beans in the xml file anymore but to notate in the source code
- 3 different ways to notate in java code
- Constructor Injection
- Setter Injection (method injection)
- Field Injection
- Different types of injetions achieve the same goal. It is a debatable topic to pick better one than another
- Just remember to be consistent about which injection to use throught the project
Changes in xml file to enable componenet scanning
XML
<?xml version="1.0" encoding="UFT-8"?><beans...> <!-- Scan the source code --> <context:component-scan base-package="packageName"/></beans...>
- Besides import, we just need to add one line of code to scan the source code:
XML
<context:component-scan base-package="packageName"/>
- Spring will can the package, recursively
@Configuration
Create a Java class and annotate as @Configuration
JAVA
@Configurationpublic class PlayerConfig {
}
@ComponentScan(optional)
- Add component scanning support
JAVA
@Configuration@ComponentScan("com.ellismin") // package to scanpublic class PlayerConfig {
}
@Componenet
- Component can be added above class, method, or field that are for Constructor injection, method injection, and field injection respectively
Using annotation above class name
JAVA
// Register this Spring bean automatically with bean id, theBean@Componenet("theBean")public class BasketballPlayer implements Player {
}
- This registered bean can be retrived in main method with the following:
JAVA
Player player = context.getBean("theBean", Player.class);
- Whole main method:
JAVA
public class AnnotationDemo { public static void main(String[] args) { // Read spring config file ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("fileName.xml");
// get the bean from spring container Player player = context.getBean("theBean", Player.class);
// call a method on the bean System.out.println(player.getWorkout()); System.out.println(player.getWeather());
// close the context context.close(); }}
- Default componenet name: without specified name, bean id will set to the class name with the first letter in lower case
JAVA
@Componenetpublic class BasketballPlayer implements Player {}
- The default bean name will set to basketballPlayer then it will be called withJAVAPlayer player = context.getBean("basketballPlayer", Player.class)
- Caveat: when first two or more letters are upper case, use the same name as its default. Ex) XMLClass => XMLClass
@Autowired
AutoWiring
- Spring uses auto wiring for dependency injection
- It will look for a class that matches the property (class or interface)
- For example, when injecting Weather into Player interface, Spring will scan @Component's
Example
JAVA
@Componentpublic class BasketballPlayer implements Player { private Weather weather;
@Autowired public BasketballPlayer(Weather weather) { this.weather = weather; }}
- With @Autowired written above constructor, Spring will find a bean that implements Weather. In our example, SunnyWeather meets requirement (code's from Full XML Config)
- This is an exmaple of constructor injection. Setter injection and field injections can be used similarly. But again when choosing one, remember to be consistent
- From Srping 4.3 and above, @Autowired on constructor is set as default without annotation
- However, when there's a multiple constructors, we at least one must be annotated
@Qualifier
What if there are multiple sub-classes that implements the same interface?
- @Qualifer can be used below @Autowired to distinguish a particular sub-class you want to use
- Example
JAVA
@Autowired@Qualifier("SunnyWeather")
Setter injection
Similar to Constructor injection, we just need to put @Autowired above a setter method
JAVA
public class BasketballPlayer implements Player { private Weather weather; public BasketballPlayer() { System.out.prntln(">> BasketballPlayer: Inside the constructor"); } @Autowired public void setWeather(Weather weather) { System.out.prntln(">> BasketballPlayer: Inside setWeather()"); this.weather = weather; }}
- Expected output:
BASH
>> BasketballPlayer: Inside the constructor>> BasketballPlayer: Inside setWeather() //@Autowired for setter injectionplaying basketballToday will be sunny all day!
- Note: the method name setWeather(Weather weather) can be anything as long as @Autowired is included above the method. For example, below code is also accepted setter injection:
JAVA
@Autowired public void doSomestuff(Weather weather){ }
Field injection
Similar to constructor injection and setter injection, field injection is applied directly to the field. There is no need for setter methods
Example
JAVA
@Componentpublic class BasketballPlayer implements Player { @Autowired private Weather weather; public BasketballPlayer(Weather weather){ } // Setter method is NOT needed // ...}
@Value
Using @Value you can inject properties file w/ Java annotations. Create a property file and add a line of code in xml file (same process done in Full XML Config)
In XML file
XML
<?xml version=1.0 encoding="UTF-8"?><beans...><!-- Load properties file: emailList.properties --> <context:property-placeholder location="classpath:emailList.properties" /></beans...>
emailList.properties in source directory
BASH
In Java code
JAVA
public class BasketballPlayer implements Player { private Weather weather; @Value("${john.email}") private String email;
public BasketballPlayer(Weather weather) { } //...}
- Here, email will set to [email protected] which is read from emailList.properties
@Scope
Particular scope can be added with @Scope("scopeName") annotation
JAVA
@Component@Scope("prototype")public class BasketballPlayer implements Player{ ...}
@PostConstruct, @PreDestroy
@PostConstruct and @PreDestroy can be use to annotate init and destroy methods
JAVA
@Componentpublic class BasketballPlayer implements Player { ... @PostConstruct public void doStartUp(){...} @PreDestroy public void doCleanUP(){...}}
- Method can have any access modifier (public, protected, private)
- Method can have any return type, but void is most commonly used since we won't be able to capture the reutrn value
- Method cannot have any arguments
- Again, prototype does not call destroy method
- Java 9, 10, 11 users will encounter errors--can be resolved by adding javax.annotation-api-1.2.jar to lib folder of the project