-
-
Notifications
You must be signed in to change notification settings - Fork 27.3k
Microservices pattern : Self-Registration #3245
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
84042e8
6ad64ff
afc7862
b902012
13bc41f
796b421
93c6653
030643b
20d34ec
c2c13ae
2bd955d
17d019f
8b08728
142fe8b
d06d61e
aa788f0
b47a00e
6b1c680
7d0152b
ab2c8ac
c4b33cd
edb73c1
84b6676
fcf605d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,236 @@ | ||
| --- | ||
| title: "Microservices Self-Registration Pattern in Java with Spring Boot and Eureka" | ||
| shortTitle: Microservices Pattern - Self-Registration | ||
| description: "Dynamically register and discover Java microservices using Spring Boot and Eureka for resilient, scalable communication." | ||
| category: Service Discovery | ||
| language: en | ||
| tag: | ||
| - Microservices | ||
| - Self-Registration | ||
| - Service Discovery | ||
| - Eureka | ||
| - Spring Boot | ||
| - Spring Cloud | ||
| - Java | ||
| - Dynamic Configuration | ||
| - Resilience | ||
| --- | ||
|
|
||
| ## Intent of Microservices Self-Registration Pattern | ||
|
|
||
| The intent of the Self-Registration pattern is to enable microservices to automatically announce their presence and location to a central registry (like Eureka) upon startup, simplifying service discovery and allowing other services to find and communicate with them without manual configuration or hardcoded addresses. This promotes dynamic and resilient microservices architectures. | ||
|
|
||
| ## What's in the Project | ||
|
|
||
| This project demonstrates the Microservices Self-Registration pattern using Java, Spring Boot (version 3.4.4), and Eureka for service discovery. It consists of three main components: a Eureka Server and two simple microservices, a Greeting Service and a Context Service, which discover and communicate with each other. | ||
|
|
||
| ### Project Structure | ||
| * **`eureka-server`:** The central service registry where microservices register themselves. | ||
| * **`greeting-service`:** A simple microservice that provides a greeting. | ||
| * **`context-service`:** A microservice that consumes the greeting from the Greeting Service and adds context. | ||
|
|
||
| The **Eureka Server** acts as the discovery service. Microservices register themselves with the Eureka Server, providing their network location. | ||
|
|
||
| package com.example.eurekaserver; | ||
|
|
||
| import org.springframework.boot.SpringApplication; | ||
| import org.springframework.boot.autoconfigure.SpringBootApplication; | ||
| import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; | ||
|
|
||
| @SpringBootApplication | ||
| @EnableEurekaServer | ||
| public class EurekaServerApplication { | ||
|
|
||
| public static void main(String[] args) { | ||
| SpringApplication.run(EurekaServerApplication.class, args); | ||
| } | ||
| } | ||
|
|
||
| The **Greeting Service** is a simple microservice that exposes an endpoint to retrieve a greeting. | ||
|
|
||
| package com.example.greetingservice; | ||
|
|
||
| import org.springframework.boot.SpringApplication; | ||
| import org.springframework.boot.autoconfigure.SpringBootApplication; | ||
| import org.springframework.cloud.client.discovery.EnableDiscoveryClient; | ||
|
|
||
| @SpringBootApplication | ||
| @EnableDiscoveryClient | ||
| public class GreetingServiceApplication { | ||
|
|
||
| public static void main(String[] args) { | ||
| SpringApplication.run(GreetingServiceApplication.class, args); | ||
| } | ||
| } | ||
|
|
||
| Greeting Controller | ||
|
|
||
| package com.example.greetingservice.controller; | ||
|
|
||
| import org.springframework.web.bind.annotation.GetMapping; | ||
| import org.springframework.web.bind.annotation.RestController; | ||
|
|
||
| @RestController | ||
| public class GreetingController { | ||
|
|
||
| @GetMapping("/greeting") | ||
| public String getGreeting() { | ||
| return "Hello"; | ||
| } | ||
| } | ||
|
|
||
| The **Context Service** consumes the greeting from the Greeting Service using OpenFeign and adds contextual information. | ||
|
|
||
| package com.example.contextservice; | ||
|
|
||
| import org.springframework.boot.SpringApplication; | ||
| import org.springframework.boot.autoconfigure.SpringBootApplication; | ||
| import org.springframework.cloud.client.discovery.EnableDiscoveryClient; | ||
| import org.springframework.cloud.openfeign.EnableFeignClients; | ||
|
|
||
| @SpringBootApplication | ||
| @EnableDiscoveryClient | ||
| @EnableFeignClients | ||
| public class ContextServiceApplication { | ||
|
|
||
| public static void main(String[] args) { | ||
| SpringApplication.run(ContextServiceApplication.class, args); | ||
| } | ||
| } | ||
|
|
||
| Feign Client : Spring Cloud OpenFeign is a declarative HTTP client that makes it easier to consume RESTful web services in your Spring Cloud applications. Instead of writing the boilerplate code for making HTTP requests, you simply declare interface with annotations that describe the web service you want to consume. | ||
|
|
||
| package com.example.contextservice.client; | ||
|
|
||
| import org.springframework.cloud.openfeign.FeignClient; | ||
| import org.springframework.web.bind.annotation.GetMapping; | ||
|
|
||
| @FeignClient(name = "greeting-service") | ||
| public interface GreetingServiceClient { | ||
|
|
||
| @GetMapping("/greeting") | ||
| String getGreeting(); | ||
| } | ||
|
|
||
| Context Controller | ||
|
|
||
| package com.example.contextservice.controller; | ||
|
|
||
| import com.example.contextservice.client.GreetingServiceClient; | ||
| import org.springframework.beans.factory.annotation.Autowired; | ||
| import org.springframework.beans.factory.annotation.Value; | ||
| import org.springframework.web.bind.annotation.GetMapping; | ||
| import org.springframework.web.bind.annotation.RestController; | ||
|
|
||
| @RestController | ||
| public class ContextController { | ||
|
|
||
| @Autowired | ||
| private GreetingServiceClient greetingServiceClient; | ||
|
|
||
| @Value("${user.region}") | ||
| private String userRegion; | ||
|
|
||
| @GetMapping("/context") | ||
| public String getContext() { | ||
| String greeting = greetingServiceClient.getGreeting(); | ||
| return "The Greeting Service says: " + greeting + " from " + userRegion + "!"; | ||
| } | ||
| } | ||
|
|
||
| 1. Both the Greeting Service and the Context Service register themselves with the Eureka Server upon startup using the _@EnableDiscoveryClient_ annotation. | ||
| 2. The Context Service, annotated with _@EnableFeignClients_, uses the GreetingServiceClient interface with _@FeignClient(name = "greeting-service")_ to declare its intent to communicate with the service named "greeting-service" in Eureka. | ||
| 3. When the /context endpoint of the Context Service is accessed, it calls the _getGreeting()_ method of the GreetingServiceClient. | ||
| 4. OpenFeign, leveraging the service discovery information from Eureka, resolves the network location of an available instance of the Greeting Service and makes an HTTP GET request to its /greeting endpoint. | ||
| 5. The Greeting Service responds with "Hello", and the Context Service then adds the configured user.region to the response. | ||
|
|
||
| This project utilizes Spring Boot Actuator, which is included as a dependency, to provide health check endpoints for each microservice. These endpoints (e.g., /actuator/health) can be used by Eureka Server to monitor the health of the registered instances. | ||
|
|
||
| ## Steps to use for this Project | ||
|
|
||
| Prerequisites: | ||
| - Java Development Kit (JDK): Make sure you have a compatible JDK installed (ideally Java 17 or later, as Spring Boot 3.x requires it). | ||
| - Maven or Gradle: You'll need either Maven (if you chose Maven during Spring Initializr setup) or Gradle (if you chose Gradle) installed on your system. | ||
| - An IDE (Optional but Recommended): IntelliJ IDEA, Eclipse, or Spring Tool Suite (STS) can make it easier to work with the project. | ||
| - Web Browser: You'll need a web browser to access the Eureka dashboard and the microservice endpoints. | ||
|
|
||
| Step : | ||
| - You'll need to build each microservice individually. Navigate to the root directory of each project in your terminal or command prompt and run the appropriate build command: | ||
| _cd eurekaserver | ||
| mvn clean install | ||
| cd ../greetingservice | ||
| mvn clean install | ||
| cd ../contextservice | ||
| mvn clean install_ | ||
| Step : | ||
| - Navigate to the root directory of your eurekaserver project in your terminal or command prompt | ||
| _mvn spring-boot:run_ | ||
| - Wait for the Eureka Server application to start. You should see logs in the console indicating that it has started on port 8761 (as configured). | ||
| - Open your web browser and go to http://localhost:8761/. You should see the Eureka Server dashboard. Initially, the list of registered instances will be empty. | ||
| Step : | ||
| - Run the Greeting Service | ||
| - Open a new terminal or command prompt. | ||
| - Navigate to the root directory of your greetingservice project. | ||
| - Run the Spring Boot application: _mvn spring-boot:run_ | ||
| - Wait for the Greeting Service to start. You should see logs indicating that it has registered with the Eureka Server. | ||
| - Go back to your Eureka Server dashboard in the browser (http://localhost:8761/). You should now see GREETINGSERVICE listed under the "Instances currently registered with Eureka". Its status should be "UP". | ||
| Step : | ||
| - Run the Context Service | ||
| - Open a new terminal or command prompt. | ||
| - Navigate to the root directory of your contextservice project. | ||
| - Run the Spring Boot application: _mvn spring-boot:run_ | ||
| - Wait for the Context Service to start. You should see logs indicating that it has registered with the Eureka Server. | ||
| - Go back to your Eureka Server dashboard in the browser (http://localhost:8761/). You should now see CONTEXTSERVICE listed under the "Instances currently registered with Eureka". Its status should be "UP". | ||
| STEP : | ||
| - Test the Greeting Service Directly: Open your web browser and go to http://localhost:8081/greeting. You should see the output: Hello. | ||
| - Test the Context Service (which calls the Greeting Service): Open your web browser and go to http://localhost:8082/context. You should see the output: The Greeting Service says: Hello from Chennai, Tamil Nadu, India!. This confirms that the Context Service successfully discovered and called the Greeting Service through Eureka. | ||
|
|
||
| Optional: Check Health Endpoints | ||
|
|
||
| You can also verify the health status of each service using Spring Boot Actuator: | ||
| - Greeting Service Health: http://localhost:8081/actuator/health (should return {"status":"UP"}) | ||
| - Context Service Health: http://localhost:8082/actuator/health (should return {"status":"UP"}) | ||
| - Eureka Server Health: http://localhost:8761/actuator/health (should return {"status":"UP"}) | ||
|
|
||
| ## When to use Microservices Self-Registration Pattern | ||
|
|
||
| - **Dynamic Environments:** When your microservices are frequently deployed, scaled up or down, or their network locations (IP addresses and ports) change often. This is common in cloud-based or containerized environments (like Docker and Kubernetes). | ||
| - **Large Number of Services:** As the number of microservices in your system grows, manually managing their configurations and dependencies becomes complex and error-prone. Self-registration automates this process. | ||
| - **Need for Automatic Service** Discovery: When services need to find and communicate with each other without hardcoding network locations. This allows for greater flexibility and reduces coupling. | ||
| - **Implementing Load Balancing:** Service registries like Eureka often integrate with load balancers, enabling them to automatically distribute traffic across available instances of a service that have registered themselves. | ||
| - **Improving System Resilience:** If a service instance fails, the registry will eventually be updated (through heartbeats or health checks), and other services can discover and communicate with the remaining healthy instances. | ||
| - **DevOps Automation:** This pattern aligns well with DevOps practices, allowing for more automated deployment and management of microservices. | ||
|
|
||
| ## Real-World Applications of Self-Registration pattern | ||
|
|
||
| - E-Commerce platforms have numerous independent services for product catalogs, order processing, payments, shipping, etc. Self-registration allows these services to dynamically discover and communicate with each other as the system scales during peak loads or as new features are deployed. | ||
| - Streaming services rely on many microservices for user authentication, content delivery networks (CDNs), recommendation engines, billing systems, etc. Self-registration helps these services adapt to varying user demands and infrastructure changes. | ||
| - Social media These platforms use microservices for managing user profiles, timelines, messaging, advertising, and more. Self-registration enables these services to scale independently and handle the massive traffic they experience. | ||
|
|
||
| ## Advantages | ||
|
|
||
| - Microservices can dynamically locate and communicate with each other without needing to know their specific network addresses beforehand. This is crucial in dynamic environments where IP addresses and ports can change frequently. | ||
| - Reduces the need for manual configuration of service locations in each microservice. Services don't need to be updated every time another service's location changes. | ||
| - Scaling microservices up or down becomes easier. New instances automatically register themselves with the service registry, making them immediately discoverable by other services without manual intervention. | ||
| - If a service instance fails, it will eventually stop sending heartbeats to the registry and will be removed. Consumers can then discover and connect to other healthy instances, improving the system's overall resilience. | ||
| - Services are less tightly coupled as they don't have direct dependencies on the physical locations of other services. This makes deployments and updates more flexible. | ||
| - Service registries often integrate with load balancers. When a new service instance registers, the load balancer can automatically include it in the pool of available instances, distributing traffic effectively. | ||
| - Microservices can be deployed across different environments (development, testing, production) without significant changes to their discovery mechanism, as long as they are configured to connect to the appropriate service registry for that environment. | ||
|
|
||
| ## Trade-offs | ||
|
|
||
| - Introducing a service registry adds another component to your system that needs to be set up, managed, and monitored. This increases the overall complexity of the infrastructure. | ||
| - The service registry itself becomes a critical component. If the service registry becomes unavailable, it can disrupt communication between microservices. High availability for the service registry is therefore essential. | ||
| - Microservices need to communicate with the service registry for registration, sending heartbeats, and querying for other services. This can lead to increased network traffic. | ||
| - There might be a slight delay between when a microservice instance starts and when it becomes fully registered and discoverable in the service registry. This needs to be considered, especially during scaling events. | ||
| - You need to consider how your microservices will behave if they fail to register with the service registry upon startup. Robust error handling and retry mechanisms are often necessary. | ||
| - Microservices need to include and configure client libraries (like the Eureka Discovery Client) to interact with the service registry. This adds a dependency to your application code. | ||
| - In distributed service registries, ensuring consistency of the registry data across all nodes can be a challenge. Different registries might have different consistency models (e.g., eventual consistency). | ||
|
|
||
| ## References | ||
|
|
||
| - Microservices Patterns: https://microservices.io/ | ||
| - Eureka Documentation: https://github.com/Netflix/eureka | https://spring.io/projects/spring-cloud-netflix | ||
| - Spring Boot Documentation: https://spring.io/projects/spring-boot | ||
| - Spring Cloud OpenFeignDocumentation: https://spring.io/projects/spring-cloud-openfeign | ||
| - Spring Boot Actuator Documentation: https://www.baeldung.com/spring-boot-actuators |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| /mvnw text eol=lf | ||
| *.cmd text eol=crlf |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| HELP.md | ||
| target/ | ||
| !.mvn/wrapper/maven-wrapper.jar | ||
| !**/src/main/**/target/ | ||
| !**/src/test/**/target/ | ||
|
|
||
| ### STS ### | ||
| .apt_generated | ||
| .classpath | ||
| .factorypath | ||
| .project | ||
| .settings | ||
| .springBeans | ||
| .sts4-cache | ||
|
|
||
| ### IntelliJ IDEA ### | ||
| .idea | ||
| *.iws | ||
| *.iml | ||
| *.ipr | ||
|
|
||
| ### NetBeans ### | ||
| /nbproject/private/ | ||
| /nbbuild/ | ||
| /dist/ | ||
| /nbdist/ | ||
| /.nb-gradle/ | ||
| build/ | ||
| !**/src/main/**/build/ | ||
| !**/src/test/**/build/ | ||
|
|
||
| ### VS Code ### | ||
| .vscode/ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,73 @@ | ||
| <?xml version="1.0" encoding="UTF-8"?> | ||
| <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
| xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||
| <modelVersion>4.0.0</modelVersion> | ||
| <parent> | ||
| <groupId>org.springframework.boot</groupId> | ||
| <artifactId>spring-boot-starter-parent</artifactId> | ||
| <version>3.4.4</version> | ||
| <relativePath/> </parent> | ||
| <groupId>com.learning</groupId> | ||
| <artifactId>contextservice</artifactId> | ||
| <version>0.0.1-SNAPSHOT</version> | ||
| <name>contextservice</name> | ||
| <description>contextservice</description> | ||
|
|
||
| <properties> | ||
| <spring-cloud.version>2024.0.1</spring-cloud.version> | ||
| </properties> | ||
| <dependencies> | ||
| <dependency> | ||
| <groupId>org.springframework.boot</groupId> | ||
| <artifactId>spring-boot-starter-web</artifactId> | ||
| </dependency> | ||
| <dependency> | ||
| <groupId>org.projectlombok</groupId> | ||
| <artifactId>lombok</artifactId> | ||
| <version>1.18.38</version> | ||
| <scope>provided</scope> | ||
| </dependency> | ||
| <dependency> | ||
| <groupId>org.springframework.cloud</groupId> | ||
| <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> | ||
| </dependency> | ||
| <dependency> | ||
| <groupId>org.springframework.boot</groupId> | ||
| <artifactId>spring-boot-starter-actuator</artifactId> | ||
| </dependency> | ||
| <dependency> | ||
| <groupId>org.springframework.cloud</groupId> | ||
| <artifactId>spring-cloud-starter-openfeign</artifactId> | ||
| </dependency> | ||
| <dependency> | ||
| <groupId>org.springframework.boot</groupId> | ||
| <artifactId>spring-boot-starter-test</artifactId> | ||
| <scope>test</scope> | ||
| </dependency> | ||
| </dependencies> | ||
| <dependencyManagement> | ||
| <dependencies> | ||
| <dependency> | ||
| <groupId>org.springframework.cloud</groupId> | ||
| <artifactId>spring-cloud-dependencies</artifactId> | ||
| <version>${spring-cloud.version}</version> | ||
| <type>pom</type> | ||
| <scope>import</scope> | ||
| </dependency> | ||
| </dependencies> | ||
| </dependencyManagement> | ||
|
|
||
| <build> | ||
| <plugins> | ||
| <plugin> | ||
| <groupId>org.springframework.boot</groupId> | ||
| <artifactId>spring-boot-maven-plugin</artifactId> | ||
| </plugin> | ||
| <plugin> | ||
| <groupId>org.apache.maven.plugins</groupId> | ||
| <artifactId>maven-compiler-plugin</artifactId> | ||
| </plugin> | ||
| </plugins> | ||
| </build> | ||
|
|
||
| </project> | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| package com.learning.contextservice; | ||
|
|
||
| import org.springframework.boot.SpringApplication; | ||
| import org.springframework.boot.autoconfigure.SpringBootApplication; | ||
| import org.springframework.cloud.client.discovery.EnableDiscoveryClient; | ||
| import org.springframework.cloud.openfeign.EnableFeignClients; | ||
|
|
||
| @SpringBootApplication | ||
| @EnableDiscoveryClient | ||
| @EnableFeignClients | ||
| public class ContextserviceApplication { | ||
|
|
||
| public static void main(String[] args) { | ||
| SpringApplication.run(ContextserviceApplication.class, args); | ||
| } | ||
|
|
||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,42 @@ | ||
| package com.learning.contextservice; | ||
|
|
||
| import org.slf4j.Logger; | ||
| import org.slf4j.LoggerFactory; | ||
| import org.springframework.boot.actuate.health.Health; | ||
| import org.springframework.boot.actuate.health.HealthIndicator; | ||
| import org.springframework.scheduling.annotation.Scheduled; | ||
| import org.springframework.stereotype.Component; | ||
|
|
||
|
|
||
| @Component("myCustomHealthCheck") | ||
| public class MyCustomHealthCheck implements HealthIndicator { | ||
|
|
||
| private static final Logger log = LoggerFactory.getLogger(MyCustomHealthCheck.class); | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use Lombok annotation @slf4j for logging |
||
|
|
||
| private volatile boolean isHealthy = true; | ||
|
|
||
| @Scheduled(fixedRate = 5000) // Run every 5 seconds | ||
| public void updateHealthStatus() { | ||
| // Perform checks here to determine the current health | ||
| // For example, check database connectivity, external service availability, etc. | ||
| isHealthy = performHealthCheck(); | ||
| log.info("Update health status : {}", isHealthy); | ||
| } | ||
|
|
||
| boolean performHealthCheck() { | ||
| boolean current = System.currentTimeMillis() % 10000 < 5000; // Simulate fluctuating health | ||
| log.debug("Performing health check, current status: {}", current); | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Remove debug-level logging not to spam the output |
||
| return current; // Simulate fluctuating health | ||
| } | ||
|
|
||
| @Override | ||
| public Health health() { | ||
| if (isHealthy) { | ||
| log.info("Health check successful, service is UP"); | ||
| return Health.up().withDetail("message", "Service is running and scheduled checks are OK").build(); | ||
| } else { | ||
| log.warn("Health check failed, service is DOWN"); | ||
| return Health.down().withDetail("error", "Scheduled health checks failed").build(); | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| package com.learning.contextservice.client; | ||
|
|
||
| import org.springframework.cloud.openfeign.FeignClient; | ||
| import org.springframework.web.bind.annotation.GetMapping; | ||
|
|
||
| @FeignClient(name = "greetingservice") | ||
| public interface GreetingServiceClient { | ||
|
|
||
| @GetMapping("/greeting") | ||
| String getGreeting(); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| package com.learning.contextservice.controller; | ||
|
|
||
| import com.learning.contextservice.client.GreetingServiceClient; | ||
| import org.springframework.beans.factory.annotation.Autowired; | ||
| import org.springframework.beans.factory.annotation.Value; | ||
| import org.springframework.web.bind.annotation.GetMapping; | ||
| import org.springframework.web.bind.annotation.RestController; | ||
|
|
||
| @RestController | ||
| public class ContextController { | ||
|
|
||
| private final GreetingServiceClient greetingServiceClient; | ||
| private final String userRegion; | ||
|
|
||
| @Autowired | ||
| public ContextController(GreetingServiceClient greetingServiceClient, @Value("${user.region}") String userRegion) { | ||
| this.greetingServiceClient = greetingServiceClient; | ||
| this.userRegion = userRegion; | ||
| } | ||
|
|
||
| @GetMapping("/context") | ||
| public String getContext() { | ||
| String greeting = greetingServiceClient.getGreeting(); | ||
| return "The Greeting Service says: "+greeting+" from "+userRegion; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| server: | ||
| port: 8082 | ||
|
|
||
| spring: | ||
| application: | ||
| name: contextservice | ||
|
|
||
| eureka: | ||
| client: | ||
| service-url.defaultZone: http://localhost:8761/eureka | ||
|
|
||
| user: | ||
| region: Chennai, Tamil Nadu, India | ||
|
|
||
| management: | ||
| endpoint: | ||
| health: | ||
| show-details: always | ||
| web: | ||
| exposure: | ||
| include: health | ||
|
|
||
| logging: | ||
| file: | ||
| name: application.log |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,49 @@ | ||
| package com.learning.contextservice; | ||
|
|
||
| import com.learning.contextservice.client.GreetingServiceClient; | ||
| import org.hamcrest.Matchers; | ||
| import org.junit.jupiter.api.Test; | ||
| import org.mockito.Mockito; | ||
| import org.springframework.beans.factory.annotation.Autowired; | ||
| import org.springframework.beans.factory.annotation.Value; | ||
| import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; | ||
|
|
||
| import org.springframework.boot.test.context.SpringBootTest; | ||
| import org.springframework.context.annotation.Import; | ||
| import org.springframework.http.MediaType; | ||
| import org.springframework.test.context.bean.override.mockito.MockitoBean; | ||
| import org.springframework.test.web.servlet.MockMvc; | ||
| import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; | ||
| import org.springframework.test.web.servlet.result.MockMvcResultMatchers; | ||
|
|
||
| @SpringBootTest(classes = ContextserviceApplication.class) | ||
| @AutoConfigureMockMvc | ||
| @Import(TestConfig.class) | ||
| class ContextControllerTest { | ||
|
|
||
| @Autowired | ||
| private MockMvc mockMvc; | ||
|
|
||
| @MockitoBean | ||
| private GreetingServiceClient greetingServiceClient; | ||
|
|
||
| @Value("${user.region}") | ||
| private String userRegion; | ||
|
|
||
| @Test | ||
| void shouldReturnContextGreeting() throws Exception{ | ||
| Mockito.when(greetingServiceClient.getGreeting()).thenReturn("Mocked Hello"); | ||
|
|
||
| mockMvc.perform(MockMvcRequestBuilders.get("/context") | ||
| .accept(MediaType.TEXT_PLAIN)) | ||
| .andExpect(MockMvcResultMatchers.status().isOk()) | ||
| .andExpect(MockMvcResultMatchers.content().string("The Greeting Service says: Mocked Hello from Chennai, Tamil Nadu, India")); | ||
| } | ||
|
|
||
| @Test | ||
| void shouldReturnContextServiceHealthStatusUp() throws Exception { | ||
| mockMvc.perform(MockMvcRequestBuilders.get("/actuator/health")) | ||
| .andExpect(MockMvcResultMatchers.status().isOk()) | ||
| .andExpect(MockMvcResultMatchers.content().string(Matchers.containsString("\"status\":\"UP\""))); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| package com.learning.contextservice; | ||
|
|
||
| import org.junit.jupiter.api.Test; | ||
| import org.springframework.boot.test.context.SpringBootTest; | ||
|
|
||
| @SpringBootTest | ||
| class ContextserviceApplicationTests { | ||
|
|
||
| @Test | ||
| void contextLoads() { | ||
| // This is a basic integration test that checks if the Spring Application Context loads successfully. | ||
| // If the context loads without any exceptions, the test is considered passing. | ||
| // It is often left empty as the act of loading the context is the primary verification. | ||
| // You can add specific assertions here if you want to verify the presence or state of certain beans. | ||
| } | ||
|
|
||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| package com.learning.contextservice; | ||
|
|
||
| import com.learning.contextservice.client.GreetingServiceClient; | ||
| import org.mockito.Mockito; | ||
| import org.springframework.context.annotation.Bean; | ||
| import org.springframework.context.annotation.Configuration; | ||
|
|
||
| @Configuration | ||
| public class TestConfig { | ||
|
|
||
| @Bean | ||
| public GreetingServiceClient greetingServiceClient() { | ||
| GreetingServiceClient mockClient = Mockito.mock(GreetingServiceClient.class); | ||
| Mockito.when(mockClient.getGreeting()).thenReturn("Mocked Hello"); | ||
| return mockClient; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| package com.learning.contextservice; | ||
|
|
||
| import org.junit.jupiter.api.Test; | ||
| import org.springframework.boot.actuate.health.Health; | ||
| import org.springframework.test.util.ReflectionTestUtils; | ||
| import org.springframework.boot.actuate.health.Status; | ||
| import static org.junit.jupiter.api.Assertions.*; | ||
|
|
||
| class MyCustomHealthCheckTest { | ||
|
|
||
| @Test | ||
| void testHealthUp() { | ||
| MyCustomHealthCheck healthCheck = new MyCustomHealthCheck(); | ||
| // Simulate a healthy state | ||
| ReflectionTestUtils.setField(healthCheck, "isHealthy", true); | ||
| Health health = healthCheck.health(); | ||
| assertEquals(Status.UP, health.getStatus()); | ||
| assertTrue(health.getDetails().containsKey("message")); | ||
| assertEquals("Service is running and scheduled checks are OK", health.getDetails().get("message")); | ||
| } | ||
|
|
||
| @Test | ||
| void testHealthDown() { | ||
| MyCustomHealthCheck healthCheck = new MyCustomHealthCheck(); | ||
| // Simulate an unhealthy state | ||
| ReflectionTestUtils.setField(healthCheck, "isHealthy", false); | ||
| Health health = healthCheck.health(); | ||
| assertEquals(Status.DOWN, health.getStatus()); | ||
| assertTrue(health.getDetails().containsKey("error")); | ||
| assertEquals("Scheduled health checks failed", health.getDetails().get("error")); | ||
| } | ||
|
|
||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| /mvnw text eol=lf | ||
| *.cmd text eol=crlf |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| HELP.md | ||
| target/ | ||
| !.mvn/wrapper/maven-wrapper.jar | ||
| !**/src/main/**/target/ | ||
| !**/src/test/**/target/ | ||
|
|
||
| ### STS ### | ||
| .apt_generated | ||
| .classpath | ||
| .factorypath | ||
| .project | ||
| .settings | ||
| .springBeans | ||
| .sts4-cache | ||
|
|
||
| ### IntelliJ IDEA ### | ||
| .idea | ||
| *.iws | ||
| *.iml | ||
| *.ipr | ||
|
|
||
| ### NetBeans ### | ||
| /nbproject/private/ | ||
| /nbbuild/ | ||
| /dist/ | ||
| /nbdist/ | ||
| /.nb-gradle/ | ||
| build/ | ||
| !**/src/main/**/build/ | ||
| !**/src/test/**/build/ | ||
|
|
||
| ### VS Code ### | ||
| .vscode/ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,55 @@ | ||
| <?xml version="1.0" encoding="UTF-8"?> | ||
| <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
| xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||
| <modelVersion>4.0.0</modelVersion> | ||
| <parent> | ||
| <groupId>org.springframework.boot</groupId> | ||
| <artifactId>spring-boot-starter-parent</artifactId> | ||
| <version>3.4.4</version> | ||
| <relativePath/> </parent> | ||
| <groupId>com.learning</groupId> | ||
| <artifactId>eurekaserver</artifactId> | ||
| <version>0.0.1-SNAPSHOT</version> | ||
| <name>eurekaserver</name> | ||
| <description>eurekaserver</description> | ||
|
|
||
| <properties> | ||
| <spring-cloud.version>2024.0.1</spring-cloud.version> | ||
| </properties> | ||
| <dependencies> | ||
| <dependency> | ||
| <groupId>org.springframework.cloud</groupId> | ||
| <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> | ||
| </dependency> | ||
| <dependency> | ||
| <groupId>org.springframework.boot</groupId> | ||
| <artifactId>spring-boot-starter-test</artifactId> | ||
| <scope>test</scope> | ||
| </dependency> | ||
| </dependencies> | ||
| <dependencyManagement> | ||
| <dependencies> | ||
| <dependency> | ||
| <groupId>org.springframework.cloud</groupId> | ||
| <artifactId>spring-cloud-dependencies</artifactId> | ||
| <version>${spring-cloud.version}</version> | ||
| <type>pom</type> | ||
| <scope>import</scope> | ||
| </dependency> | ||
| </dependencies> | ||
| </dependencyManagement> | ||
|
|
||
| <build> | ||
| <plugins> | ||
| <plugin> | ||
| <groupId>org.springframework.boot</groupId> | ||
| <artifactId>spring-boot-maven-plugin</artifactId> | ||
| </plugin> | ||
| <plugin> | ||
| <groupId>org.apache.maven.plugins</groupId> | ||
| <artifactId>maven-compiler-plugin</artifactId> | ||
| </plugin> | ||
| </plugins> | ||
| </build> | ||
|
|
||
| </project> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| package com.learning.eurekaserver; | ||
|
|
||
| import org.springframework.boot.SpringApplication; | ||
| import org.springframework.boot.autoconfigure.SpringBootApplication; | ||
| import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; | ||
|
|
||
| @SpringBootApplication | ||
| @EnableEurekaServer | ||
| public class EurekaserverApplication { | ||
|
|
||
| public static void main(String[] args) { | ||
| SpringApplication.run(EurekaserverApplication.class, args); | ||
| } | ||
|
|
||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| server: | ||
| port: 8761 | ||
|
|
||
| eureka: | ||
| client: | ||
| register-with-eureka: false | ||
| fetch-registry: false | ||
| server: | ||
| enable-self-preservation: true | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| package com.learning.eurekaserver; | ||
|
|
||
| import org.junit.jupiter.api.Test; | ||
| import org.springframework.boot.test.context.SpringBootTest; | ||
|
|
||
| @SpringBootTest | ||
| class EurekaserverApplicationTests { | ||
|
|
||
| @Test | ||
| void contextLoads() { | ||
| // This is a basic integration test that checks if the Spring Application Context loads successfully. | ||
| // If the context loads without any exceptions, the test is considered passing. | ||
| // It is often left empty as the act of loading the context is the primary verification. | ||
| // You can add specific assertions here if you want to verify the presence or state of certain beans. | ||
| } | ||
|
|
||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| /mvnw text eol=lf | ||
| *.cmd text eol=crlf |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| HELP.md | ||
| target/ | ||
| !.mvn/wrapper/maven-wrapper.jar | ||
| !**/src/main/**/target/ | ||
| !**/src/test/**/target/ | ||
|
|
||
| ### STS ### | ||
| .apt_generated | ||
| .classpath | ||
| .factorypath | ||
| .project | ||
| .settings | ||
| .springBeans | ||
| .sts4-cache | ||
|
|
||
| ### IntelliJ IDEA ### | ||
| .idea | ||
| *.iws | ||
| *.iml | ||
| *.ipr | ||
|
|
||
| ### NetBeans ### | ||
| /nbproject/private/ | ||
| /nbbuild/ | ||
| /dist/ | ||
| /nbdist/ | ||
| /.nb-gradle/ | ||
| build/ | ||
| !**/src/main/**/build/ | ||
| !**/src/test/**/build/ | ||
|
|
||
| ### VS Code ### | ||
| .vscode/ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,69 @@ | ||
| <?xml version="1.0" encoding="UTF-8"?> | ||
| <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
| xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||
| <modelVersion>4.0.0</modelVersion> | ||
| <parent> | ||
| <groupId>org.springframework.boot</groupId> | ||
| <artifactId>spring-boot-starter-parent</artifactId> | ||
| <version>3.4.4</version> | ||
| <relativePath/> </parent> | ||
| <groupId>com.learning</groupId> | ||
| <artifactId>greetingservice</artifactId> | ||
| <version>0.0.1-SNAPSHOT</version> | ||
| <name>greetingservice</name> | ||
| <description>greetingservice</description> | ||
|
|
||
| <properties> | ||
| <spring-cloud.version>2024.0.1</spring-cloud.version> | ||
| </properties> | ||
| <dependencies> | ||
| <dependency> | ||
| <groupId>org.springframework.boot</groupId> | ||
| <artifactId>spring-boot-starter-web</artifactId> | ||
| </dependency> | ||
| <dependency> | ||
| <groupId>org.projectlombok</groupId> | ||
| <artifactId>lombok</artifactId> | ||
| <version>1.18.38</version> | ||
| <scope>provided</scope> | ||
| </dependency> | ||
| <dependency> | ||
| <groupId>org.springframework.cloud</groupId> | ||
| <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> | ||
| </dependency> | ||
| <dependency> | ||
| <groupId>org.springframework.boot</groupId> | ||
| <artifactId>spring-boot-starter-test</artifactId> | ||
| <scope>test</scope> | ||
| </dependency> | ||
| <dependency> | ||
| <groupId>org.springframework.boot</groupId> | ||
| <artifactId>spring-boot-starter-actuator</artifactId> | ||
| </dependency> | ||
| </dependencies> | ||
| <dependencyManagement> | ||
| <dependencies> | ||
| <dependency> | ||
| <groupId>org.springframework.cloud</groupId> | ||
| <artifactId>spring-cloud-dependencies</artifactId> | ||
| <version>${spring-cloud.version}</version> | ||
| <type>pom</type> | ||
| <scope>import</scope> | ||
| </dependency> | ||
| </dependencies> | ||
| </dependencyManagement> | ||
|
|
||
| <build> | ||
| <plugins> | ||
| <plugin> | ||
| <groupId>org.springframework.boot</groupId> | ||
| <artifactId>spring-boot-maven-plugin</artifactId> | ||
| </plugin> | ||
| <plugin> | ||
| <groupId>org.apache.maven.plugins</groupId> | ||
| <artifactId>maven-compiler-plugin</artifactId> | ||
| </plugin> | ||
| </plugins> | ||
| </build> | ||
|
|
||
| </project> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| package com.learning.greetingservice; | ||
|
|
||
| import org.springframework.boot.SpringApplication; | ||
| import org.springframework.boot.autoconfigure.SpringBootApplication; | ||
| import org.springframework.cloud.client.discovery.EnableDiscoveryClient; | ||
| import org.springframework.context.annotation.ComponentScan; | ||
|
|
||
| @SpringBootApplication | ||
| @EnableDiscoveryClient | ||
| @ComponentScan("com.learning.greetingservice.controller") | ||
| public class GreetingserviceApplication { | ||
|
|
||
| public static void main(String[] args) { | ||
| SpringApplication.run(GreetingserviceApplication.class, args); | ||
| } | ||
|
|
||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| package com.learning.greetingservice; | ||
|
|
||
| import org.slf4j.Logger; | ||
| import org.slf4j.LoggerFactory; | ||
| import org.springframework.boot.actuate.health.Health; | ||
| import org.springframework.boot.actuate.health.HealthIndicator; | ||
| import org.springframework.scheduling.annotation.Scheduled; | ||
| import org.springframework.stereotype.Component; | ||
|
|
||
| @Component("myCustomHealthCheck") | ||
| public class MyCustomHealthCheck implements HealthIndicator { | ||
|
|
||
| private static final Logger log = LoggerFactory.getLogger(MyCustomHealthCheck.class); | ||
|
|
||
| private volatile boolean isHealthy = true; | ||
|
|
||
| @Scheduled(fixedRate = 5000) // Run every 5 seconds | ||
| public void updateHealthStatus() { | ||
| // Perform checks here to determine the current health | ||
| // For example, check database connectivity, external service availability, etc. | ||
| isHealthy = performHealthCheck(); | ||
| log.info("Update health status : {}", isHealthy); | ||
| } | ||
|
|
||
| boolean performHealthCheck() { | ||
| boolean current = System.currentTimeMillis() % 10000 < 5000; // Simulate fluctuating health | ||
| log.debug("Performing health check, current status: {}", current); | ||
| return current; // Simulate fluctuating health | ||
| } | ||
|
|
||
| @Override | ||
| public Health health() { | ||
| if (isHealthy) { | ||
| log.info("Health check successful, service is UP"); | ||
| return Health.up().withDetail("message", "Service is running and scheduled checks are OK").build(); | ||
| } else { | ||
| log.warn("Health check failed, service is DOWN"); | ||
| return Health.down().withDetail("error", "Scheduled health checks failed").build(); | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| package com.learning.greetingservice.controller; | ||
|
|
||
| import org.springframework.web.bind.annotation.GetMapping; | ||
| import org.springframework.web.bind.annotation.RestController; | ||
|
|
||
| @RestController | ||
| public class GreetingsController { | ||
|
|
||
| @GetMapping("/greeting") | ||
| public String getGreeting() { | ||
| return "Hello"; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| server: | ||
| port: 8081 | ||
|
|
||
| spring: | ||
| application: | ||
| name: greetingservice | ||
| eureka: | ||
| client: | ||
| service-url.defaultZone: http://localhost:8761/eureka | ||
|
|
||
| management: | ||
| endpoint: | ||
| health: | ||
| show-details: always | ||
| web: | ||
| exposure: | ||
| include: health | ||
|
|
||
| logging: | ||
| file: | ||
| name: application.log | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| package com.learning.greetingservice; | ||
|
|
||
| import org.junit.jupiter.api.Test; | ||
| import org.springframework.boot.test.context.SpringBootTest; | ||
|
|
||
| @SpringBootTest | ||
| class GreetingserviceApplicationTests { | ||
|
|
||
| @Test | ||
| void contextLoads() { | ||
| // This is a basic integration test that checks if the Spring Application Context loads successfully. | ||
| // If the context loads without any exceptions, the test is considered passing. | ||
| // It is often left empty as the act of loading the context is the primary verification. | ||
| // You can add specific assertions here if you want to verify the presence or state of certain beans. | ||
| } | ||
|
|
||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| package com.learning.greetingservice; | ||
|
|
||
| import org.junit.jupiter.api.Test; | ||
| import org.springframework.boot.actuate.health.Health; | ||
| import org.springframework.test.util.ReflectionTestUtils; | ||
| import org.springframework.boot.actuate.health.Status; | ||
| import static org.junit.jupiter.api.Assertions.*; | ||
|
|
||
| class MyCustomHealthCheckTest { | ||
|
|
||
| @Test | ||
| void testHealthUp() { | ||
| MyCustomHealthCheck healthCheck = new MyCustomHealthCheck(); | ||
| // Simulate a healthy state | ||
| ReflectionTestUtils.setField(healthCheck, "isHealthy", true); | ||
| Health health = healthCheck.health(); | ||
| assertEquals(Status.UP, health.getStatus()); | ||
| assertTrue(health.getDetails().containsKey("message")); | ||
| assertEquals("Service is running and scheduled checks are OK", health.getDetails().get("message")); | ||
| } | ||
|
|
||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| package com.learning.greetingservice.controller; | ||
|
|
||
| import com.learning.greetingservice.GreetingserviceApplication; | ||
| import org.junit.jupiter.api.Test; | ||
| import org.springframework.beans.factory.annotation.Autowired; | ||
| import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; | ||
| import org.springframework.boot.test.context.SpringBootTest; | ||
| import org.springframework.http.MediaType; | ||
| import org.springframework.test.context.ActiveProfiles; | ||
| import org.springframework.test.web.servlet.MockMvc; | ||
| import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; | ||
| import org.springframework.test.web.servlet.result.MockMvcResultMatchers; | ||
|
|
||
| @SpringBootTest(classes = GreetingserviceApplication.class) | ||
| @AutoConfigureMockMvc | ||
| @ActiveProfiles("test") | ||
| class GreetingControllerTest { | ||
|
|
||
| @Autowired | ||
| private MockMvc mockMvc; | ||
|
|
||
| @Test | ||
| void shouldReturnGreeting() throws Exception{ | ||
| mockMvc.perform(MockMvcRequestBuilders.get("/greeting") | ||
| .accept(MediaType.TEXT_PLAIN)) | ||
| .andExpect(MockMvcResultMatchers.status().isOk()) | ||
| .andExpect(MockMvcResultMatchers.content().string("Hello")); | ||
| } | ||
|
|
||
| @Test | ||
| void shouldReturnHealthStatusUp() throws Exception{ | ||
| mockMvc.perform(MockMvcRequestBuilders.get("/actuator/health")) | ||
| .andExpect(MockMvcResultMatchers.status().isOk()) | ||
| .andExpect(MockMvcResultMatchers.content().string(org.hamcrest.Matchers.containsString("\"status\":\"UP\""))); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,63 @@ | ||
| <?xml version="1.0" encoding="UTF-8"?> | ||
| <!-- | ||
| This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). | ||
| The MIT License | ||
| Copyright © 2014-2022 Ilkka Seppälä | ||
| Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| of this software and associated documentation files (the "Software"), to deal | ||
| in the Software without restriction, including without limitation the rights | ||
| to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| copies of the Software, and to permit persons to whom the Software is | ||
| furnished to do so, subject to the following conditions: | ||
| The above copyright notice and this permission notice shall be included in | ||
| all copies or substantial portions of the Software. | ||
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
| THE SOFTWARE. | ||
| --> | ||
| <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||
| <parent> | ||
| <artifactId>java-design-patterns</artifactId> | ||
| <groupId>com.iluwatar</groupId> | ||
| <version>1.26.0-SNAPSHOT</version> | ||
| </parent> | ||
| <modelVersion>4.0.0</modelVersion> | ||
| <artifactId>microservices-self-registration</artifactId> | ||
| <packaging>pom</packaging> | ||
| <modules> | ||
| <module>eurekaserver</module> | ||
| <module>greetingservice</module> | ||
| <module>contextservice</module> | ||
| </modules> | ||
|
|
||
| <properties> | ||
| <java.version>21</java.version> | ||
| <maven.compiler.source>${java.version}</maven.compiler.source> | ||
| <maven.compiler.target>${java.version}</maven.compiler.target> | ||
| </properties> | ||
|
|
||
| <build> | ||
| <pluginManagement> | ||
| <plugins> | ||
| <plugin> | ||
| <groupId>org.apache.maven.plugins</groupId> | ||
| <artifactId>maven-compiler-plugin</artifactId> | ||
| <version>3.8.1</version> <configuration> | ||
| <source>${maven.compiler.source}</source> | ||
| <target>${maven.compiler.target}</target> | ||
| </configuration> | ||
| </plugin> | ||
| </plugins> | ||
| </pluginManagement> | ||
| </build> | ||
|
Comment on lines
+43
to
+62
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think you can use the maven-compiler-plugin from the parent pom.xml, so all this can be left out. This helps in maintenance work. |
||
| </project> | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use groupId
com.iluwatar