From 920214f38dd07af14eea79682e16572a41118054 Mon Sep 17 00:00:00 2001 From: Kasra Madadipouya Date: Wed, 31 May 2023 13:40:49 +0200 Subject: [PATCH] JAVA-17164 update config and discovery services to use Spring Boot 2.7.X (#13967) --- .../book-service.properties | 2 + .../application-config/gateway.properties | 18 +---- .../rating-service.properties | 2 + .../spring-cloud-bootstrap/config/pom.xml | 8 +-- .../bootstrap/config/ConfigApplication.java | 4 +- .../bootstrap/config/SecurityConfig.java | 42 +++++++---- .../spring-cloud-bootstrap/discovery/pom.xml | 14 ++-- .../bootstrap/discovery/SecurityConfig.java | 2 +- .../spring-cloud-bootstrap/gateway/pom.xml | 24 ++++--- .../bootstrap/gateway/ErrorPageConfig.java | 6 +- .../bootstrap/gateway/GatewayApplication.java | 67 +----------------- .../bootstrap/gateway/SecurityConfig.java | 70 ++++++++++++------- .../bootstrap/gateway/SessionConfig.java | 9 ++- .../gateway/client/book/BooksClient.java | 5 +- .../gateway/client/rating/RatingsClient.java | 9 ++- .../filter/SessionSavingPreFilter.java | 25 +++++++ .../filter/SessionSavingZuulPreFilter.java | 47 ------------- .../src/main/resources/bootstrap.properties | 2 + .../spring-cloud-bootstrap/pom.xml | 1 - .../spring-cloud-bootstrap/svc-book/pom.xml | 20 ++++-- .../svcbook/BookServiceApplication.java | 43 +----------- .../cloud/bootstrap/svcbook/CookieConfig.java | 16 +++++ .../bootstrap/svcbook/SecurityConfig.java | 35 +++++----- .../bootstrap/svcbook/book/BookService.java | 10 +-- .../src/main/resources/bootstrap.properties | 2 + .../spring-cloud-bootstrap/svc-rating/pom.xml | 28 +++++--- .../bootstrap/svcrating/CookieConfig.java | 16 +++++ .../svcrating/RatingServiceApplication.java | 57 +-------------- .../bootstrap/svcrating/SecurityConfig.java | 50 ++++++------- .../bootstrap/svcrating/SessionConfig.java | 20 +++--- .../rating/RatingCacheRepository.java | 6 +- .../svcrating/rating/RatingService.java | 22 +++--- .../src/main/resources/bootstrap.properties | 2 + .../spring-cloud-bootstrap/zipkin/README.md | 19 +++++ .../zipkin/docker-compose.yml | 6 ++ .../spring-cloud-bootstrap/zipkin/pom.xml | 53 -------------- .../bootstrap/zipkin/ZipkinApplication.java | 15 ---- .../src/main/resources/bootstrap.properties | 7 -- .../zipkin/src/main/resources/logback.xml | 13 ---- .../java/com/baeldung/SpringContextTest.java | 17 ----- 40 files changed, 329 insertions(+), 485 deletions(-) create mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway/src/main/java/com/baeldung/spring/cloud/bootstrap/gateway/filter/SessionSavingPreFilter.java delete mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway/src/main/java/com/baeldung/spring/cloud/bootstrap/gateway/filter/SessionSavingZuulPreFilter.java create mode 100644 spring-cloud-modules/spring-cloud-bootstrap/svc-book/src/main/java/com/baeldung/spring/cloud/bootstrap/svcbook/CookieConfig.java create mode 100644 spring-cloud-modules/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/CookieConfig.java create mode 100644 spring-cloud-modules/spring-cloud-bootstrap/zipkin/README.md create mode 100644 spring-cloud-modules/spring-cloud-bootstrap/zipkin/docker-compose.yml delete mode 100644 spring-cloud-modules/spring-cloud-bootstrap/zipkin/pom.xml delete mode 100644 spring-cloud-modules/spring-cloud-bootstrap/zipkin/src/main/java/com/baeldung/spring/cloud/bootstrap/zipkin/ZipkinApplication.java delete mode 100644 spring-cloud-modules/spring-cloud-bootstrap/zipkin/src/main/resources/bootstrap.properties delete mode 100644 spring-cloud-modules/spring-cloud-bootstrap/zipkin/src/main/resources/logback.xml delete mode 100644 spring-cloud-modules/spring-cloud-bootstrap/zipkin/src/test/java/com/baeldung/SpringContextTest.java diff --git a/spring-cloud-modules/spring-cloud-bootstrap/application-config/book-service.properties b/spring-cloud-modules/spring-cloud-bootstrap/application-config/book-service.properties index 49f7d1ed91..2ea30b9ab7 100644 --- a/spring-cloud-modules/spring-cloud-bootstrap/application-config/book-service.properties +++ b/spring-cloud-modules/spring-cloud-bootstrap/application-config/book-service.properties @@ -18,3 +18,5 @@ spring.redis.port=6379 spring.sleuth.sampler.percentage=1.0 spring.sleuth.web.skipPattern=(^cleanup.*) + +spring.zipkin.baseUrl=http://localhost:9411 diff --git a/spring-cloud-modules/spring-cloud-bootstrap/application-config/gateway.properties b/spring-cloud-modules/spring-cloud-bootstrap/application-config/gateway.properties index e9e593284c..42e114450d 100644 --- a/spring-cloud-modules/spring-cloud-bootstrap/application-config/gateway.properties +++ b/spring-cloud-modules/spring-cloud-bootstrap/application-config/gateway.properties @@ -6,25 +6,13 @@ eureka.client.registryFetchIntervalSeconds = 5 management.security.sessions=always -zuul.routes.book-service.path=/book-service/** -zuul.routes.book-service.sensitive-headers=Set-Cookie,Authorization -hystrix.command.book-service.execution.isolation.thread.timeoutInMilliseconds=600000 - -zuul.routes.rating-service.path=/rating-service/** -zuul.routes.rating-service.sensitive-headers=Set-Cookie,Authorization -hystrix.command.rating-service.execution.isolation.thread.timeoutInMilliseconds=600000 - -zuul.routes.discovery.path=/discovery/** -zuul.routes.discovery.sensitive-headers=Set-Cookie,Authorization -zuul.routes.discovery.url=http://localhost:8082 -hystrix.command.discovery.execution.isolation.thread.timeoutInMilliseconds=600000 - logging.level.org.springframework.web.=debug logging.level.org.springframework.security=debug -logging.level.org.springframework.cloud.netflix.zuul=debug spring.redis.host=localhost spring.redis.port=6379 spring.sleuth.sampler.percentage=1.0 -spring.sleuth.web.skipPattern=(^cleanup.*|.+favicon.*) \ No newline at end of file +spring.sleuth.web.skipPattern=(^cleanup.*|.+favicon.*) + +spring.zipkin.baseUrl=http://localhost:9411 diff --git a/spring-cloud-modules/spring-cloud-bootstrap/application-config/rating-service.properties b/spring-cloud-modules/spring-cloud-bootstrap/application-config/rating-service.properties index b7cbb6fbd6..059b87e4e7 100644 --- a/spring-cloud-modules/spring-cloud-bootstrap/application-config/rating-service.properties +++ b/spring-cloud-modules/spring-cloud-bootstrap/application-config/rating-service.properties @@ -18,3 +18,5 @@ spring.redis.port=6379 spring.sleuth.sampler.percentage=1.0 spring.sleuth.web.skipPattern=(^cleanup.*) + +spring.zipkin.baseUrl=http://localhost:9411 diff --git a/spring-cloud-modules/spring-cloud-bootstrap/config/pom.xml b/spring-cloud-modules/spring-cloud-bootstrap/config/pom.xml index 6c9c3c5374..c1be447822 100644 --- a/spring-cloud-modules/spring-cloud-bootstrap/config/pom.xml +++ b/spring-cloud-modules/spring-cloud-bootstrap/config/pom.xml @@ -9,9 +9,9 @@ com.baeldung - parent-boot-1 + parent-boot-2 0.0.1-SNAPSHOT - ../../../parent-boot-1 + ../../../parent-boot-2 @@ -33,7 +33,7 @@ org.springframework.cloud - spring-cloud-starter-eureka + spring-cloud-starter-netflix-eureka-client org.springframework.boot @@ -42,7 +42,7 @@ - Brixton.SR7 + 2021.0.7 \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-bootstrap/config/src/main/java/com/baeldung/spring/cloud/bootstrap/config/ConfigApplication.java b/spring-cloud-modules/spring-cloud-bootstrap/config/src/main/java/com/baeldung/spring/cloud/bootstrap/config/ConfigApplication.java index 847c86f881..c3e04c4b54 100644 --- a/spring-cloud-modules/spring-cloud-bootstrap/config/src/main/java/com/baeldung/spring/cloud/bootstrap/config/ConfigApplication.java +++ b/spring-cloud-modules/spring-cloud-bootstrap/config/src/main/java/com/baeldung/spring/cloud/bootstrap/config/ConfigApplication.java @@ -2,12 +2,12 @@ package com.baeldung.spring.cloud.bootstrap.config; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.config.server.EnableConfigServer; -import org.springframework.cloud.netflix.eureka.EnableEurekaClient; @SpringBootApplication @EnableConfigServer -@EnableEurekaClient +@EnableDiscoveryClient public class ConfigApplication { public static void main(String[] args) { SpringApplication.run(ConfigApplication.class, args); diff --git a/spring-cloud-modules/spring-cloud-bootstrap/config/src/main/java/com/baeldung/spring/cloud/bootstrap/config/SecurityConfig.java b/spring-cloud-modules/spring-cloud-bootstrap/config/src/main/java/com/baeldung/spring/cloud/bootstrap/config/SecurityConfig.java index ef1d7b0b78..d563052baa 100644 --- a/spring-cloud-modules/spring-cloud-bootstrap/config/src/main/java/com/baeldung/spring/cloud/bootstrap/config/SecurityConfig.java +++ b/spring-cloud-modules/spring-cloud-bootstrap/config/src/main/java/com/baeldung/spring/cloud/bootstrap/config/SecurityConfig.java @@ -1,23 +1,41 @@ package com.baeldung.spring.cloud.bootstrap.config; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Configuration; -import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.context.annotation.Bean; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; -import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.core.userdetails.User; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.provisioning.InMemoryUserDetailsManager; +import org.springframework.security.web.SecurityFilterChain; -@Configuration @EnableWebSecurity -public class SecurityConfig extends WebSecurityConfigurerAdapter { +public class SecurityConfig { - @Autowired - public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { - auth.inMemoryAuthentication().withUser("configUser").password("configPassword").roles("SYSTEM"); + @Bean + public InMemoryUserDetailsManager userDetailsService(BCryptPasswordEncoder bCryptPasswordEncoder) { + InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager(); + manager.createUser(User.withUsername("configUser") + .password(bCryptPasswordEncoder.encode("configPassword")) + .roles("SYSTEM") + .build()); + return manager; } - @Override - protected void configure(HttpSecurity http) throws Exception { - http.authorizeRequests().anyRequest().hasRole("SYSTEM").and().httpBasic().and().csrf().disable(); + @Bean + public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { + http.authorizeRequests() + .anyRequest() + .hasRole("SYSTEM") + .and() + .httpBasic() + .and() + .csrf() + .disable(); + return http.build(); + } + + @Bean + public BCryptPasswordEncoder encoder() { + return new BCryptPasswordEncoder(); } } diff --git a/spring-cloud-modules/spring-cloud-bootstrap/discovery/pom.xml b/spring-cloud-modules/spring-cloud-bootstrap/discovery/pom.xml index fb06c6052b..28c1a741a6 100644 --- a/spring-cloud-modules/spring-cloud-bootstrap/discovery/pom.xml +++ b/spring-cloud-modules/spring-cloud-bootstrap/discovery/pom.xml @@ -9,9 +9,9 @@ com.baeldung - parent-boot-1 + parent-boot-2 0.0.1-SNAPSHOT - ../../../parent-boot-1 + ../../../parent-boot-2 @@ -33,7 +33,11 @@ org.springframework.cloud - spring-cloud-starter-eureka-server + spring-cloud-starter-bootstrap + + + org.springframework.cloud + spring-cloud-starter-netflix-eureka-server org.springframework.boot @@ -41,7 +45,7 @@ org.springframework.session - spring-session + spring-session-data-redis org.springframework.boot @@ -50,7 +54,7 @@ - Edgware.SR5 + 2021.0.7 \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-bootstrap/discovery/src/main/java/com/baeldung/spring/cloud/bootstrap/discovery/SecurityConfig.java b/spring-cloud-modules/spring-cloud-bootstrap/discovery/src/main/java/com/baeldung/spring/cloud/bootstrap/discovery/SecurityConfig.java index a89faba962..fa389ec6a3 100644 --- a/spring-cloud-modules/spring-cloud-bootstrap/discovery/src/main/java/com/baeldung/spring/cloud/bootstrap/discovery/SecurityConfig.java +++ b/spring-cloud-modules/spring-cloud-bootstrap/discovery/src/main/java/com/baeldung/spring/cloud/bootstrap/discovery/SecurityConfig.java @@ -17,7 +17,7 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { - auth.inMemoryAuthentication().withUser("discUser").password("discPassword").roles("SYSTEM"); + auth.inMemoryAuthentication().withUser("discUser").password("{noop}discPassword").roles("SYSTEM"); } @Override diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway/pom.xml b/spring-cloud-modules/spring-cloud-bootstrap/gateway/pom.xml index e1041516c4..fa6735199f 100644 --- a/spring-cloud-modules/spring-cloud-bootstrap/gateway/pom.xml +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway/pom.xml @@ -9,9 +9,9 @@ com.baeldung - parent-boot-1 + parent-boot-2 0.0.1-SNAPSHOT - ../../../parent-boot-1 + ../../../parent-boot-2 @@ -33,11 +33,15 @@ org.springframework.cloud - spring-cloud-starter-eureka + spring-cloud-starter-bootstrap org.springframework.cloud - spring-cloud-starter-zuul + spring-cloud-starter-netflix-eureka-client + + + org.springframework.cloud + spring-cloud-starter-gateway org.springframework.boot @@ -45,7 +49,7 @@ org.springframework.session - spring-session + spring-session-data-redis org.springframework.boot @@ -53,11 +57,15 @@ org.springframework.cloud - spring-cloud-starter-zipkin + spring-cloud-starter-sleuth org.springframework.cloud - spring-cloud-starter-feign + spring-cloud-sleuth-zipkin + + + org.springframework.cloud + spring-cloud-starter-openfeign @@ -97,7 +105,7 @@ - Dalston.RELEASE + 2021.0.7 \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway/src/main/java/com/baeldung/spring/cloud/bootstrap/gateway/ErrorPageConfig.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway/src/main/java/com/baeldung/spring/cloud/bootstrap/gateway/ErrorPageConfig.java index 67d172d3cd..b1fa7ce0bb 100644 --- a/spring-cloud-modules/spring-cloud-bootstrap/gateway/src/main/java/com/baeldung/spring/cloud/bootstrap/gateway/ErrorPageConfig.java +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway/src/main/java/com/baeldung/spring/cloud/bootstrap/gateway/ErrorPageConfig.java @@ -1,8 +1,8 @@ package com.baeldung.spring.cloud.bootstrap.gateway; -import org.springframework.boot.web.servlet.ErrorPage; -import org.springframework.boot.web.servlet.ErrorPageRegistrar; -import org.springframework.boot.web.servlet.ErrorPageRegistry; +import org.springframework.boot.web.server.ErrorPage; +import org.springframework.boot.web.server.ErrorPageRegistrar; +import org.springframework.boot.web.server.ErrorPageRegistry; import org.springframework.http.HttpStatus; import org.springframework.stereotype.Component; diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway/src/main/java/com/baeldung/spring/cloud/bootstrap/gateway/GatewayApplication.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway/src/main/java/com/baeldung/spring/cloud/bootstrap/gateway/GatewayApplication.java index 8fc75e1ff6..6adda92c25 100644 --- a/spring-cloud-modules/spring-cloud-bootstrap/gateway/src/main/java/com/baeldung/spring/cloud/bootstrap/gateway/GatewayApplication.java +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway/src/main/java/com/baeldung/spring/cloud/bootstrap/gateway/GatewayApplication.java @@ -1,76 +1,15 @@ package com.baeldung.spring.cloud.bootstrap.gateway; -import com.netflix.appinfo.InstanceInfo; -import com.netflix.discovery.EurekaClient; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.cloud.client.loadbalancer.LoadBalanced; -import org.springframework.cloud.netflix.eureka.EnableEurekaClient; -import org.springframework.cloud.netflix.feign.EnableFeignClients; -import org.springframework.cloud.netflix.ribbon.RibbonClientSpecification; -import org.springframework.cloud.netflix.ribbon.SpringClientFactory; -import org.springframework.cloud.netflix.zuul.EnableZuulProxy; -import org.springframework.cloud.sleuth.metric.SpanMetricReporter; -import org.springframework.cloud.sleuth.zipkin.HttpZipkinSpanReporter; -import org.springframework.cloud.sleuth.zipkin.ZipkinProperties; -import org.springframework.cloud.sleuth.zipkin.ZipkinSpanReporter; -import org.springframework.context.annotation.Bean; -import org.springframework.web.client.RestTemplate; -import zipkin.Span; - -import java.util.ArrayList; -import java.util.List; +import org.springframework.cloud.client.discovery.EnableDiscoveryClient; +import org.springframework.cloud.openfeign.EnableFeignClients; @SpringBootApplication -@EnableZuulProxy -@EnableEurekaClient @EnableFeignClients +@EnableDiscoveryClient public class GatewayApplication { public static void main(String[] args) { SpringApplication.run(GatewayApplication.class, args); } - - @Autowired(required = false) - private List configurations = new ArrayList<>(); - @Autowired - private EurekaClient eurekaClient; - @Autowired - private SpanMetricReporter spanMetricReporter; - @Autowired - private ZipkinProperties zipkinProperties; - @Value("${spring.sleuth.web.skipPattern}") - private String skipPattern; - - @Bean - @LoadBalanced - RestTemplate restTemplate() { - return new RestTemplate(); - } - - @Bean - public SpringClientFactory springClientFactory() { - SpringClientFactory factory = new SpringClientFactory(); - factory.setConfigurations(this.configurations); - return factory; - } - - @Bean - public ZipkinSpanReporter makeZipkinSpanReporter() { - return new ZipkinSpanReporter() { - private HttpZipkinSpanReporter delegate; - private String baseUrl; - - @Override - public void report(Span span) { - InstanceInfo instance = eurekaClient.getNextServerFromEureka("zipkin", false); - if (baseUrl == null || !instance.getHomePageUrl().equals(baseUrl)) { - baseUrl = instance.getHomePageUrl(); - } - delegate = new HttpZipkinSpanReporter(new RestTemplate(), baseUrl, zipkinProperties.getFlushInterval(), spanMetricReporter); - if (!span.name.matches(skipPattern)) delegate.report(span); - } - }; - } } diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway/src/main/java/com/baeldung/spring/cloud/bootstrap/gateway/SecurityConfig.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway/src/main/java/com/baeldung/spring/cloud/bootstrap/gateway/SecurityConfig.java index d56be699e6..088fdd01f7 100644 --- a/spring-cloud-modules/spring-cloud-bootstrap/gateway/src/main/java/com/baeldung/spring/cloud/bootstrap/gateway/SecurityConfig.java +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway/src/main/java/com/baeldung/spring/cloud/bootstrap/gateway/SecurityConfig.java @@ -1,37 +1,59 @@ package com.baeldung.spring.cloud.bootstrap.gateway; -import org.springframework.beans.factory.annotation.Autowired; +import static org.springframework.security.config.Customizer.withDefaults; + +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; -import org.springframework.security.config.annotation.web.builders.HttpSecurity; -import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; -import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity; +import org.springframework.security.config.web.server.ServerHttpSecurity; +import org.springframework.security.core.userdetails.MapReactiveUserDetailsService; +import org.springframework.security.core.userdetails.User; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.security.web.server.SecurityWebFilterChain; +import org.springframework.security.web.server.authentication.RedirectServerAuthenticationSuccessHandler; -@EnableWebSecurity +@EnableWebFluxSecurity @Configuration -public class SecurityConfig extends WebSecurityConfigurerAdapter { +public class SecurityConfig { - @Autowired - public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { - auth.inMemoryAuthentication() - .withUser("user").password("password").roles("USER") - .and() - .withUser("admin").password("admin").roles("ADMIN"); + @Bean + public MapReactiveUserDetailsService userDetailsService() { + UserDetails user = User.withUsername("user") + .password(passwordEncoder().encode("password")) + .roles("USER") + .build(); + UserDetails adminUser = User.withUsername("admin") + .password(passwordEncoder().encode("admin")) + .roles("ADMIN") + .build(); + return new MapReactiveUserDetailsService(user, adminUser); } - @Override - protected void configure(HttpSecurity http) throws Exception { - http - .formLogin() - .defaultSuccessUrl("/home/index.html", true) + @Bean + public PasswordEncoder passwordEncoder() { + return new BCryptPasswordEncoder(); + } + + @Bean + public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { + http.formLogin() + .authenticationSuccessHandler(new RedirectServerAuthenticationSuccessHandler("/home/index.html")) .and() - .authorizeRequests() - .antMatchers("/book-service/**", "/rating-service/**", "/login*", "/").permitAll() - .antMatchers("/eureka/**").hasRole("ADMIN") - .anyRequest().authenticated() + .authorizeExchange() + .pathMatchers("/book-service/**", "/rating-service/**", "/login*", "/") + .permitAll() + .pathMatchers("/eureka/**") + .hasRole("ADMIN") + .anyExchange() + .authenticated() .and() - .logout() + .logout() .and() - .csrf().disable(); + .csrf() + .disable() + .httpBasic(withDefaults()); + return http.build(); } } diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway/src/main/java/com/baeldung/spring/cloud/bootstrap/gateway/SessionConfig.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway/src/main/java/com/baeldung/spring/cloud/bootstrap/gateway/SessionConfig.java index 14f7deb770..498c780f65 100644 --- a/spring-cloud-modules/spring-cloud-bootstrap/gateway/src/main/java/com/baeldung/spring/cloud/bootstrap/gateway/SessionConfig.java +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway/src/main/java/com/baeldung/spring/cloud/bootstrap/gateway/SessionConfig.java @@ -1,11 +1,10 @@ package com.baeldung.spring.cloud.bootstrap.gateway; import org.springframework.context.annotation.Configuration; -import org.springframework.session.data.redis.RedisFlushMode; -import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession; -import org.springframework.session.web.context.AbstractHttpSessionApplicationInitializer; +import org.springframework.session.data.redis.config.annotation.web.server.EnableRedisWebSession; @Configuration -@EnableRedisHttpSession(redisFlushMode = RedisFlushMode.IMMEDIATE) -public class SessionConfig extends AbstractHttpSessionApplicationInitializer { +@EnableRedisWebSession +public class SessionConfig { + } diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway/src/main/java/com/baeldung/spring/cloud/bootstrap/gateway/client/book/BooksClient.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway/src/main/java/com/baeldung/spring/cloud/bootstrap/gateway/client/book/BooksClient.java index f60f65d23c..8fd235b3dc 100644 --- a/spring-cloud-modules/spring-cloud-bootstrap/gateway/src/main/java/com/baeldung/spring/cloud/bootstrap/gateway/client/book/BooksClient.java +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway/src/main/java/com/baeldung/spring/cloud/bootstrap/gateway/client/book/BooksClient.java @@ -1,7 +1,6 @@ package com.baeldung.spring.cloud.bootstrap.gateway.client.book; -import org.springframework.cloud.netflix.feign.FeignClient; -import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; @@ -9,6 +8,6 @@ import org.springframework.web.bind.annotation.RequestMethod; @FeignClient(value = "book-service") public interface BooksClient { - @RequestMapping(value = "/books/{bookId}", method = {RequestMethod.GET}) + @RequestMapping(value = "/books/{bookId}", method = { RequestMethod.GET }) Book getBookById(@PathVariable("bookId") Long bookId); } diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway/src/main/java/com/baeldung/spring/cloud/bootstrap/gateway/client/rating/RatingsClient.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway/src/main/java/com/baeldung/spring/cloud/bootstrap/gateway/client/rating/RatingsClient.java index 9728111c5e..d04ba85082 100644 --- a/spring-cloud-modules/spring-cloud-bootstrap/gateway/src/main/java/com/baeldung/spring/cloud/bootstrap/gateway/client/rating/RatingsClient.java +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway/src/main/java/com/baeldung/spring/cloud/bootstrap/gateway/client/rating/RatingsClient.java @@ -1,17 +1,16 @@ package com.baeldung.spring.cloud.bootstrap.gateway.client.rating; -import org.springframework.cloud.netflix.feign.FeignClient; -import org.springframework.web.bind.annotation.GetMapping; +import java.util.List; + +import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.RequestHeader; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; -import java.util.List; - @FeignClient(value = "rating-service") public interface RatingsClient { - @RequestMapping(value = "/ratings", method = {RequestMethod.GET}) + @RequestMapping(value = "/ratings", method = { RequestMethod.GET }) List getRatingsByBookId(@RequestParam("bookId") Long bookId, @RequestHeader("Cookie") String session); } diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway/src/main/java/com/baeldung/spring/cloud/bootstrap/gateway/filter/SessionSavingPreFilter.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway/src/main/java/com/baeldung/spring/cloud/bootstrap/gateway/filter/SessionSavingPreFilter.java new file mode 100644 index 0000000000..bf10152318 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway/src/main/java/com/baeldung/spring/cloud/bootstrap/gateway/filter/SessionSavingPreFilter.java @@ -0,0 +1,25 @@ +package com.baeldung.spring.cloud.bootstrap.gateway.filter; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.cloud.gateway.filter.GatewayFilterChain; +import org.springframework.cloud.gateway.filter.GlobalFilter; +import org.springframework.stereotype.Component; +import org.springframework.web.server.ServerWebExchange; + +import reactor.core.publisher.Mono; + +@Component +public class SessionSavingPreFilter implements GlobalFilter { + + private static final Logger logger = LoggerFactory.getLogger(SessionSavingPreFilter.class); + + @Override + public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { + return exchange.getSession() + .flatMap(session -> { + logger.debug("SessionId: {}", session.getId()); + return chain.filter(exchange); + }); + } +} diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway/src/main/java/com/baeldung/spring/cloud/bootstrap/gateway/filter/SessionSavingZuulPreFilter.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway/src/main/java/com/baeldung/spring/cloud/bootstrap/gateway/filter/SessionSavingZuulPreFilter.java deleted file mode 100644 index 1c90ba2e12..0000000000 --- a/spring-cloud-modules/spring-cloud-bootstrap/gateway/src/main/java/com/baeldung/spring/cloud/bootstrap/gateway/filter/SessionSavingZuulPreFilter.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.baeldung.spring.cloud.bootstrap.gateway.filter; - -import com.netflix.zuul.ZuulFilter; -import com.netflix.zuul.context.RequestContext; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.session.Session; -import org.springframework.session.SessionRepository; -import org.springframework.stereotype.Component; - -import javax.servlet.http.HttpSession; - -@Component -public class SessionSavingZuulPreFilter extends ZuulFilter { - - private Logger log = LoggerFactory.getLogger(this.getClass()); - - @Autowired - private SessionRepository repository; - - @Override - public boolean shouldFilter() { - return true; - } - - @Override - public Object run() { - RequestContext context = RequestContext.getCurrentContext(); - HttpSession httpSession = context.getRequest().getSession(); - Session session = repository.getSession(httpSession.getId()); - - context.addZuulRequestHeader("Cookie", "SESSION=" + httpSession.getId()); - log.info("ZuulPreFilter session proxy: {}", session.getId()); - return null; - } - - @Override - public String filterType() { - return "pre"; - } - - @Override - public int filterOrder() { - return 0; - } -} diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway/src/main/resources/bootstrap.properties b/spring-cloud-modules/spring-cloud-bootstrap/gateway/src/main/resources/bootstrap.properties index 43491ff36b..1c90ca9db0 100644 --- a/spring-cloud-modules/spring-cloud-bootstrap/gateway/src/main/resources/bootstrap.properties +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway/src/main/resources/bootstrap.properties @@ -3,5 +3,7 @@ spring.cloud.config.discovery.service-id=config spring.cloud.config.discovery.enabled=true spring.cloud.config.username=configUser spring.cloud.config.password=configPassword +spring.cloud.gateway.discovery.locator.enabled=true +spring.cloud.gateway.discovery.locator.lowerCaseServiceId=true eureka.client.serviceUrl.defaultZone=http://discUser:discPassword@localhost:8082/eureka/ \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-bootstrap/pom.xml b/spring-cloud-modules/spring-cloud-bootstrap/pom.xml index 1e97082db1..e7fe7e7485 100644 --- a/spring-cloud-modules/spring-cloud-bootstrap/pom.xml +++ b/spring-cloud-modules/spring-cloud-bootstrap/pom.xml @@ -20,7 +20,6 @@ gateway svc-book svc-rating - zipkin customer-service order-service diff --git a/spring-cloud-modules/spring-cloud-bootstrap/svc-book/pom.xml b/spring-cloud-modules/spring-cloud-bootstrap/svc-book/pom.xml index b1aa205af5..c973968a70 100644 --- a/spring-cloud-modules/spring-cloud-bootstrap/svc-book/pom.xml +++ b/spring-cloud-modules/spring-cloud-bootstrap/svc-book/pom.xml @@ -10,9 +10,9 @@ com.baeldung - parent-boot-1 + parent-boot-2 0.0.1-SNAPSHOT - ../../../parent-boot-1 + ../../../parent-boot-2 @@ -34,7 +34,11 @@ org.springframework.cloud - spring-cloud-starter-eureka + spring-cloud-starter-bootstrap + + + org.springframework.cloud + spring-cloud-starter-netflix-eureka-client org.springframework.boot @@ -46,7 +50,7 @@ org.springframework.session - spring-session + spring-session-data-redis org.springframework.boot @@ -63,12 +67,16 @@ org.springframework.cloud - spring-cloud-starter-zipkin + spring-cloud-starter-sleuth + + + org.springframework.cloud + spring-cloud-sleuth-zipkin - Dalston.RELEASE + 2021.0.7 \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-bootstrap/svc-book/src/main/java/com/baeldung/spring/cloud/bootstrap/svcbook/BookServiceApplication.java b/spring-cloud-modules/spring-cloud-bootstrap/svc-book/src/main/java/com/baeldung/spring/cloud/bootstrap/svcbook/BookServiceApplication.java index d787b5e407..8b1eab7885 100644 --- a/spring-cloud-modules/spring-cloud-bootstrap/svc-book/src/main/java/com/baeldung/spring/cloud/bootstrap/svcbook/BookServiceApplication.java +++ b/spring-cloud-modules/spring-cloud-bootstrap/svc-book/src/main/java/com/baeldung/spring/cloud/bootstrap/svcbook/BookServiceApplication.java @@ -1,53 +1,14 @@ package com.baeldung.spring.cloud.bootstrap.svcbook; -import com.netflix.appinfo.InstanceInfo; -import com.netflix.discovery.EurekaClient; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.cloud.netflix.eureka.EnableEurekaClient; -import org.springframework.cloud.sleuth.metric.SpanMetricReporter; -import org.springframework.cloud.sleuth.zipkin.HttpZipkinSpanReporter; -import org.springframework.cloud.sleuth.zipkin.ZipkinProperties; -import org.springframework.cloud.sleuth.zipkin.ZipkinSpanReporter; -import org.springframework.context.annotation.Bean; -import org.springframework.web.client.RestTemplate; - -import zipkin.Span; +import org.springframework.cloud.client.discovery.EnableDiscoveryClient; @SpringBootApplication -@EnableEurekaClient +@EnableDiscoveryClient public class BookServiceApplication { - @Autowired - private EurekaClient eurekaClient; - @Autowired - private SpanMetricReporter spanMetricReporter; - @Autowired - private ZipkinProperties zipkinProperties; - @Value("${spring.sleuth.web.skipPattern}") - private String skipPattern; - public static void main(String[] args) { SpringApplication.run(BookServiceApplication.class, args); } - - @Bean - public ZipkinSpanReporter makeZipkinSpanReporter() { - return new ZipkinSpanReporter() { - private HttpZipkinSpanReporter delegate; - private String baseUrl; - - @Override - public void report(Span span) { - InstanceInfo instance = eurekaClient.getNextServerFromEureka("zipkin", false); - if (baseUrl == null || !instance.getHomePageUrl().equals(baseUrl)) { - baseUrl = instance.getHomePageUrl(); - } - delegate = new HttpZipkinSpanReporter(new RestTemplate(), baseUrl, zipkinProperties.getFlushInterval(), spanMetricReporter); - if (!span.name.matches(skipPattern)) delegate.report(span); - } - }; - } } diff --git a/spring-cloud-modules/spring-cloud-bootstrap/svc-book/src/main/java/com/baeldung/spring/cloud/bootstrap/svcbook/CookieConfig.java b/spring-cloud-modules/spring-cloud-bootstrap/svc-book/src/main/java/com/baeldung/spring/cloud/bootstrap/svcbook/CookieConfig.java new file mode 100644 index 0000000000..99696836c1 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-bootstrap/svc-book/src/main/java/com/baeldung/spring/cloud/bootstrap/svcbook/CookieConfig.java @@ -0,0 +1,16 @@ +package com.baeldung.spring.cloud.bootstrap.svcbook; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.session.web.http.DefaultCookieSerializer; + +@Configuration +public class CookieConfig { + + @Bean + public DefaultCookieSerializer cookieSerializer() { + DefaultCookieSerializer serializer = new DefaultCookieSerializer(); + serializer.setUseBase64Encoding(false); + return serializer; + } +} \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-bootstrap/svc-book/src/main/java/com/baeldung/spring/cloud/bootstrap/svcbook/SecurityConfig.java b/spring-cloud-modules/spring-cloud-bootstrap/svc-book/src/main/java/com/baeldung/spring/cloud/bootstrap/svcbook/SecurityConfig.java index 6aa996c575..0b9520c976 100644 --- a/spring-cloud-modules/spring-cloud-bootstrap/svc-book/src/main/java/com/baeldung/spring/cloud/bootstrap/svcbook/SecurityConfig.java +++ b/spring-cloud-modules/spring-cloud-bootstrap/svc-book/src/main/java/com/baeldung/spring/cloud/bootstrap/svcbook/SecurityConfig.java @@ -1,36 +1,37 @@ package com.baeldung.spring.cloud.bootstrap.svcbook; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.HttpMethod; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; -import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.web.SecurityFilterChain; @EnableWebSecurity @Configuration -public class SecurityConfig extends WebSecurityConfigurerAdapter { +public class SecurityConfig { @Autowired - public void configureGlobal1(AuthenticationManagerBuilder auth) throws Exception { - //try in memory auth with no users to support the case that this will allow for users that are logged in to go anywhere + public void registerAuthProvider(AuthenticationManagerBuilder auth) throws Exception { auth.inMemoryAuthentication(); } - @Override - protected void configure(HttpSecurity http) throws Exception { - http.httpBasic() + @Bean + public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { + return http.authorizeHttpRequests((auth) -> auth.antMatchers(HttpMethod.GET, "/books") + .permitAll() + .antMatchers(HttpMethod.GET, "/books/*") + .permitAll() + .antMatchers(HttpMethod.POST, "/books") + .hasRole("ADMIN") + .antMatchers(HttpMethod.PATCH, "/books/*") + .hasRole("ADMIN") + .antMatchers(HttpMethod.DELETE, "/books/*") + .hasRole("ADMIN")) + .csrf() .disable() - .authorizeRequests() - .antMatchers(HttpMethod.GET, "/books").permitAll() - .antMatchers(HttpMethod.GET, "/books/*").permitAll() - .antMatchers(HttpMethod.POST, "/books").hasRole("ADMIN") - .antMatchers(HttpMethod.PATCH, "/books/*").hasRole("ADMIN") - .antMatchers(HttpMethod.DELETE, "/books/*").hasRole("ADMIN") - .anyRequest().authenticated() - .and() - .csrf() - .disable(); + .build(); } } diff --git a/spring-cloud-modules/spring-cloud-bootstrap/svc-book/src/main/java/com/baeldung/spring/cloud/bootstrap/svcbook/book/BookService.java b/spring-cloud-modules/spring-cloud-bootstrap/svc-book/src/main/java/com/baeldung/spring/cloud/bootstrap/svcbook/book/BookService.java index 106fdad5d9..4ee3112049 100644 --- a/spring-cloud-modules/spring-cloud-bootstrap/svc-book/src/main/java/com/baeldung/spring/cloud/bootstrap/svcbook/book/BookService.java +++ b/spring-cloud-modules/spring-cloud-bootstrap/svc-book/src/main/java/com/baeldung/spring/cloud/bootstrap/svcbook/book/BookService.java @@ -2,7 +2,6 @@ package com.baeldung.spring.cloud.bootstrap.svcbook.book; import java.util.List; import java.util.Map; -import java.util.Optional; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -23,8 +22,8 @@ public class BookService { } public Book findBookById(Long bookId) { - return Optional.ofNullable(bookRepository.findOne(bookId)) - .orElseThrow(() -> new BookNotFoundException("Book not found. ID: " + bookId)); + return bookRepository.findById(bookId) + .orElseThrow(() -> new BookNotFoundException(String.format("Book not found. ID: %s", bookId))); } @Transactional(propagation = Propagation.REQUIRED) @@ -37,7 +36,7 @@ public class BookService { @Transactional(propagation = Propagation.REQUIRED) public void deleteBook(Long bookId) { - bookRepository.delete(bookId); + bookRepository.deleteById(bookId); } @Transactional(propagation = Propagation.REQUIRED) @@ -60,7 +59,8 @@ public class BookService { public Book updateBook(Book book, Long bookId) { Preconditions.checkNotNull(book); Preconditions.checkState(book.getId() == bookId); - Preconditions.checkNotNull(bookRepository.findOne(bookId)); + Preconditions.checkArgument(bookRepository.findById(bookId) + .isPresent()); return bookRepository.save(book); } } diff --git a/spring-cloud-modules/spring-cloud-bootstrap/svc-book/src/main/resources/bootstrap.properties b/spring-cloud-modules/spring-cloud-bootstrap/svc-book/src/main/resources/bootstrap.properties index 481cdc182c..a50048c671 100644 --- a/spring-cloud-modules/spring-cloud-bootstrap/svc-book/src/main/resources/bootstrap.properties +++ b/spring-cloud-modules/spring-cloud-bootstrap/svc-book/src/main/resources/bootstrap.properties @@ -3,5 +3,7 @@ spring.cloud.config.discovery.service-id=config spring.cloud.config.discovery.enabled=true spring.cloud.config.username=configUser spring.cloud.config.password=configPassword +spring.cloud.gateway.discovery.locator.enabled=true +spring.cloud.gateway.discovery.locator.lowerCaseServiceId=true eureka.client.serviceUrl.defaultZone=http://discUser:discPassword@localhost:8082/eureka/ \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-bootstrap/svc-rating/pom.xml b/spring-cloud-modules/spring-cloud-bootstrap/svc-rating/pom.xml index 336c1ff2c6..29ebb4c4bc 100644 --- a/spring-cloud-modules/spring-cloud-bootstrap/svc-rating/pom.xml +++ b/spring-cloud-modules/spring-cloud-bootstrap/svc-rating/pom.xml @@ -10,9 +10,9 @@ com.baeldung - parent-boot-1 + parent-boot-2 0.0.1-SNAPSHOT - ../../../parent-boot-1 + ../../../parent-boot-2 @@ -34,7 +34,11 @@ org.springframework.cloud - spring-cloud-starter-eureka + spring-cloud-starter-bootstrap + + + org.springframework.cloud + spring-cloud-starter-netflix-eureka-client org.springframework.boot @@ -46,7 +50,7 @@ org.springframework.session - spring-session + spring-session-data-redis org.springframework.boot @@ -58,25 +62,29 @@ org.springframework.cloud - spring-cloud-starter-hystrix + spring-cloud-starter-circuitbreaker-resilience4j org.springframework.boot spring-boot-starter-actuator + + org.springframework.cloud + spring-cloud-starter-sleuth + + + org.springframework.cloud + spring-cloud-sleuth-zipkin + com.h2database h2 runtime - - org.springframework.cloud - spring-cloud-starter-zipkin - - Dalston.RELEASE + 2021.0.7 \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/CookieConfig.java b/spring-cloud-modules/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/CookieConfig.java new file mode 100644 index 0000000000..9774c18568 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/CookieConfig.java @@ -0,0 +1,16 @@ +package com.baeldung.spring.cloud.bootstrap.svcrating; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.session.web.http.DefaultCookieSerializer; + +@Configuration +public class CookieConfig { + + @Bean + public DefaultCookieSerializer cookieSerializer() { + DefaultCookieSerializer serializer = new DefaultCookieSerializer(); + serializer.setUseBase64Encoding(false); + return serializer; + } +} \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/RatingServiceApplication.java b/spring-cloud-modules/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/RatingServiceApplication.java index 5a94f19472..1774407d26 100644 --- a/spring-cloud-modules/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/RatingServiceApplication.java +++ b/spring-cloud-modules/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/RatingServiceApplication.java @@ -1,69 +1,18 @@ package com.baeldung.spring.cloud.bootstrap.svcrating; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.cloud.netflix.eureka.EnableEurekaClient; -import org.springframework.cloud.netflix.hystrix.EnableHystrix; -import org.springframework.cloud.sleuth.metric.SpanMetricReporter; -import org.springframework.cloud.sleuth.zipkin.HttpZipkinSpanReporter; -import org.springframework.cloud.sleuth.zipkin.ZipkinProperties; -import org.springframework.cloud.sleuth.zipkin.ZipkinSpanReporter; +import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.context.annotation.AdviceMode; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Primary; import org.springframework.core.Ordered; -import org.springframework.core.annotation.Order; import org.springframework.transaction.annotation.EnableTransactionManagement; -import org.springframework.web.client.RestTemplate; - -import com.netflix.appinfo.InstanceInfo; -import com.netflix.discovery.EurekaClient; -import com.netflix.hystrix.contrib.javanica.aop.aspectj.HystrixCommandAspect; - -import zipkin.Span; @SpringBootApplication -@EnableEurekaClient -@EnableHystrix -@EnableTransactionManagement(order=Ordered.LOWEST_PRECEDENCE, mode=AdviceMode.ASPECTJ) +@EnableDiscoveryClient +@EnableTransactionManagement(order = Ordered.LOWEST_PRECEDENCE, mode = AdviceMode.ASPECTJ) public class RatingServiceApplication { - @Autowired - private EurekaClient eurekaClient; - @Autowired - private SpanMetricReporter spanMetricReporter; - @Autowired - private ZipkinProperties zipkinProperties; - @Value("${spring.sleuth.web.skipPattern}") - private String skipPattern; public static void main(String[] args) { SpringApplication.run(RatingServiceApplication.class, args); } - - @Bean - public ZipkinSpanReporter makeZipkinSpanReporter() { - return new ZipkinSpanReporter() { - private HttpZipkinSpanReporter delegate; - private String baseUrl; - - @Override - public void report(Span span) { - InstanceInfo instance = eurekaClient.getNextServerFromEureka("zipkin", false); - if (baseUrl == null || !instance.getHomePageUrl().equals(baseUrl)) { - baseUrl = instance.getHomePageUrl(); - } - delegate = new HttpZipkinSpanReporter(new RestTemplate(), baseUrl, zipkinProperties.getFlushInterval(), spanMetricReporter); - if (!span.name.matches(skipPattern)) delegate.report(span); - } - }; - } - - @Bean - @Primary - @Order(value=Ordered.HIGHEST_PRECEDENCE) - public HystrixCommandAspect hystrixAspect() { - return new HystrixCommandAspect(); - } } \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/SecurityConfig.java b/spring-cloud-modules/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/SecurityConfig.java index 9b6afc8059..f470946e1d 100644 --- a/spring-cloud-modules/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/SecurityConfig.java +++ b/spring-cloud-modules/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/SecurityConfig.java @@ -1,39 +1,41 @@ package com.baeldung.spring.cloud.bootstrap.svcrating; -import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.HttpMethod; -import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; -import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.provisioning.InMemoryUserDetailsManager; +import org.springframework.security.web.SecurityFilterChain; @EnableWebSecurity @Configuration -public class SecurityConfig extends WebSecurityConfigurerAdapter { +public class SecurityConfig { - @Autowired - public void configureGlobal1(AuthenticationManagerBuilder auth) throws Exception { - //try in memory auth with no users to support the case that this will allow for users that are logged in to go anywhere - auth.inMemoryAuthentication(); + @Bean + public UserDetailsService users() { + return new InMemoryUserDetailsManager(); } - @Override - protected void configure(HttpSecurity http) throws Exception { - http - .authorizeRequests() - .regexMatchers("^/ratings\\?bookId.*$").authenticated() - .antMatchers(HttpMethod.POST,"/ratings").authenticated() - .antMatchers(HttpMethod.PATCH,"/ratings/*").hasRole("ADMIN") - .antMatchers(HttpMethod.DELETE,"/ratings/*").hasRole("ADMIN") - .antMatchers(HttpMethod.GET,"/ratings").hasRole("ADMIN") - .antMatchers(HttpMethod.GET,"/hystrix").authenticated() - .anyRequest().authenticated() + @Bean + public SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception { + return httpSecurity.authorizeHttpRequests((auth) -> auth.regexMatchers("^/ratings\\?bookId.*$") + .authenticated() + .antMatchers(HttpMethod.POST, "/ratings") + .authenticated() + .antMatchers(HttpMethod.PATCH, "/ratings/*") + .hasRole("ADMIN") + .antMatchers(HttpMethod.DELETE, "/ratings/*") + .hasRole("ADMIN") + .antMatchers(HttpMethod.GET, "/ratings") + .hasRole("ADMIN") + .anyRequest() + .authenticated()) + .httpBasic() .and() - .httpBasic().and() - .csrf() - .disable(); - - + .csrf() + .disable() + .build(); } } diff --git a/spring-cloud-modules/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/SessionConfig.java b/spring-cloud-modules/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/SessionConfig.java index 6e8fcd10d4..c0e067026d 100644 --- a/spring-cloud-modules/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/SessionConfig.java +++ b/spring-cloud-modules/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/SessionConfig.java @@ -5,24 +5,24 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; import org.springframework.core.env.Environment; -import org.springframework.data.redis.connection.jedis.JedisConnectionFactory; +import org.springframework.data.redis.connection.RedisStandaloneConfiguration; +import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession; import org.springframework.session.web.context.AbstractHttpSessionApplicationInitializer; @Configuration @EnableRedisHttpSession public class SessionConfig extends AbstractHttpSessionApplicationInitializer { + @Autowired - Environment properties; - + private Environment properties; + @Bean @Primary - public JedisConnectionFactory connectionFactory() { - JedisConnectionFactory factory = new JedisConnectionFactory(); - factory.setHostName(properties.getProperty("spring.redis.host","localhost")); - factory.setPort(properties.getProperty("spring.redis.port", Integer.TYPE,6379)); - factory.afterPropertiesSet(); - factory.setUsePool(true); - return factory; + public LettuceConnectionFactory redisConnectionFactory() { + RedisStandaloneConfiguration redisConfiguration = new RedisStandaloneConfiguration(); + redisConfiguration.setHostName(properties.getProperty("spring.redis.host", "localhost")); + redisConfiguration.setPort(properties.getProperty("spring.redis.port", Integer.TYPE, 6379)); + return new LettuceConnectionFactory(redisConfiguration); } } diff --git a/spring-cloud-modules/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/rating/RatingCacheRepository.java b/spring-cloud-modules/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/rating/RatingCacheRepository.java index d9f3a3584e..1263093b80 100644 --- a/spring-cloud-modules/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/rating/RatingCacheRepository.java +++ b/spring-cloud-modules/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/rating/RatingCacheRepository.java @@ -6,21 +6,21 @@ import java.util.stream.Collectors; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.redis.connection.jedis.JedisConnectionFactory; +import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; import org.springframework.data.redis.core.SetOperations; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.data.redis.core.ValueOperations; +import org.springframework.stereotype.Repository; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; -import org.springframework.stereotype.Repository; @Repository public class RatingCacheRepository implements InitializingBean { @Autowired - private JedisConnectionFactory cacheConnectionFactory; + private LettuceConnectionFactory cacheConnectionFactory; private StringRedisTemplate redisTemplate; private ValueOperations valueOps; diff --git a/spring-cloud-modules/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/rating/RatingService.java b/spring-cloud-modules/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/rating/RatingService.java index 395ff50bd7..e02803bff3 100644 --- a/spring-cloud-modules/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/rating/RatingService.java +++ b/spring-cloud-modules/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/rating/RatingService.java @@ -2,7 +2,6 @@ package com.baeldung.spring.cloud.bootstrap.svcrating.rating; import java.util.List; import java.util.Map; -import java.util.Optional; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -10,7 +9,8 @@ import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; import com.google.common.base.Preconditions; -import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand; + +import io.github.resilience4j.circuitbreaker.annotation.CircuitBreaker; @Service @Transactional(readOnly = true) @@ -22,31 +22,31 @@ public class RatingService { @Autowired private RatingCacheRepository cacheRepository; - @HystrixCommand(commandKey = "ratingsByBookIdFromDB", fallbackMethod = "findCachedRatingsByBookId") + @CircuitBreaker(name = "ratingsByBookIdFromDB", fallbackMethod = "findCachedRatingsByBookId") public List findRatingsByBookId(Long bookId) { return ratingRepository.findRatingsByBookId(bookId); } - public List findCachedRatingsByBookId(Long bookId) { + public List findCachedRatingsByBookId(Long bookId, Exception exception) { return cacheRepository.findCachedRatingsByBookId(bookId); } - @HystrixCommand(commandKey = "ratingsFromDB", fallbackMethod = "findAllCachedRatings") + @CircuitBreaker(name = "ratingsFromDB", fallbackMethod = "findAllCachedRatings") public List findAllRatings() { return ratingRepository.findAll(); } - public List findAllCachedRatings() { + public List findAllCachedRatings(Exception exception) { return cacheRepository.findAllCachedRatings(); } - @HystrixCommand(commandKey = "ratingsByIdFromDB", fallbackMethod = "findCachedRatingById", ignoreExceptions = { RatingNotFoundException.class }) + @CircuitBreaker(name = "ratingsByIdFromDB", fallbackMethod = "findCachedRatingById") public Rating findRatingById(Long ratingId) { - return Optional.ofNullable(ratingRepository.findOne(ratingId)) + return ratingRepository.findById(ratingId) .orElseThrow(() -> new RatingNotFoundException("Rating not found. ID: " + ratingId)); } - public Rating findCachedRatingById(Long ratingId) { + public Rating findCachedRatingById(Long ratingId, Exception exception) { return cacheRepository.findCachedRatingById(ratingId); } @@ -62,7 +62,7 @@ public class RatingService { @Transactional(propagation = Propagation.REQUIRED) public void deleteRating(Long ratingId) { - ratingRepository.delete(ratingId); + ratingRepository.deleteById(ratingId); cacheRepository.deleteRating(ratingId); } @@ -86,7 +86,7 @@ public class RatingService { public Rating updateRating(Rating rating, Long ratingId) { Preconditions.checkNotNull(rating); Preconditions.checkState(rating.getId() == ratingId); - Preconditions.checkNotNull(ratingRepository.findOne(ratingId)); + Preconditions.checkNotNull(ratingRepository.findById(ratingId)); return ratingRepository.save(rating); } diff --git a/spring-cloud-modules/spring-cloud-bootstrap/svc-rating/src/main/resources/bootstrap.properties b/spring-cloud-modules/spring-cloud-bootstrap/svc-rating/src/main/resources/bootstrap.properties index be5cf7f1e1..846bc4c7aa 100644 --- a/spring-cloud-modules/spring-cloud-bootstrap/svc-rating/src/main/resources/bootstrap.properties +++ b/spring-cloud-modules/spring-cloud-bootstrap/svc-rating/src/main/resources/bootstrap.properties @@ -3,5 +3,7 @@ spring.cloud.config.discovery.service-id=config spring.cloud.config.discovery.enabled=true spring.cloud.config.username=configUser spring.cloud.config.password=configPassword +spring.cloud.gateway.discovery.locator.enabled=true +spring.cloud.gateway.discovery.locator.lowerCaseServiceId=true eureka.client.serviceUrl.defaultZone=http://discUser:discPassword@localhost:8082/eureka/ diff --git a/spring-cloud-modules/spring-cloud-bootstrap/zipkin/README.md b/spring-cloud-modules/spring-cloud-bootstrap/zipkin/README.md new file mode 100644 index 0000000000..66f150ede0 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-bootstrap/zipkin/README.md @@ -0,0 +1,19 @@ +# Zipkin server + +Zipkin project [deprecated custom server](https://github.com/openzipkin/zipkin/tree/master/zipkin-server). +It's no longer possible to run a custom Zipkin server compatible with Spring Cloud or even Spring Boot. + +The best approach to run a Zipkin server is to use docker. We provided a docker-compose file that you can run: + +```bash +$ docker compose up -d +``` + +After that Zipkin is accessible via [http://localhost:9411](http://localhost:9411) + +Alternatively, you can run the Zipkin Jar file, + +```bash +$ curl -sSL https://zipkin.io/quickstart.sh | bash -s +$ java -jar zipkin.jar +``` \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-bootstrap/zipkin/docker-compose.yml b/spring-cloud-modules/spring-cloud-bootstrap/zipkin/docker-compose.yml new file mode 100644 index 0000000000..20528dca8f --- /dev/null +++ b/spring-cloud-modules/spring-cloud-bootstrap/zipkin/docker-compose.yml @@ -0,0 +1,6 @@ +version: "3.9" +services: + zipkin: + image: openzipkin/zipkin + ports: + - 9411:9411 \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-bootstrap/zipkin/pom.xml b/spring-cloud-modules/spring-cloud-bootstrap/zipkin/pom.xml deleted file mode 100644 index b515661a00..0000000000 --- a/spring-cloud-modules/spring-cloud-bootstrap/zipkin/pom.xml +++ /dev/null @@ -1,53 +0,0 @@ - - - 4.0.0 - zipkin - 1.0.0-SNAPSHOT - zipkin - - - com.baeldung - parent-boot-1 - 0.0.1-SNAPSHOT - ../../../parent-boot-1 - - - - - - org.springframework.cloud - spring-cloud-dependencies - ${spring-cloud-dependencies.version} - pom - import - - - - - - - org.springframework.cloud - spring-cloud-starter-config - - - org.springframework.cloud - spring-cloud-starter-eureka - - - io.zipkin.java - zipkin-server - - - io.zipkin.java - zipkin-autoconfigure-ui - runtime - - - - - Brixton.SR7 - - - \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-bootstrap/zipkin/src/main/java/com/baeldung/spring/cloud/bootstrap/zipkin/ZipkinApplication.java b/spring-cloud-modules/spring-cloud-bootstrap/zipkin/src/main/java/com/baeldung/spring/cloud/bootstrap/zipkin/ZipkinApplication.java deleted file mode 100644 index d757567156..0000000000 --- a/spring-cloud-modules/spring-cloud-bootstrap/zipkin/src/main/java/com/baeldung/spring/cloud/bootstrap/zipkin/ZipkinApplication.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.baeldung.spring.cloud.bootstrap.zipkin; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.cloud.netflix.eureka.EnableEurekaClient; -import zipkin.server.EnableZipkinServer; - -@SpringBootApplication -@EnableEurekaClient -@EnableZipkinServer -public class ZipkinApplication { - public static void main(String[] args) { - SpringApplication.run(ZipkinApplication.class, args); - } -} diff --git a/spring-cloud-modules/spring-cloud-bootstrap/zipkin/src/main/resources/bootstrap.properties b/spring-cloud-modules/spring-cloud-bootstrap/zipkin/src/main/resources/bootstrap.properties deleted file mode 100644 index 9569179a4f..0000000000 --- a/spring-cloud-modules/spring-cloud-bootstrap/zipkin/src/main/resources/bootstrap.properties +++ /dev/null @@ -1,7 +0,0 @@ -spring.cloud.config.name=zipkin -spring.cloud.config.discovery.service-id=config -spring.cloud.config.discovery.enabled=true -spring.cloud.config.username=configUser -spring.cloud.config.password=configPassword - -eureka.client.serviceUrl.defaultZone=http://discUser:discPassword@localhost:8082/eureka/ \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-bootstrap/zipkin/src/main/resources/logback.xml b/spring-cloud-modules/spring-cloud-bootstrap/zipkin/src/main/resources/logback.xml deleted file mode 100644 index 7d900d8ea8..0000000000 --- a/spring-cloud-modules/spring-cloud-bootstrap/zipkin/src/main/resources/logback.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n - - - - - - - - \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-bootstrap/zipkin/src/test/java/com/baeldung/SpringContextTest.java b/spring-cloud-modules/spring-cloud-bootstrap/zipkin/src/test/java/com/baeldung/SpringContextTest.java deleted file mode 100644 index 71e67df191..0000000000 --- a/spring-cloud-modules/spring-cloud-bootstrap/zipkin/src/test/java/com/baeldung/SpringContextTest.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.baeldung; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.junit4.SpringRunner; - -import com.baeldung.spring.cloud.bootstrap.zipkin.ZipkinApplication; - -@RunWith(SpringRunner.class) -@SpringBootTest(classes = ZipkinApplication.class) -public class SpringContextTest { - - @Test - public void whenSpringContextIsBootstrapped_thenNoExceptions() { - } -}