Introduction to Spring Core with Annotations.

Dasari Swaroop Kumar
6 min readDec 12, 2020

In this quick article, we will discuss Spring core annotations that are used in Spring DI and Spring IOC. As we know Spring DI and Spring IOC are core concepts of Spring Framework. These Spring core annotations we will explore from org.springframework.beans.factory.annotation and org.springframework.context.annotation packages.

Before starting let’s see exactly what the concept of IoC is,

IoC is also known as dependency injection (DI). It is a process whereby objects define their dependencies (that is, the other objects they work with) only through constructor arguments, arguments to a factory method, or properties that are set on the object instance after it is constructed or returned from a factory method. The container then injects those dependencies when it creates the bean. This process is fundamentally the inverse (hence the name, Inversion of Control) of the bean itself controlling the instantiation or location of its dependencies by using direct construction of classes.

Now, Let’s dive into Spring Core Annotations!

@Autowired

We can use the @Autowired to mark a dependency which Spring is going to resolve and inject. We can use this annotation with a constructor, setter, or field injection.

Constructor Injection:

@RestController
public class CustomerController {
private CustomerService customerService;

@Autowired
public CustomerController(CustomerService customerService) {
this.customerService = customerService;
}
}

Setter Injection:

@RestController
public class CustomerController {
private CustomerService customerService;

@Autowired
public void setCustomerService(CustomerService customerService) {
this.customerService = customerService;
}
}

Field Injection:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class CustomerController {
@Autowired
private CustomerService customerService;
}

@Bean

@Bean is a method-level annotation and a direct analog of the XML element. The annotation supports some of the attributes offered by, such as init-method, destroy-method, autowiring, and name.

You can use the @Bean annotation or in a @Component annotated class.

The following is a simple example of a @Bean method declaration:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.companyname.projectname.customer.CustomerService;
import com.companyname.projectname.order.OrderService;
@Configuration
public class Application {
@Bean
public CustomerService customerService() {
return new CustomerService();
}
@Bean
public OrderService orderService() {
return new OrderService();
}
}

The preceding configuration is exactly equivalent to the following Spring XML:

<beans>
<bean id="customerService" class="com.companyname.projectname.CustomerService"/>
<bean id="orderService" class="com.companyname.projectname.OrderService"/>
</beans>

@Qualifier

This annotation helps fine-tune annotation-based autowiring. There may be scenarios when we create more than one bean of the same type and want to wire only one of them with a property. This can be controlled using @Qualifier annotation along with the @Autowired annotation.

Example: Consider EmailService and SMSService classes implement a single MessageService interface.

Create a MessageService interface for multiple message service implementations.

public interface MessageService {
public void sendMsg(String message);
}

Create implementations — EmailService and SmsService.

public class EmailService implements MessageService{    public void sendMsg(String message) {
System.out.println(message);
}
}
public class SmsService implements MessageService{ public void sendMsg(String message) {
System.out.println(message);
}
}

It’s time to see the usage of @Qualifier annotation.

public interface MessageProcessor {
public void processMsg(String message);
}
public class MessageProcessorImpl implements MessageProcessor { private MessageService messageService; // setter based DI
@Autowired
@Qualifier("emailService")
public void setMessageService(MessageService messageService) {
this.messageService = messageService;
}

// constructor based DI
@Autowired
public MessageProcessorImpl(@Qualifier("emailService") MessageService messageService) {
this.messageService = messageService;
}

public void processMsg(String message) {
messageService.sendMsg(message);
}
}

@Required

The @Required annotation is method-level annotation and applied to the setter method of a bean.

This annotation simply indicates that the setter method must be configured to be dependency-injected with a value at configuration time.

For example, @Required on setter methods to mark dependencies that we want to populate through XML:

@Required
void setColor(String color) {
this.color = color;
}
<bean class="com.javaguides.spring.Car">
<property name="color" value="green" />
</bean>

Otherwise, BeanInitializationException will be thrown.

@Value

Spring @Value annotation is used to assign default values to variables and method arguments. We can read spring environment variables as well as system variables using @Value annotation.

Spring @Value annotation also supports SpEL. Let’s look at some of the examples of using @Value annotation.

Examples:

We can assign a default value to a class property using @Value annotation.

@Value("Default DBConfiguration")
private String defaultName;

@Value annotation argument can be a string only, but spring tries to convert it to the specified type. The below code will work fine and assign the boolean and integer values to the variable.

@Value("true")
private boolean defaultBoolean;
@Value("10")
private int defaultInt;

Spring @Value — Spring Environment Property

@Value("${APP_NAME_NOT_FOUND}")
private String defaultAppName;

Assign system variables using @Value annotation.

@Value("${java.home}")
private String javaHome;

@Value("${HOME}")
private String homeDir;

Spring @Value — SpEL

@Value("#{systemProperties['java.home']}")
private String javaHome;

@DependsOn

The @DependsOn annotation can force the Spring IoC container to initialize one or more beans before the bean which is annotated by @DependsOn annotation.

The @DependsOn annotation may be used on any class directly or indirectly annotated with @Component or on methods annotated with @Bean.

Example: Let’s create FirstBean and SecondBean classes. In this example, the SecondBean is initialized before the bean FirstBean.

public class FirstBean {    @Autowired
private SecondBean secondBean;
}
public class SecondBean {
public SecondBean() {
System.out.println("SecondBean Initialized via Constuctor");
}
}

Declare the above beans in java based configuration class.

@Configuration
public class AppConfig {
@Bean("firstBean")
@DependsOn(value = {
"secondBean"
})
public FirstBean firstBean() {
return new FirstBean();
}
@Bean("secondBean")
public SecondBean secondBean() {
return new SecondBean();
}
}

@Lazy

By default, the Spring IOC container creates and initializes all singleton beans at the time of application startup. We can prevent this pre-initialization of a singleton bean by using the @Lazy annotation.

The @Lazy annotation may be used on any class directly or indirectly annotated with @Component or on methods annotated with @Bean.

Example: Consider we have below two beans — FirstBean and SecondBean. In this example, we will explicitly load FirstBean using @Lazy annotation.

public class FirstBean {
public void test() {
System.out.println("Method of FirstBean Class");
}
}
public class SecondBean {
public void test() {
System.out.println("Method of SecondBean Class");
}
}

Declare the above beans in java based configuration class.

@Configuration
public class AppConfig {
@Lazy(value = true)
@Bean
public FirstBean firstBean() {
return new FirstBean();
}
@Bean
public SecondBean secondBean() {
return new SecondBean();
}
}

As we can see, bean secondBean is initialized by Spring container while bean firstBean is initialized explicitly.

@Lookup

A method annotated with @Lookup tells Spring to return an instance of the method’s return type when we invoke it.

@Primary

We use @Primary to give higher preference to a bean when there are multiple beans of the same type.

@Component
@Primary
class Car implements Vehicle {}

@Component
class Bike implements Vehicle {}

@Component
class Driver {
@Autowired
Vehicle vehicle;
}

@Component
class Biker {
@Autowired
@Qualifier("bike")
Vehicle vehicle;
}

@Scope

We use @Scope to define the scope of a @Component class or a @Bean definition. It can be either singleton, prototype, request, session, globalSession, or some custom scope.

For example:

@Component
@Scope(value = ConfigurableBeanFactory.SCOPE_SINGLETON)
public class TwitterMessageService implements MessageService {
}
@Component
@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class TwitterMessageService implements MessageService {
}

@Profile

If we want Spring to use a @Component class or a @Bean method only when a specific profile is active, we can mark it with @Profile. We can configure the name of the profile with the value argument of the annotation:

@Component
@Profile("sportDay")
class Bike implements Vehicle {}

@Import

The @Import annotation indicates one or more @Configuration classes to import.

For example: In a Java-based configuration, Spring provides the @Import annotation which allows for loading @Bean definitions from another configuration class.

@Configuration
public class ConfigA {
@Bean
public A a() {
return new A();
}
}
@Configuration
@Import(ConfigA.class)
public class ConfigB {
@Bean
public B b() {
return new B();
}
}

Now, rather than needing to specify both ConfigA class and ConfigB class when instantiating the context, only ConfigB needs to be supplied explicitly.

@ImportResource

Spring provides a @ImportResource annotation is used to load beans from an applicationContext.xml file into an ApplicationContext.

Example: Consider we have applicationContext.xml spring bean configuration XML file on the classpath.

@Configuration
@ImportResource({"classpath*:applicationContext.xml"})
public class XmlConfiguration {
}

@PropertySource

The @PropertySource annotation provides a convenient and declarative mechanism for adding a PropertySource to Spring’s Environment. To be used in conjunction with @Configuration classes.

For example: In this example, we are reading database configuration from the file config.properties file and set these property values to DataSourceConfig class using Environment.

import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
@Configuration
@PropertySource("classpath:config.properties")
public class ProperySourceDemo implements InitializingBean {
@Autowired
Environment env;
@Override
public void afterPropertiesSet() throws Exception {
setDatabaseConfig();
}
private void setDatabaseConfig() {
DataSourceConfig config = new DataSourceConfig();
config.setDriver(env.getProperty("jdbc.driver"));
config.setUrl(env.getProperty("jdbc.url"));
config.setUsername(env.getProperty("jdbc.username"));
config.setPassword(env.getProperty("jdbc.password"));
System.out.println(config.toString());
}
}

@PropertySources

We can use this annotation to specify multiple @PropertySource configurations:

@PropertySources({
@PropertySource("classpath:config.properties"),
@PropertySource("classpath:db.properties")
})
public class AppConfig {
//...
}

--

--