GET /users
GET /users/1
GET /users/1/comments
GET /users?userId=1"
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Home</title>
</head>
<body>
<h1>App</h1>
<a href="t1">확인 페이지</a>
<br/>
<a href="app/0">0ms 성공</a>
<br/>
<a href="app/2000">2000ms 실패</a>
<br/>
<a href="users">users</a>
<br/>
<a href="users/1">users/1</a>
<br/>
<a href="users/1/comments">users/1/comments</a>
<br/>
<a href="users?userId=1">users?userId=1</a>
<br/>
</body>
</html>
package Pack01;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import com.netflix.hystrix.contrib.javanica.annotation.*;
@Controller
public class Application {
@RequestMapping("/")
public String f0() {
// System.out.println("f0 call");
return "index";
}
@RequestMapping("/t1")
public String f1() {
System.out.println("f1 call");
return "CheckView";
//루트로 리다이렉트
// return "redirect:/";
}
}
@RestController
@RequestMapping("/app")
class AppController{
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
@Autowired
RestTemplate restTemplate;
//성공 - 실패 - 실패 -> 실패 확률(66%) > 50% (50% 이상이면 발생)
//서킷 발동의 의미: 서비스 호출 자체를 하지 않고, fallbackMethod 함수 호출
//서킷 발동 8초 이후에 몇 년이 지나서 1회 클릭했을 때
@GetMapping("/{appNum}") //제품번호가 날라왔다 정도
@HystrixCommand(
fallbackMethod = "tiger",
commandProperties = {
@HystrixProperty(
name = "execution.isolation.thread.timeoutInMilliseconds",
value = "500"), //응답을 기다리는 시간
@HystrixProperty(
name = "circuitBreaker.errorThresholdPercentage",
value = "50"), //50% 이상 문제가 발생하면 서킷을 오픈
@HystrixProperty(
name = "metrics.rollingStats.timeInMilliseconds",
value = "10000"), //최근 10초 동안
@HystrixProperty(
name = "circuitBreaker.requestVolumeThreshold",
value = "3"), //최근 10초동안 서비스 호출이 3회 이상이면 통계를 시작하세요 (10초 안에 3번 이상 클릭)
@HystrixProperty(
name = "circuitBreaker.sleepWindowInMilliseconds",
value = "8000") //서킷브레이크 오픈 유지시간
}
)
public String f1(@PathVariable String appNum) {
System.out.println();
String result = restTemplate.getForObject(
"http://localhost:8082/bpp/" + appNum,
String.class
);
return result;
}
public String tiger(String s) {
System.out.println(s);
return "기본 광고";
}
}
@RestController
@RequestMapping("/users")
class TestController{
// @GetMapping("")
// public String f1() {
// System.out.println("f1");
// return "f1";
// }
@GetMapping("/{num}")
public String f2(@PathVariable String num) {
System.out.println("f2");
return "f2 : " + num;
}
@GetMapping("/{num}/{com}")
public String f3(@PathVariable String num,
@PathVariable String com) {
System.out.println("f3");
return "f3 : " + com;
}
@GetMapping("")
public String f4(@RequestParam(
value="usersId", required=false) String usersId) {
System.out.println("f4");
return "f4";
}
}
구성 요소
ServerList
로드 밸런싱 대상 서버 목록
configuration을 통해 static 하게 설정 가능
eureka 등을 기반으로 dynamic하게 설정 가능
Rule
요청을 보낼 서버를 선택하는 논리
Round Robbin - 한 서버씩 돌아가며 전달
Available Filtering - 에러가 많은 서버 제외
weighted Response Time - 서버별 응답 시간에 따라 확률 조절
Ping
서버 list가 살아있는지 체크하는논리
static, dynamic 모두 가능
Ribbon의 가장 중요하다고 생각하는 기능중 하나는 Retry입니다.
- Retry는 말 그대로 만약 server에게 응답을 받지 못하였을 경우 동일한 서버로 재시도 하거나 다른 서버로 재시도하는 기능입니다.
ribbon의 서버리스트를 환경파일에서 가져올지 eureka에서 동적으로 가져올지 설정할 수도 있습니다.
기존에는 하드웨어로 지원되던 로드 밸런싱으로 소프트웨어화 시킨 것이 리본
하드웨어 기반의 서버 사이드 로드 밸런서의 단점은 기본적으로 별도의 스위치 장비가 필요하기 때문에 상대적으로 비용이 많이 소모되게 되며 유연성도 떨어지게 됩니다.
서버 목록의 추가는 수동으로 보통 이루어집니다.
이러한 단점 때문에 클라이이언트 사이드 로드밸런서가 MSA에서는 주로 사용됩니다.
클라이언트 사이드 로드밸런서를 사용하게 되면 아래와 같이 아키텍처가 형성됩니다.
의존성 (application.properties)
implementation 'org.springframework.cloud:spring-cloud-starter-netflix-ribbon:2.1.4.RELEASE'
# 첫 시도 실패시 같은 서버로 재시도 하는 수(첫번째 전송은 제외)
sample-client.ribbon.MaxAutoRetries=1
# 첫 시도 실패시 다음 서버로 재시도 하는 수(첫번째 전송은 제외)
sample-client.ribbon.MaxAutoRetriesNextServer=1
# Whether all operations can be retried for this client
sample-client.ribbon.OkToRetryOnAllOperations=true
# source로 부터 서버 리스트를 ribbon으로 다시 가져오는 interval time
sample-client.ribbon.ServerListRefreshInterval=2000
# HttpClient의 Connection timeout(연결과정의 Timeout 시간)
sample-client.ribbon.ConnectTimeout=3000
# HttpClient의 Read Timeout(데이터를 읽어오는 과정의 Timeout 시간)
sample-client.ribbon.ReadTimeout=3000
# 최초의 서버 리스트, 다이나믹하게 변경될 수 있다.
sample-client.ribbon.listOfServers=www.microsoft.com:80,www.yahoo.com:80,www.google.com:80
sample-client를 생략하게 되면 전체적으로 설정이 걸리게 되며, sample-client에 서비스 이름을 기입하면 해당 서비스에만 적용되어지게 됩니다.
ribbon-Client 생성
ribbon을 사용하기 위해서는 ribbon-client를 생성해야합니다.
ribbon-client란 로드밸런서 그룹이라고 생각하시면 됩니다. 일반적으로 서비스 단위로 생성하면 됩니다.
@Configuration
@RibbonClients({
@RibbonClient(name = "service-group-1", configuration = LoadBalancerConfiguration.class)
})
public class RibbonClientConfig {
}
service-group-1.ribbon.MaxAutoRetries=1
service-group-1.ribbon.listOfServers=localhost:8081,localhost:8081
RestTemplate에 Ribbon 적용
@Bean
@LoadBalanced
public RestTemplate getRestTemplate() {
return new RestTemplate();
}
4-1. 묵시적 사용
@Service
public class LogisticsServiceImpl {
RestTemplate restTemplate;
public LogisticsServiceImpl(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
public String getLogisticsInfo() {
return restTemplate.getForObject("http://server-group-1",String.class);
}
}
4-2. 명시적 사용
@Service
public class LogisticsServiceImpl {
@Autowired
LoadBalancerClient loadBalancerClient;
RestTemplate restTemplate;
public LogisticsServiceImpl(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
public String getLogisticsInfo() {
final ServiceInstance choose = loadBalancerClient.choose("server-group-1");
return restTemplate.getForObject(String.format("http://%s:%s", choose.getHost(), choose.getPort()),String.class);
}
}
Ribbon customizing
Ribbon의 구성요소는 Ping, ServerList, Rule의 3가지라고 했습니다. 이 3가지 요소는 커스터마이징 할 수 있습니다.
IPing은 ping관련으로 ribbon-client에 물려있는 서버가 살아있는지 판단할 때 사용합니다. ping이 정상적으로 수행되지 않으면 해당 서버로 실제 요청을 보내지 않습니다. IRule은 로드밸런싱 룰을 설정하는 부분입니다.
이렇게 설정한 것들은 @Configuration
으로 주입하면 안되며 @RibbonClient(name = "service-group-1", configuration = LoadBalancerConfiguration.class)
으로 configuration에 들어가도록 적용해주어야 합니다.
public class LoadBalancerConfiguration {
@Autowired
IClientConfig ribbonClientConfig;
@Bean
public IPing ribbonPing(IClientConfig config) {
return new PingUrl(false, "/ping");
}
@Bean
public IRule ribbonRule(IClientConfig config) {
return new AvailabilityFilteringRule();
}
}
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-netflix-ribbon -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
<version>2.2.10.RELEASE</version>
</dependency>
server:
port: 8081
spring:
mvc:
view:
prefix: /WEB-INF/views/
suffix: .jsp
# 내가 tiger라는 주소표기를 사용하면 localhost:8082로 해석하세요
tiger:
ribbon:
listOfServers: localhost:8082 , localhost:8083, localhost:8084 #라운드로빈으로 찾아감
MaxAutoRetries: 0
MaxAutoRetriesNextServer: 1
package Pack01;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
@SpringBootApplication
public class Ribbon01Application {
@Bean
@LoadBalanced
RestTemplate restTemplate() {
return new RestTemplate();
}
public static void main(String[] args) {
SpringApplication.run(Ribbon01Application.class, args);
}
}
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Home</title>
</head>
<body>
<h1>홈</h1>
<a href="t1">확인 페이지</a>
<br/>
<a href="app">두번째</a>
<br/>
</body>
</html>
package Pack01;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
@Controller
public class Application {
@RequestMapping("/")
public String f0() {
System.out.println("f0 call");
return "index";
}
@RequestMapping("/t1")
public String f1() {
System.out.println("f1 call");
return "CheckView";
//루트로 리다이렉트
// return "redirect:/";
}
}
@RestController
@RequestMapping("/app")
class AppController{
@Autowired
RestTemplate restTemplate;
@GetMapping("")
public String f1() {
System.out.println("f1");
String result = restTemplate.getForObject(
// "http://localhost:8082/bpp",
"http://tiger/bpp",
String.class);
return result;
}
}
server.port = 8082
spring.mvc.view.prefix=/WEB-INF/views/
spring.mvc.view.suffix=.jsp
package Pack01;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
@Controller
public class Application {
@RequestMapping("/")
public String f0() {
System.out.println("f0 call");
return "index";
}
@RequestMapping("/t1")
public String f1() {
System.out.println("f1 call");
return "CheckView";
//루트로 리다이렉트
// return "redirect:/";
}
}
@RestController
@RequestMapping("/bpp")
class AppController{
@GetMapping("")
public String f1() {
System.out.println("number2");
return "number2";
}
}
server.port = 8083
spring.mvc.view.prefix=/WEB-INF/views/
spring.mvc.view.suffix=.jsp
package Pack01;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@Controller
public class Application {
@RequestMapping("/")
public String f0() {
System.out.println("f0 call");
return "index";
}
@RequestMapping("/t1")
public String f1() {
System.out.println("f1 call");
return "CheckView";
//루트로 리다이렉트
// return "redirect:/";
}
}
@RestController
@RequestMapping("/bpp")
class AppController{
@GetMapping("")
public String f1() {
System.out.println("number3");
return "number3";
}
}
server.port = 8084
spring.mvc.view.prefix=/WEB-INF/views/
spring.mvc.view.suffix=.jsp
package Pack01;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@Controller
public class Application {
@RequestMapping("/")
public String f0() {
System.out.println("f0 call");
return "index";
}
@RequestMapping("/t1")
public String f1() {
System.out.println("f1 call");
return "CheckView";
//루트로 리다이렉트
// return "redirect:/";
}
}
@RestController
@RequestMapping("/bpp")
class AppController{
@GetMapping("")
public String f1() {
System.out.println("number4");
return "number4";
}
}
server:
port: 8761
eureka:
instance:
hostname: localhost
client:
registerWithEureka: false
fetchRegistry: false
serviceUrl:
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
<?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>2.3.1.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>EurekaServer</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>EurekaServer</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>11</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.16</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
<version>2.2.10.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
<version>2.2.10.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
<version>2.2.10.RELEASE</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
package Pack01;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.EnableMBeanExport;
import org.springframework.web.client.RestTemplate;
@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {
@Bean
RestTemplate restTemplate() {
return new RestTemplate();
}
public static void main(String[] args) {
SpringApplication.run(EurekaServerApplication.class, args);
}
}
package Pack01;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
@Controller
public class Application {
@RequestMapping("/")
public String f0() {
System.out.println("f0 call");
return "index";
}
@RequestMapping("/t1")
public String f1() {
System.out.println("f1 call");
return "CheckView";
//루트로 리다이렉트
// return "redirect:/";
}
}
server:
port: 8081
spring:
mvc:
view:
prefix: /WEB-INF/views/
suffix: .jsp
application:
name: Service01
eureka:
instance:
prefer-ip-address: true
<?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>2.3.1.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>EurekaClient01</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>EurekaClient01</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>11</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.16</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
<version>2.2.10.RELEASE</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
package Pack01;
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.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
@EnableEurekaClient
@SpringBootApplication
public class EurekaClient01Application {
@Bean
@LoadBalanced
RestTemplate restTemplate() {
return new RestTemplate();
}
public static void main(String[] args) {
SpringApplication.run(EurekaClient01Application.class, args);
}
}
package Pack01;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
@Controller
public class Application {
@RequestMapping("/")
public String f0() {
System.out.println("f0 call");
return "index";
}
@RequestMapping("/t1")
public String f1() {
System.out.println("f1 call");
return "CheckView";
//루트로 리다이렉트
// return "redirect:/";
}
}
@RestController
@RequestMapping("/app")
class AppController{
@Autowired
RestTemplate restTemplate;
@GetMapping("")
public String f1() {
//System.out.println(restTemplate);
String result = restTemplate.getForObject(
"http://Service02/bpp",
String.class);
return "test : " + result;
}
}
server:
port: 8082
spring:
mvc:
view:
prefix: /WEB-INF/views/
suffix: .jsp
application:
name: Service02
eureka:
instance:
prefer-ip-address: true
<?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>2.3.1.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>EurekaClient02</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>EurekaClient02</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>11</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.16</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
<version>2.2.10.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
<version>2.2.10.RELEASE</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
package Pack01;
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.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
@EnableEurekaClient
@SpringBootApplication
public class EurekaClient02Application {
// @Bean
// @LoadBalanced
// RestTemplate restTemplate() {
// return new RestTemplate();
// }
public static void main(String[] args) {
SpringApplication.run(EurekaClient02Application.class, args);
}
}
package Pack01;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@Controller
public class Application {
@RequestMapping("/")
public String f0() {
System.out.println("f0 call");
return "index";
}
@RequestMapping("/t1")
public String f1() {
System.out.println("f1 call");
return "CheckView";
//루트로 리다이렉트
// return "redirect:/";
}
}
@RestController
@RequestMapping("/bpp")
class AppController{
@GetMapping("")
public String f1() {
System.out.println("test1");
return "test : 1";
}
}
server:
port: 8083
spring:
mvc:
view:
prefix: /WEB-INF/views/
suffix: .jsp
application:
name: Service02
eureka:
instance:
prefer-ip-address: true
<?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>2.3.1.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>EurekaClient03</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>EurekaClient03</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>11</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.16</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
<version>2.2.10.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
<version>2.2.10.RELEASE</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
package Pack01;
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.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
@EnableEurekaClient
@SpringBootApplication
public class EurekaClient03Application {
// @Bean
// @LoadBalanced
// RestTemplate restTemplate() {
// return new RestTemplate();
// }
public static void main(String[] args) {
SpringApplication.run(EurekaClient03Application.class, args);
}
}
package Pack01;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@Controller
public class Application {
@RequestMapping("/")
public String f0() {
System.out.println("f0 call");
return "index";
}
@RequestMapping("/t1")
public String f1() {
System.out.println("f1 call");
return "CheckView";
//루트로 리다이렉트
// return "redirect:/";
}
}
@RestController
@RequestMapping("/bpp")
class AppController{
@GetMapping("")
public String f1() {
System.out.println("test1");
return "test : 1";
}
}