anitsh / til

Today I Learn (til) - Github `Issues` used as daily learning management system for taking notes and storing resource links.
https://anitshrestha.com.np
MIT License
78 stars 11 forks source link

Spring Annotations #972

Open anitsh opened 2 years ago

anitsh commented 2 years ago

Annotations DI-Related Annotations (Package: org.springframework.beans.factory.annotation Context Configuration Annotations (Package: org.springframework.context.annotation) Spring Web Annotations (Package: org.springframework.web.bind.annotation)

DI-Related Annotations

@Autowired

Marks a dependency which Spring is going to resolve and inject. Use this annotation with a constructor, setter, or field injection.

Constructor Injection: class Car { Engine engine;

@Autowired
Car(Engine engine) {
    this.engine = engine;
}

}

Setter Injection: class Car { Engine engine;

@Autowired
void setEngine(Engine engine) {
    this.engine = engine;
}

}

Field Injection: class Car { @Autowired Engine engine; }

@Autowired has a boolean argument called required with a default value of true. It tunes Spring's behavior when it doesn't find a suitable bean to wire. When true, an exception is thrown, otherwise, nothing is wired.

Note, that if we use constructor injection, all constructor arguments are mandatory.

Starting with version 4.3, we don't need to annotate constructors with @Autowired explicitly unless we declare at least two constructors.

@Bean

@Bean marks a factory method which instantiates a Spring bean:

@Bean Engine engine() { return new Engine(); }

Spring calls these methods when a new instance of the return type is required.

The resulting bean has the same name as the factory method. If we want to name it differently, we can do so with the name or the value arguments of this annotation (the argument value is an alias for the argument name):

@Bean("engine") Engine getEngine() { return new Engine(); } Note, that all methods annotated with @Bean must be in @Configuration classes.

@Qualifier

We use @Qualifier along with @Autowired to provide the bean id or bean name we want to use in ambiguous situations.

For example, the following two beans implement the same interface:

class Bike implements Vehicle {} class Car implements Vehicle {}

If Spring needs to inject a Vehicle bean, it ends up with multiple matching definitions. In such cases, we can provide a bean's name explicitly using the @Qualifier annotation.

Using constructor injection: @Autowired Biker(@Qualifier("bike") Vehicle vehicle) { this.vehicle = vehicle; }

Using setter injection: @Autowired void setVehicle(@Qualifier("bike") Vehicle vehicle) { this.vehicle = vehicle;

}

Alternatively: @Autowired @Qualifier("bike") void setVehicle(Vehicle vehicle) { this.vehicle = vehicle; }

Using field injection: @Autowired @Qualifier("bike") Vehicle vehicle;

@Required

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

@Required void setColor(String color) { this.color = color; }

Otherwise, BeanInitializationException will be thrown.

@Value

We can use @Value for injecting property values into beans. It's compatible with constructor, setter, and field injection.

Constructor injection: Engine(@Value("8") int cylinderCount) { this.cylinderCount = cylinderCount; }

Setter injection: @Autowired void setCylinderCount(@Value("8") int cylinderCount) { this.cylinderCount = cylinderCount; }

Alternatively: @Value("8") void setCylinderCount(int cylinderCount) { this.cylinderCount = cylinderCount; }

Field injection: @Value("8") int cylinderCount;

Injecting static values isn't useful. Therefore, we can use placeholder strings in @Value to wire values defined in external sources, for example, in .properties or .yaml files.

Let's assume the following .properties file: engine.fuelType=petrol

We can inject the value of engine.fuelType with the following: @Value("${engine.fuelType}") String fuelType;

@DependsOn

We can use this annotation to make Spring initialize other beans before the annotated one. Usually, this behavior is automatic, based on the explicit dependencies between beans.

We only need this annotation when the dependencies are implicit, for example, JDBC driver loading or static variable initialization.

We can use @DependsOn on the dependent class specifying the names of the dependency beans. The annotation's value argument needs an array containing the dependency bean names:

@DependsOn("engine") class Car implements Vehicle {}

Alternatively, if we define a bean with the @Bean annotation, the factory method should be annotated with @DependsOn:

@Bean @DependsOn("fuel") Engine engine() { return new Engine(); }

@Lazy

We use @Lazy when we want to initialize our bean lazily. By default, Spring creates all singleton beans eagerly at the startup/bootstrapping of the application context.

However, there are cases when we need to create a bean when we request it, not at application startup.

This annotation behaves differently depending on where we exactly place it. We can put it on:

This annotation has an argument named value with the default value of true. It is useful to override the default behavior.

For example, marking beans to be eagerly loaded when the global setting is lazy, or configure specific @Bean methods to eager loading in a @Configuration class marked with @Lazy:

@Configuration @Lazy class VehicleFactoryConfig {

@Bean
@Lazy(false)
Engine engine() {
    return new Engine();
}

}

@Lookup

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

@Primary

Sometimes we need to define multiple beans of the same type. In these cases, the injection will be unsuccessful because Spring has no clue which bean we need.

We already saw an option to deal with this scenario: marking all the wiring points with @Qualifier and specify the name of the required bean.

However, most of the time we need a specific bean and rarely the others. We can use @Primary to simplify this case: if we mark the most frequently used bean with @Primary it will be chosen on unqualified injection points:

@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; }

In the previous example Car is the primary vehicle. Therefore, in the Driver class, Spring injects a Car bean. Of course, in the Biker bean, the value of the field vehicle will be a Bike object because it's qualified.

@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("prototype") class Engine {}

Context Configuration Annotations

We can configure the application context with the annotations.

@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

We can use specific @Configuration classes without component scanning with this annotation. We can provide those classes with @Import‘s value argument:

@Import(VehiclePartSupplier.class) class VehicleFactoryConfig {}

@ImportResource

We can import XML configurations with this annotation. We can specify the XML file locations with the locations argument, or with its alias, the value argument:

@Configuration @ImportResource("classpath:/annotations.xml") class VehicleFactoryConfig {}

@PropertySource

With this annotation, we can define property files for application settings:

@Configuration @PropertySource("classpath:/annotations.properties") class VehicleFactoryConfig {}

@PropertySource leverages the Java 8 repeating annotations feature, which means we can mark a class with it multiple times:

@Configuration @PropertySource("classpath:/annotations.properties") @PropertySource("classpath:/vehicle-factory.properties") class VehicleFactoryConfig {}

@PropertySources

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

@Configuration @PropertySources({ @PropertySource("classpath:/annotations.properties"), @PropertySource("classpath:/vehicle-factory.properties") }) class VehicleFactoryConfig {}

Note, that since Java 8 we can achieve the same with the repeating annotations feature as described above.

Spring Web Requst Handling

@RequestMapping

@RequestMapping marks request handler methods inside @Controller classes; it can be configured using:

Here's a quick example of what that looks like:

@Controller class VehicleController {

@RequestMapping(value = "/vehicles/home", method = RequestMethod.GET)
String home() {
    return "home";
}

}

We can provide default settings for all handler methods in a @Controller class if we apply this annotation on the class level. The only exception is the URL which Spring won't override with method level settings but appends the two path parts.

For example, the following configuration has the same effect as the one above: @Controller @RequestMapping(value = "/vehicles", method = RequestMethod.GET) class VehicleController {

@RequestMapping("/home")
String home() {
    return "home";
}

}

Moreover, @GetMapping, @PostMapping, @PutMapping, @DeleteMapping, and @PatchMapping are different variants of @RequestMapping with the HTTP method already set to GET, POST, PUT, DELETE, and PATCH respectively.

@RequestBody

Maps the body of the HTTP request to an object:

@PostMapping("/save") void saveVehicle(@RequestBody Vehicle vehicle) { // ... }

The deserialization is automatic and depends on the content type of the request.

@PathVariable

This annotation indicates that a method argument is bound to a URI template variable. We can specify the URI template with the @RequestMapping annotation and bind a method argument to one of the template parts with @PathVariable.

We can achieve this with the name or its alias, the value argument:

@RequestMapping("/{id}") Vehicle getVehicle(@PathVariable("id") long id) { // ... } Copy If the name of the part in the template matches the name of the method argument, we don't have to specify it in the annotation:

@RequestMapping("/{id}") Vehicle getVehicle(@PathVariable long id) { // ... } Copy Moreover, we can mark a path variable optional by setting the argument required to false:

@RequestMapping("/{id}") Vehicle getVehicle(@PathVariable(required = false) long id) { // ... }

@RequestParam

We use @RequestParam for accessing HTTP request parameters:

@RequestMapping Vehicle getVehicleByParam(@RequestParam("id") long id) { // ... }

It has the same configuration options as the @PathVariable annotation.

In addition to those settings, with @RequestParam we can specify an injected value when Spring finds no or empty value in the request. To achieve this, we have to set the defaultValue argument.

Providing a default value implicitly sets required to false:

@RequestMapping("/buy") Car buyCar(@RequestParam(defaultValue = "5") int seatCount) { // ... }

Besides parameters, there are other HTTP request parts we can access: cookies and headers. We can access them with the annotations @CookieValue and @RequestHeader respectively.

We can configure them the same way as @RequestParam.

@ResponseBody

If we mark a request handler method with @ResponseBody, Spring treats the result of the method as the response itself:

@ResponseBody @RequestMapping("/hello") String hello() { return "Hello World!"; }

If we annotate a @Controller class with this annotation, all request handler methods will use it.

@ExceptionHandler

With this annotation, we can declare a custom error handler method. Spring calls this method when a request handler method throws any of the specified exceptions.

The caught exception can be passed to the method as an argument:

@ExceptionHandler(IllegalArgumentException.class) void onIllegalArgumentException(IllegalArgumentException exception) { // ... }

@ResponseStatus

We can specify the desired HTTP status of the response if we annotate a request handler method with this annotation. We can declare the status code with the code argument, or its alias, the value argument.

Also, we can provide a reason using the reason argument.

We also can use it along with @ExceptionHandler:

@ExceptionHandler(IllegalArgumentException.class) @ResponseStatus(HttpStatus.BAD_REQUEST) void onIllegalArgumentException(IllegalArgumentException exception) { // ... }

Some annotations don't manage HTTP requests or responses directly.

@Controller

We can define a Spring MVC controller with @Controller.

@RestController

The @RestController combines @Controller and @ResponseBody.

Therefore, the following declarations are equivalent:

@Controller @ResponseBody class VehicleRestController { // ... }

@RestController class VehicleRestController { // ... }

@ModelAttribute

With this annotation we can access elements that are already in the model of an MVC @Controller, by providing the model key:

@PostMapping("/assemble") void assembleVehicle(@ModelAttribute("vehicle") Vehicle vehicleInModel) { // ... }

Like with @PathVariable and @RequestParam, we don't have to specify the model key if the argument has the same name:

@PostMapping("/assemble") void assembleVehicle(@ModelAttribute Vehicle vehicle) { // ... }

Besides, @ModelAttribute has another use: if we annotate a method with it, Spring will automatically add the method's return value to the model:

@ModelAttribute("vehicle") Vehicle getVehicle() { // ... }

Like before, we don't have to specify the model key, Spring uses the method's name by default:

@ModelAttribute Vehicle vehicle() { // ... }

Before Spring calls a request handler method, it invokes all @ModelAttribute annotated methods in the class.

@CrossOrigin

@CrossOrigin enables cross-domain communication for the annotated request handler methods:

@CrossOrigin @RequestMapping("/hello") String hello() { return "Hello World!"; }

If we mark a class with it, it applies to all request handler methods in it.

We can fine-tune CORS behavior with this annotation's arguments.

Spring Boot Annotations

@SpringBootApplication

We use this annotation to mark the main class of a Spring Boot application:

@SpringBootApplication class VehicleFactoryApplication {

public static void main(String[] args) {
    SpringApplication.run(VehicleFactoryApplication.class, args);
}

}

@SpringBootApplication encapsulates @Configuration, @EnableAutoConfiguration, and @ComponentScan annotations with their default attributes.

@EnableAutoConfiguration

@EnableAutoConfiguration, as its name says, enables auto-configuration. It means that Spring Boot looks for auto-configuration beans on its classpath and automatically applies them.

We have to use this annotation with @Configuration:

@Configuration @EnableAutoConfiguration class VehicleFactoryConfig {}

Auto-Configuration Conditions

Usually, when we write our custom auto-configurations, we want Spring to use them conditionally. We can achieve this with the annotations in this section.

We can place the annotations in this section on @Configuration classes or @Bean methods.

@ConditionalOnClass and @ConditionalOnMissingClass

Using these conditions, Spring will only use the marked auto-configuration bean if the class in the annotation's argument is present/absent:

freestar @Configuration @ConditionalOnClass(DataSource.class) class MySQLAutoconfiguration { //... }

@ConditionalOnBean and @ConditionalOnMissingBean

We can use these annotations when we want to define conditions based on the presence or absence of a specific bean:

@Bean @ConditionalOnBean(name = "dataSource") LocalContainerEntityManagerFactoryBean entityManagerFactory() { // ... }

@ConditionalOnProperty

Make conditions on the values of properties:

@Bean @ConditionalOnProperty( name = "usemysql", havingValue = "local" ) DataSource dataSource() { // ... }

@ConditionalOnResource

Make Spring to use a definition only when a specific resource is present:

@ConditionalOnResource(resources = "classpath:mysql.properties") Properties additionalProperties() { // ... }

@ConditionalOnWebApplication and @ConditionalOnNotWebApplication

Create conditions based on if the current application is or isn't a web application:

@ConditionalOnWebApplication HealthCheckController healthCheckController() { // ... }

@ConditionalExpression

Use this annotation in more complex situations. Spring will use the marked definition when the SpEL expression is evaluated to true: @Bean @ConditionalOnExpression("${usemysql} && ${mysqlserver == 'local'}") DataSource dataSource() { // ... }

@Conditional

For even more complex conditions, we can create a class evaluating the custom condition. We tell Spring to use this custom condition with @Conditional:

@Conditional(HibernateCondition.class) Properties additionalProperties() { //... }

Spring Scheduling Annotations

We can use annotations when single-threaded execution isn't enough.

@EnableAsync With this annotation, we can enable asynchronous functionality in Spring.

We must use it with @Configuration:

@Configuration @EnableAsync class VehicleFactoryConfig {}

Now, that we enabled asynchronous calls, we can use @Async to define the methods supporting it.

@EnableScheduling

With this annotation, we can enable scheduling in the application.

We also have to use it in conjunction with @Configuration:

@Configuration @EnableScheduling class VehicleFactoryConfig {}

As a result, we can now run methods periodically with @Scheduled.

@Async

We can define methods we want to execute on a different thread, hence run them asynchronously.

To achieve this, we can annotate the method with @Async: @Async void repairCar() { // ... } If we apply this annotation to a class, then all methods will be called asynchronously.

Note, that we need to enable the asynchronous calls for this annotation to work, with @EnableAsync or XML configuration.

@Scheduled If we need a method to execute periodically, we can use this annotation:

@Scheduled(fixedRate = 10000) void checkVehicle() { // ... } We can use it to execute a method at fixed intervals, or we can fine-tune it with cron-like expressions.

@Scheduled leverages the Java 8 repeating annotations feature, which means we can mark a method with it multiple times:

@Scheduled(fixedRate = 10000) @Scheduled(cron = "0 MON-FRI") void checkVehicle() { // ... }

Note, that the method annotated with @Scheduled should have a void return type.

Moreover, we have to enable scheduling for this annotation to work for example with @EnableScheduling or XML configuration.

@Schedules

We can use this annotation to specify multiple @Scheduled rules:

@Schedules({ @Scheduled(fixedRate = 10000), @Scheduled(cron = "0 MON-FRI") }) void checkVehicle() { // ... }

Note, that since Java 8 we can achieve the same with the repeating annotations feature as described above.

Spring Data

It provides an abstraction over data storage technologies. Therefore, our business logic code can be much more independent of the underlying persistence implementation. Also, Spring simplifies the handling of implementation-dependent details of data storage.

In this tutorial, we'll see the most common annotations of the Spring Data, Spring Data JPA, and Spring Data MongoDB projects.

@Transactional

When we want to configure the transactional behavior of a method, we can do it with:

@Transactional void pay() {}

If we apply this annotation on class level, then it works on all methods inside the class. However, we can override its effects by applying it to a specific method.

@NoRepositoryBean

Sometimes we want to create repository interfaces with the only goal of providing common methods for the child repositories.

Of course, we don't want Spring to create a bean of these repositories since we won't inject them anywhere. @NoRepositoryBean does exactly this: when we mark a child interface of org.springframework.data.repository.Repository, Spring won't create a bean out of it.

For example, if we want an Optional findById(ID id) method in all of our repositories, we can create a base repository:

@NoRepositoryBean interface MyUtilityRepository<T, ID extends Serializable> extends CrudRepository<T, ID> { Optional findById(ID id); }

This annotation doesn't affect the child interfaces; hence Spring will create a bean for the following repository interface:

@Repository interface PersonRepository extends MyUtilityRepository<Person, Long> {}

Note, that the example above isn't necessary since Spring Data version 2 which includes this method replacing the older T findOne(ID id).

@Param

We can pass named parameters to our queries using @Param:

@Query("FROM Person p WHERE p.name = :name") Person findByName(@Param("name") String name);

Note, that we refer to the parameter with the :name syntax.

For further examples, please visit this article.

@Id

@Id marks a field in a model class as the primary key:

class Person {

@Id
Long id;

// ...

}

Since it's implementation-independent, it makes a model class easy to use with multiple data store engines.

@Transient

We can use this annotation to mark a field in a model class as transient. Hence the data store engine won't read or write this field's value:

class Person {

// ...

@Transient
int age;

// ...

}

Like @Id, @Transient is also implementation-independent, which makes it convenient to use with multiple data store implementations.

@CreatedBy, @LastModifiedBy, @CreatedDate, @LastModifiedDate

With these annotations, we can audit our model classes: Spring automatically populates the annotated fields with the principal who created the object, last modified it, and the date of creation, and last modification:

public class Person {

// ...

@CreatedBy
User creator;

@LastModifiedBy
User modifier;

@CreatedDate
Date createdAt;

@LastModifiedDate
Date modifiedAt;

// ...

}

Note, that if we want Spring to populate the principals, we need to use Spring Security as well.

@Query

With @Query, we can provide a JPQL implementation for a repository method:

@Query("SELECT COUNT(*) FROM Person p") long getPersonCount();

Also, we can use named parameters:

@Query("FROM Person p WHERE p.name = :name") Person findByName(@Param("name") String name);

Besides, we can use native SQL queries, if we set the nativeQuery argument to true: @Query(value = "SELECT AVG(p.age) FROM person p", nativeQuery = true) int getAverageAge();

@Procedure

With Spring Data JPA we can easily call stored procedures from repositories.

First, we need to declare the repository on the entity class using standard JPA annotations:

@NamedStoredProcedureQueries({ @NamedStoredProcedureQuery( name = "count_by_name", procedureName = "person.count_by_name", parameters = { @StoredProcedureParameter( mode = ParameterMode.IN, name = "name", type = String.class), @StoredProcedureParameter( mode = ParameterMode.OUT, name = "count", type = Long.class) } ) })

class Person {}

After this, we can refer to it in the repository with the name we declared in the name argument:

@Procedure(name = "count_by_name") long getCountByName(@Param("name") String name);

@Lock

We can configure the lock mode when we execute a repository query method:

@Lock(LockModeType.NONE) @Query("SELECT COUNT(*) FROM Person p") long getPersonCount();

The available lock modes: READ WRITE OPTIMISTIC OPTIMISTIC_FORCE_INCREMENT PESSIMISTIC_READ PESSIMISTIC_WRITE PESSIMISTIC_FORCE_INCREMENT NONE

@Modifying

We can modify data with a repository method if we annotate it with @Modifying:

@Modifying @Query("UPDATE Person p SET p.name = :name WHERE p.id = :id") void changeName(@Param("id") long id, @Param("name") String name);

@EnableJpaRepositories

To use JPA repositories, we have to indicate it to Spring. We can do this with @EnableJpaRepositories.

Note, that we have to use this annotation with @Configuration:

@Configuration @EnableJpaRepositories class PersistenceJPAConfig {}

Spring will look for repositories in the sub packages of this @Configuration class.

We can alter this behavior with the basePackages argument:

@Configuration @EnableJpaRepositories(basePackages = "com.baeldung.persistence.dao") class PersistenceJPAConfig {}

Also note, that Spring Boot does this automatically if it finds Spring Data JPA on the classpath.

Spring Data makes working with MongoDB much easier.

@Document

This annotation marks a class as being a domain object that we want to persist to the database:

@Document class User {}

It also allows us to choose the name of the collection we want to use:

@Document(collection = "user") class User {}

Note, that this annotation is the Mongo equivalent of @Entity in JPA.

@Field

With @Field, we can configure the name of a field we want to use when MongoDB persists the document:

@Document class User {

// ...

@Field("email")
String emailAddress;

// ...

}

Note, that this annotation is the Mongo equivalent of @Column in JPA.

@Query

With @Query, we can provide a finder query on a MongoDB repository method:

@Query("{ 'name' : ?0 }") List findUsersByName(String name);

@EnableMongoRepositories

To use MongoDB repositories, we have to indicate it to Spring. We can do this with @EnableMongoRepositories.

Note, that we have to use this annotation with @Configuration:

@Configuration @EnableMongoRepositories class MongoConfig {}

Spring will look for repositories in the sub packages of this @Configuration class. We can alter this behavior with the basePackages argument:

@Configuration @EnableMongoRepositories(basePackages = "com.baeldung.repository") class MongoConfig {}

Also note, that Spring Boot does this automatically if it finds Spring Data MongoDB on the classpath.

anitsh commented 2 years ago

https://www.digitalocean.com/community/tutorials/spring-bean-annotation https://www.baeldung.com/spring-bean-annotations

https://www.baeldung.com/spring-boot-console-app https://spring.io/guides/tutorials/rest/ https://www.digitalocean.com/community/tutorials/maven-commands-options-cheat-sheet https://spring.io/guides/gs/convert-jar-to-war

https://spring.io/guides/gs/uploading-files/ https://spring.io/guides/gs/convert-jar-to-war/