[Spring]: Java Annotation

spring

09/11/2019


Methods to create a spring container

  1. Full XML Config
  2. Java Annotation (Partial XML; scanning)
  3. 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
    1. Constructor Injection
    2. Setter Injection (method injection)
    3. 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
@Configuration
public class PlayerConfig {
}

@ComponentScan(optional)

  • Add component scanning support
JAVA
@Configuration
@ComponentScan("com.ellismin") // package to scan
public 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
@Componenet
public class BasketballPlayer implements Player {}
  • The default bean name will set to basketballPlayer then it will be called with
    JAVA
    Player 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
@Component
public 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 injection
playing basketball
Today 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
@Component
public 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
ellis.email=[email protected]

In Java code

JAVA
public class BasketballPlayer implements Player {
private Weather weather;
@Value("${john.email}")
private String email;
public BasketballPlayer(Weather weather) { }
//...
}

@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
@Component
public 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

WRITTEN BY

Keeping a record