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; } }
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
<dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency>
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; }
Create auth server and resource server
Create auth client that consumes resource from a third party like Google or Github
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 = "taskExecutor") public ThreadPoolTaskExecutor taskExecutor() { 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; }
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; } }