In this article, we will discuss on ‘Spring Boot Security-Scheduling-Transactions Annotations With Examples’. Needless to say, these annotations play a crucial role in creating a web application in Spring Boot. If you want to learn all annotations which are generally used in a Spring Boot Project, kindly visit our article ‘Spring Boot Annotations with Examples‘. Let’s discuss about ‘Spring Boot Security-Scheduling-Transactions Annotations With Examples’ here only.
Table of Contents (Click on links below to navigate)
Spring Security Annotations
Let’s start with Spring Boot Security annotations from our article ‘Spring Boot Security-Scheduling-Transactions Annotations With Examples’. In order to enable Security related annotations in your Spring Boot project, you need to add security starter dependency. If you created a project using STS (Spring Tool Suite), you have to select ‘Spring Security’ starter or else add the following dependency in your pom.xml file.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
@EnableWebSecurity
Spring Boot already provides some basic security configurations. In contrast, while doing customizations on Web Security, we generally create a custom configuration class that extends WebSecurityConfigurerAdapter. That custom configuration class becomes the candidate for applying @EnableWebSecurity annotation. Therefore, we can add this annotation to a @Configuration class to have the Spring Security configuration defined in any WebSecurityConfigurer or more likely by extending the WebSecurityConfigurerAdapter base class and override individual methods. For example, below code demonstrates the scenario & concept:
@Configuration
@EnableWebSecurity
public class MyWebSecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) {
// enable in memory based authentication with a user named "user" and "admin"
auth.inMemoryAuthentication().withUser("user").password("password").roles("USER")
.and().withUser("admin").password("password").roles("USER", "ADMIN");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/public/**").permitAll().anyRequest()
.hasRole("USER").and()
// Possibly more configuration ...
.formLogin() // enable form based log in
// set permitAll for all URLs associated with Form Login
.permitAll();
}
// Possibly more overridden methods ...
}
You may also visit our article for Spring Boot JDBC Authentication example. Moreover, in order to get more details on WebSecurityConfigurerAdapter kindly visit our Spring Boot Security Article.
@EnableGlobalMethodSecurity
@EnableGlobalMethodSecurity annotation enables method security in your application. We can enable annotation-based security using the @EnableGlobalMethodSecurity annotation on any @Configuration annotated class. Moreover, in order to get access of annotations such as @PreAuthorize, @PostAuthorize, @Secured, @RolesAllowed, you first need to enable Global Method Security by applying @GlobalMethodSecurity annotation to any @Configuration annotated java class. For example, below code demonstrates the concept.
@EnableWebSecurity
@EnableGlobalMethodSecurity(
prePostEnabled = true, // Enables @PreAuthorize and @PostAuthorize
securedEnabled = true, // Enables @Secured
jsr250Enabled = true // Enables @RolesAllowed
)
@Configuration
public class AppSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
....
}
// some other overriden methods
}
1) The property prePostEnabled=true enables support for Spring’s @PreAuthorize and @PostAuthorize annotations. Hence, Spring will ignore this annotation unless you set the flag to true.
2) The property securedEnabled=true enables support for the @Secured annotation. Hence, Spring will ignore this annotation unless you set the flag to true.
3) The property jsr250Enabled=true enables support for the @RolesAllowed annotation. Hence, Spring will ignore this annotation unless you set the flag to true.
@Secured vs @RolesAllowed
We use @Secured on a method to specify list of roles who can access the method. If there are multiple roles, user can access that method if user has at least one of the specified roles. For example, Let’s assume that we created a method getUserDetails() as below:
@Secured("ROLE_MANAGER","ROLE_ADMIN")
public String getUserDetails() {
SecurityContext securityContext = SecurityContextHolder.getContext();
return securityContext.getAuthentication().getName();
}
In the example above, If a user has either Admin or Manager role, that user can access the getUserDetails() method. We use @RolesAllowed in a similar way as @Secured. The @RolesAllowed annotation is the JSR-250’s equivalent annotation of the @Secured annotation. However, @Secured annotation doesn’t support SpEL(Spring Expression Language).
@PreAuthorize and @PostAuthorize
If we have a requirement where we want to apply a conditional or expression based access restriction to a method, then we can use @PreAuthorize and @PostAuthorize annotations. Moreover, we can write expressions using SpEL (Spring Expression Language). The @PreAuthorize annotation validates the provided expression before entering into the method. In contrast, the @PostAuthorize annotation checks it after the execution of the method and could modify the result.
@PreAuthorize
@PreAuthorize("hasRole('ROLE_MANAGER') or hasRole('ROLE_ADMIN')") public String getUserDetails() { SecurityContext securityContext = SecurityContextHolder.getContext(); return securityContext.getAuthentication().getName(); }
If you compare the example from @Secured annotation, the @PreAuthorize(“hasRole(‘ROLE_MANAGER’) or hasRole(‘ROLE_ADMIN’)”) is another way of writing @Secured(“ROLE_MANAGER”,”ROLE_ADMIN”). Consequently, The @PreAuthorize(“hasRole(‘ROLE_ADMIN’)”) is equivalent to @Secured(“ROLE_ADMIN”) and both have the same meaning.
@PostAuthorize
As aforementioned, @PostAuthorize annotation allows the business logic of a method to execute first and only then, the security expression it contains will be evaluated. So, be careful while applying this annotation. It is recommended that do not use this annotation with methods that perform modifying queries like for example Delete User or Update User. The @PostAuthorize annotation has access to an object that the method is going to return. We can access the object that the method is going to return in a security expression via the ‘returnObject’. Lets write an example of @PostAuthorize using this concept.
@PostAuthorize("returnObject.userId == authentication.principal.userId")
public User getUserDetail(String username) {
return userRepository.getUserByUserName(username);
}
In this example, the getUserDetail( ) method would only execute successfully if the userId of the returned User is equal to the current authentication principal’s userId.
In order to learn complete security features in Spring Boot, kindly visit our series of articles on Spring Boot Security.
Spring Scheduling Annotations
Spring Boot Scheduling Annotations don’t require any starter dependency. In order to have complete understanding on Scheduling in Spring Boot, you may visit Spring Boot Scheduler article.
@EnableScheduling
If we want to enable Scheduling in our application, we need to apply @EnableScheduling in conjunction with @Configuration. You can also use it on your main class as it has @Configuration enabled by default. For example, below code demonstrates the use of annotation.
@EnableScheduling
@Configuration
public class MySchedulingConfig {
....
}
Please note that if you are using this annotation in your main class(having annotation @SpringBootApplication) of application, you don’t need to apply @Configuration.
@Scheduled
This is a method level annotation. If we want a method to execute periodically, we can annotate that method with @Scheduled. This annotation instructs Spring Container to execute the method in a loop as per the provided parameters until the application/server stops. The method annotated with @Scheduled should not return any value, ie. It should have a void return type and even it should not have any parameter. However, it uses below concepts to support scheduling.
1) fixed Delay
2) fixed Rate
3) cron expression
♦ Note: You can’t write @Scheduled without providing any input as an attribute of it, other wise Spring container will throw IllegalStateException: Encountered invalid @Scheduled method ‘XYZ()’: Exactly one of the ‘cron’, ‘fixedDelay(String)’, or ‘fixedRate(String)’ attributes is required.
@Scheduled with fixedDelay
@Scheduled(fixedDelay = 4000)
// @Scheduled(fixedDelayString = "4000")
public void scheduledMethod() {
System.out.println(" Scheduler with Fixed delay :" + new Date());
}
In case of fixedDelay, there is a delay of 4000 milliseconds(4 seconds) between the finish time of an execution of a task and the start time of the next execution of the task.
♥ Note: We can provide fixedDelay input in two ways : Integer and String (For example, look at the above code example)
Integer type : @Scheduled(fixedDelay = 4000)
String type : @Scheduled(fixedDelayString = “4000”)
String value input also offers us to externalize the configuration by using Spring Expressions and storing them in properties files as shown in the example below.
@Scheduled(fixedDelayString = "${fixedDelay.input}")
@Scheduled(cron = "${cron.expression}")
@Scheduled with fixedDelay & initialDelay
The task will execute the first time after the initialDelay value, and it will continue executing as per the fixedDelay.
@Scheduled(initialDelay = 5000, fixedDelay = 9000)
// @Scheduled(initialDelayString = "5000" ,fixedDelayString = "9000")
public void scheduledMethod() {
System.out.println(" Scheduler with Fixed delay and Initial Delay:" + new Date());
}
@Scheduled with fixedRate
@Scheduled(fixedRate = 4000)
// @Scheduled(fixedRateString = "4000")
public void scheduledMethod() {
System.out.println(" Scheduler with Fixed Rate :" + new Date());
}
In case of fixedRate, the scheduled task will run at every 4000 milliseconds(4 seconds). It doesn’t check for any previous executions of the task.
@Scheduled with cron
Sometimes fixedDelay & fixedRate don’t solve our purpose. In that case we should use cron expressions as it provides more flexibile options. For example, below code demonstrates that the scheduled task will execute every year on Feb 14th 9:00:00 AM
if the given day(14th) is Sunday or Tuesday only.
@Scheduled(cron = "0 0 9 14 2 SUN,TUE")
public void scheduledMethod() {
System.out.println("Hello cron Scheduler :" +new Date());
}
Moreoever, we can also use the zone attribute to modify this timezone as below. By default, Spring considers the server’s local time zone for evaluation of the cron expression.
@Scheduled(cron = "0 0 9 14 2 SUN,TUE", zone = "America/New_York")
@Schedules
We can even configure multiple @Scheduled rules using @Schedules annotation. For example, below code demonstrates the concept:
@Schedules({
@Scheduled(fixedRate = 4000),
@Scheduled(cron = "0 0 0 14 2 *")
})
void getValentineDayNotification() { .... }
As shown in the example above, we have used two types of @Schedules rules.
In order to learn complete Scheduling in Spring Boot, kindly visit our article on Spring Boot Scheduler.
Transaction Annotations
@EnableTransactionManagement
We use the @EnableTransactionManagement annotation in a @Configuration class to enable Transaction related support. It is similar to the support found in Spring’s <tx:*> XML namespace. However, if we are on a Spring Boot Project and already have Spring-data or Spring-transaction related dependencies on the classpath, then all the features of this annotation will be available by default. For example, below code demonstrates the feature:
@Configuration
@EnableTransactionManagement
public class AppConfig {
@Bean
public DataSource dataSource() {
// configure and return the necessary JDBC DataSource
}
@Bean
public PlatformTransactionManager txManager() {
return new DataSourceTransactionManager(dataSource());
}
}
In the above code, @EnableTransactionManagement is responsible for registering the necessary Spring components that enable annotation-driven transaction management.
@Transactional
We can annotate a class or method with @Transactional. We use the @Transactional annotation to separate transaction management code from the code that incorporates business logic. Let’s understand it with the help of an example. To illustrate, let’s assume that we have to develop a money transfer business logic in a Banking application. Then we will write code something like below:
BankTransaction btx = entityManager.getTransaction(); try { btx.begin(); transferMoney(); btx.commit(); } catch(Exception ex) { btx.rollback(); throw ex; }
Now, If we use @Transactional annotation, our code will look like below:
@Transactional
public void transferMoney() {
...//logic to transfer money
}
This is the magic of @Transactional. You saw how @Transactional has separated the transaction management code from the actual business logic code.
It is amazing and very useful. Thanks for explain in details.
Thank you for this article. It’s been really helpful.