Spring Boot Table of Content




Subscribe To Our Newsletter
You will receive our latest post and tutorial.
Thank you for subscribing!

required
required


Leave a Reply

Your email address will not be published. Required fields are marked *

Springboot Retry

Spring framework has a retry project that is very useful when you have a business logic failure that you want to be able to retry to complete.

 

<dependency>
    <groupId>org.springframework.retry</groupId>
    <artifactId>spring-retry</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

 

@Configuration
@EnableRetry
public class GlobalConfig {

}

 

 

@Service
@Slf4j
public class UserServiceImp implements UserService {

    @Retryable(value = {RuntimeException.class}, maxAttempts = 3, backoff = @Backoff(delay = 2000))
    @Override
    public boolean sendEmail(User user) throws RuntimeException {
        log.info("send email");
        if (true) {
            throw new RuntimeException("error");
        }

        return false;
    }

    @Recover
    @Override
    public boolean recover(RuntimeException e, User user) {
        log.info("recover");
        return true;
    }

}

 

October 7, 2020

Springboot Lombok

Project Lombok is a java library that automatically plugs into your editor and build tools, spicing up your java.
Never write another getter or equals method again, with one annotation your class has a fully featured builder, Automate your logging variables, and much more.

Java can get too verbose for things you have to do such as generating getter and setter methods. These things often bring no real value to the business side of your applications. This is what lombok is for. Lombok is here to help you generate boilerplate code and you focus on business logic. The way it works is by plugging into your build process and autogenerating Java bytecode into your .class files as per a number of project annotations you introduce in your code.

Install Lombok on your computer

  1. Add dependency 
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
  2. Find lombok.jar in your project maven directory -> Right click -> Run As -> Java Application 
  3. Click on Specify Location button to choose the path where STS is installed
  4. Go to Application/Contents/Eclipse/SpringToolSuit4.ini Then click on Install -> Quick Installer
  5. Restart STS you are good to go

Use Lombok in your project

import java.io.Serializable;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Index;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.Lob;
import javax.persistence.ManyToMany;
import javax.persistence.OneToOne;
import javax.persistence.PrePersist;
import javax.persistence.PreUpdate;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.validation.constraints.NotEmpty;
import org.hibernate.annotations.CreationTimestamp;
import org.hibernate.annotations.ResultCheckStyle;
import org.hibernate.annotations.SQLDelete;
import org.hibernate.annotations.Type;
import org.hibernate.annotations.UpdateTimestamp;
import org.hibernate.annotations.Where;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.social.api.address.Address;
import com.social.api.user.role.Role;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;

@Setter
@Getter
@ToString
@AllArgsConstructor
@NoArgsConstructor
@JsonInclude(value = Include.NON_NULL)
public class User implements Serializable {

    private static final long serialVersionUID       = 1L;

    private Long              id;

    private String            firstName;

    private String            lastName;

    private String            email;

    private String            password;

    private String            phoneNumber;

    private Date              dateOfBirth;

    private String            aboutMe;

    private String            profileImageUrl;

    private String            coverImageUrl;

    private Date              passwordExpirationDate;

    private Integer           invalidPasswordCounter = 0;


}

 

 

September 19, 2020

Spring Boot – OAuth2

Create auth server and resource server

 

Create auth client that consumes resource from a third party like Google or Github

August 12, 2020

Spring Boot Thread Pool

One technique would be to balance thread pool size based on individual demand for hardware. However it might be important to give priority to web clients over requests coming in via JMS and therefore you might balance the pools in that direction. Of course as you rebalance you’ll have to adjust the size of each pool to take into account the difference in hardware demanded.

Getting a proper configuration for a thread pool may not be easy but it’s also not rocket science. The mathematics behind the problem are well understood and are fairly intuitive in that we meet them all the time in our every day lives. What is lacking are the measurements (as witness by j.u.c.ExecutorService) needed to make a reasonable choice. Getting to a proper setting will be a bit fiddly as this is more like bucket chemistry than a precise science but spending a little bit of time fiddling can save you the headache of having to deal with a system that has been destabilized by higher than expected workloads.

Here is a Thread Pool configuration sample.

/*
	 * corePoolSize parameter is the amount of core threads which will be
	 * instantiated and kept in the pool. If all core threads are busy and more
	 * tasks are submitted, then the pool is allowed to grow up to a
	 * maximumPoolSize.
	 */

	@Bean(name = "mainThreadPoolTaskExecutor")
	public ThreadPoolTaskExecutor threadPoolTaskExecutor() {
		ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
		// initial number of threads
		executor.setCorePoolSize(20);

		// max number of threads
		executor.setMaxPoolSize(Integer.MAX_VALUE);

		// some tasks may be put into a queue to wait for their turn.
		executor.setQueueCapacity(500);
		executor.setThreadNamePrefix("Auth-Thread-");
		executor.setAllowCoreThreadTimeOut(true);
		executor.setKeepAliveSeconds(60);
		executor.setWaitForTasksToCompleteOnShutdown(true);
		executor.setAwaitTerminationSeconds(60);
		executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
		executor.initialize();

		return executor;
	}
September 6, 2019

Spring Boot Security Config

Java Security Configuration 

Add dependency

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>

Add SecurityConfig class

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.MethodInvokingFactoryBean;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.RegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

import com.folaukaveinga.security.CustomAcccessDeniedHandler;
import com.folaukaveinga.security.CustomAuthenticationFilter;
import com.folaukaveinga.security.CustomAuthenticationProvider;
import com.folaukaveinga.security.CustomLoginFilter;
import com.folaukaveinga.security.CustomLogoutHandler;
import com.folaukaveinga.security.CustomLogoutSuccessHandler;
import com.folaukaveinga.utils.PathConstantUtil;

/**
 * Configure Security
 * @author fkaveinga
 *
 */
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private CustomAuthenticationProvider customAuthenticationProvider;
    
    @Autowired
    private CustomLogoutHandler customLogoutHandler;
    
    @Autowired
    private CustomLogoutSuccessHandler customLogoutSuccessHandler;
    
    @Autowired
    private CustomAcccessDeniedHandler customAcccessDeniedHandler;
    
    @Bean
    public CustomLoginFilter customUsernamePassworAuthenticationFilter() throws Exception {
        return new CustomLoginFilter(PathConstantUtil.LOGIN_URL,authenticationManagerBean());
    }
    
    @Bean
    public CustomAuthenticationFilter customAuthenticationFilter() {
        return new CustomAuthenticationFilter();
    }
    
    @Bean
    public RegistrationBean jwtAuthFilterRegister(CustomAuthenticationFilter customAuthenticationFilter) {
        FilterRegistrationBean<CustomAuthenticationFilter> registrationBean = new FilterRegistrationBean<CustomAuthenticationFilter>(
                customAuthenticationFilter);
        registrationBean.setEnabled(false);
        return registrationBean;
    }
    
    
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // rest call rules
        http
            .cors().and().csrf().disable()
            .authorizeRequests()
                .antMatchers(PathConstantUtil.PING_URL).permitAll()
                .antMatchers(PathConstantUtil.LOGIN_URL).permitAll()
                .antMatchers(PathConstantUtil.SIGNUP_URL).permitAll()
                .antMatchers(PathConstantUtil.PUBLIC_ENDPOINTS).permitAll()
                .anyRequest().permitAll();
                    
        // logout
        http.logout()
            .logoutRequestMatcher(new AntPathRequestMatcher(PathConstantUtil.LOGOUT_URL))
            .addLogoutHandler(customLogoutHandler)
            .logoutSuccessHandler(customLogoutSuccessHandler);
        
        // Login filter
        http.addFilterBefore(customUsernamePassworAuthenticationFilter(),UsernamePasswordAuthenticationFilter.class);
        // Signup filter
        http.addFilterBefore(customAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
        
        // stateless
        http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
        
        // handler access denied calls
        http.exceptionHandling().accessDeniedHandler(customAcccessDeniedHandler);
    }

    @Override
    protected void configure(AuthenticationManagerBuilder builder) throws Exception {
        builder.authenticationProvider(customAuthenticationProvider);
    }
    
    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring()
            .antMatchers(PathConstantUtil.SIGNUP_URL)
            .antMatchers(PathConstantUtil.LOGIN_URL)
            .antMatchers(PathConstantUtil.PING_URL)
            .antMatchers(PathConstantUtil.AUTH_TOKEN_URL)
            .antMatchers(PathConstantUtil.SWAGGER_DOC_URLS)
            .antMatchers(PathConstantUtil.PUBLIC_ENDPOINTS)
            .antMatchers("/actuator/**");
    }

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Bean
    public BCryptPasswordEncoder passwordEncoder() {
        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        return encoder;
    }
    
    @Bean
    public MethodInvokingFactoryBean methodInvokingFactoryBean() {
        MethodInvokingFactoryBean methodInvokingFactoryBean = new MethodInvokingFactoryBean();
        methodInvokingFactoryBean.setTargetClass(SecurityContextHolder.class);
        methodInvokingFactoryBean.setTargetMethod("setStrategyName");
        methodInvokingFactoryBean.setArguments(SecurityContextHolder.MODE_INHERITABLETHREADLOCAL);
        return methodInvokingFactoryBean;
    }
}

 

 

 

September 6, 2019