※POM
※父POM
<packaging>pom</packaging> <modules> <module>provider</module> <module>consumer</module> <module>api</module> <module>eureka</module> </modules> <groupId>scp</groupId> <artifactId>SpringCloudPractice</artifactId> <version>1.0-SNAPSHOT</version> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.5.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> <spring-cloud-release.version>Greenwich.RELEASE</spring-cloud-release.version> </properties> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud-release.version}</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>2.1.5.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.8</version> <scope>provided</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-config</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build>
※生產者和消費者向註冊中心註冊,api 為生產者和消費者共用的方法
※consumer pom
<parent> <artifactId>SpringCloudPractice</artifactId> <groupId>scp</groupId> <version>1.0-SNAPSHOT</version> </parent> <artifactId>consumer</artifactId> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <artifactId>api</artifactId> <groupId>scp</groupId> <version>1.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> </dependencies>
※provider pom
<parent> <artifactId>SpringCloudPractice</artifactId> <groupId>scp</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>provider</artifactId> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <artifactId>api</artifactId> <groupId>scp</groupId> <version>1.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> </dependencies>
※api pom
<parent> <artifactId>SpringCloudPractice</artifactId> <groupId>scp</groupId> <version>1.0-SNAPSHOT</version> </parent> <artifactId>api</artifactId> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> </dependencies> <build> <finalName>cyc</finalName> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <classifier>exec</classifier> </configuration> </plugin> </plugins> </build>
※因為 api 有程式碼給 consumer 和 provider 使用,maven install 會失敗,所以要在 api 加上 plugin 才可以
※eureka pom
<parent> <artifactId>SpringCloudPractice</artifactId> <groupId>scp</groupId> <version>1.0-SNAPSHOT</version> </parent> <artifactId>eureka</artifactId> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> <!--<artifactId>spring-cloud-netflix-eureka-server</artifactId>没有 starter 是错的--> </dependency> </dependencies>
※java 類別
※provider
package controller; @RestController public class TestController { @GetMapping("/testGet") public ApiBean get() { System.out.println("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"); ApiBean ab = new ApiBean(); ab.setId(1); ab.setName("xxx"); return ab; } }
※consumer
package controller; @RestController @Import(RestTemplate.class) public class consumerController { @Resource private RestTemplate restTemplate; @GetMapping("/xxx") public ApiBean get() { return restTemplate.getForObject("http://localhost:9001" + "/testGet", ApiBean.class); } }
※因為 RestTemplate 是內鍵的 class,並沒有類似 @Component 這種註解,spring 不知道,所以用了 @Import 將它註冊到 spring
※api
package scp; @Data public class ApiBean implements Serializable { private int id; private String name; }
※eureka
package main; @SpringBootApplication @EnableEurekaServer public class EurekaMain { public static void main(String[] args) { SpringApplication.run(EurekaMain.class, args); } }
※application.yml
※provider
server: port: 9001 eureka: client: service-url: defaultZone: http://localhost:9051/eureka
※consumer
server: port: 80 eureka: client: service-url: defaultZone: http://localhost:9051/eureka
※eureka
server: port: 9051 eureka: client: register-with-eureka: false # 不註冊自己 fetch-registry: false # 取得註冊資訊,因為自己就是註冊中心,不需要取得註冊資訊 service-url: defaultZone: http://localhost:${server.port}/eureka/ # Eureka Server 的位址
※ fetch-registry 一定要 false 才有辦法啟動,否則會報 Cannot execute request on any known server
※ register-with-eureka 如果註冊自己可以順利啟動成功,只是沒什麼意義,感覺就像麥當勞的員工自己也在排隊買漢堡一樣
※server.port 如果給 0,會隨機產生一個,看控製台即可知道
※遇到的問題
invalid LOC headerjar 檔簽名壞了,從倉庫刪除後重新下載即可
Make sure your own configuration does not rely on that class. This can also happen if you are @ComponentScanning a springframework package
main 方法要有 package,還有另外一個錯誤是要有 main 方法,但錯誤訊息很明顯,所以一個專案放一個有 package 的 main 方法就可以了,方法裡什麼都不寫也行
※Eureka 註冊中心
啟動後會有現都是 UNKNOWN,所以 consumer 和 provider 還要在 application.yml 加上 spring.application.name,這樣 eureka 才會分辯的出來,修改後如下,eureka 會變成全部大寫英文如果想改右邊的 Status 顯示的名稱,還得在 consumer 和 provider 加上 eureka.instance.instance-id,修改後如下,這裡 eureka 不會變成大寫
上上一張圖的左下角有網址,是滑鼠在 status 的 consumer 或 provider 上時顯示的,我記得不改是 localhost 之類的,但不知哪一版改了,如果是 localhost 想改成 ip,還可以加上 eureka.instance.prefer-ip-address: true 就可以了
還有一個很像的設定 eureka.instance.ip-address: ,因為有可能有多張網卡,可以寫死其中一張網卡的 IP,如果兩個都設定,最終註冊在 eureka 會是這裡的設定
※啟動順序
必需先啟動 eureka,再啟動 provider,最後是 consumer如果 eureka 在啟動前有其他的專案先啟動了,eureka 抓不到
如果 consumer 在 provider 之前,我試的結果沒問題,但理論上是先有提供者,這樣消費者才抓的到
如果已經照順序啟動好了,將 provider 或 consumer 的 spring.application.name 名字換掉,只重啟改掉的專案,會發現 eureka 會有紅色的警告,因為有個 CAP 理論
Consistency(一致性)
Availability(可用性)
Partition tolerance(分区容错性)
目前不可能全部做到,會犧牲一個
eureka 保證 AP
zookeeper 保證 CP
長時間沒有人連 eureka 會報這個警告,或者我將名稱換掉也會,因為他要保證可用性,有可能只是網路不順,寧可記錄錯的資料也不要刪掉,而預設過了 90 秒後,真的都沒有人連了,才會刪除,如果不喜歡這個功能,可以關掉
eureka.server.enable-self-preservation: false
※actuator/info
上面的 Status 一點進去就掛了,這裡是設定裡面的資訊<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> ----------------------------- <build> <finalName>SpringCloudPractice</finalName> <resources> <resource> <directory>src/main/resources</directory> <filtering>true</filtering> </resource> </resources> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-resources-plugin</artifactId> <configuration> <delimiters> <delimit>@</delimit> </delimiters> </configuration> </plugin> </plugins> </build>
※這裡的 pom 是全域的
※delimit 裡面的符號是用在註冊進 eureka 的專案要用到的,前後用這個符號包起來即可
※以下以 provider 為例,在 application.yml 增加如下的設定
info: xxx.ooo: xxoo.aa name: provider.info jdk_version: @java.version@ version: @version@ chi_test: 梅山小路用
※info 下的 key 和 value 都可以隨便亂打,但 @ 包起來的部分會去 pom 抓,有自己的就抓自己的,沒有就抓父 pom 的,雖然 provider 有 api,但不會去抓,如果都沒有,啟動會報錯
※服務發現
使用 DiscoveryClient 可以發現 Eureka 上註冊的服務
@Resource private DiscoveryClient client; @GetMapping("/discovery") public DiscoveryClient discoveryTest() { List<String> services = client.getServices(); System.out.println("所有服務名稱=" + services); // List<ServiceInstance> instances = client.getInstances("provider1".toUpperCase()); // 一定要大寫 services.forEach(serviceName -> { List<ServiceInstance> instances = client.getInstances(serviceName); instances.forEach(s -> { System.out.println("host=" + s.getHost()); // 192.168.254.104 System.out.println("instanceId=" + s.getInstanceId()); // bruceProvider1 System.out.println("scheme=" + s.getScheme()); // null System.out.println("serviceId=" + s.getServiceId()); // PROVIDER1 System.out.println("port=" + s.getPort()); // 9001 System.out.println("uri=" + s.getUri()); // http://192.168.254.104:9001 Map<String, String> metadata = s.getMetadata(); metadata.forEach((k, v) -> { System.out.print("key=" + k); // management.port System.out.println(", value=" + v); // 9001 }); }); System.out.println("------------------------------------"); }); return client; }
※在 provider 加上上面的程式碼
※注意 DiscoveryClient是
org.springframework.cloud.client.discovery 的包
※在 provider 的啟動類上加上 @EnableDiscoveryClient,但我試的結果,不加也可以
private static final String PROVIDER_URI = "http://localhost:9001"; @GetMapping("/consumer/discovery") public Object discovery() { return restTemplate.getForObject(PROVIDER_URI + "/discovery", Object.class); }
※provider 最後是要給 consumer 的,所以這裡新增這一段程式碼,但回傳值我給 DiscoveryClient 後,打上網址 localhost/consumer/discovery 會報錯
※Eureka 增加帳號密碼
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency>
※在 Eureka server 增加 security 的 POM
※application.yml 增加 spring.security.user,下一層有 name 和 password 可以設定帳號密碼
※如果有集群,每個都要加 pom 和設定密碼,也可以設定不一樣的帳密
※如果只有加 pom,連網址就會出現打帳密的視窗,但因為沒有帳密進不去
※
@SpringBootApplication @EnableEurekaServer public class EurekaMain extends WebSecurityConfigurerAdapter { public static void main(String[] args) { SpringApplication.run(EurekaMain.class, args); } @Override protected void configure(HttpSecurity http) throws Exception { // http.csrf().disable(); // 不處理 CSRF 攻擊 http.csrf().ignoringAntMatchers("/eureka/**"); super.configure(http); } }
※繼承 WebSecurityConfigurerAdapter 後,覆寫 configure,參數是 HttpSecurity 的
※也可以自己寫一個類別繼承 WebSecurityConfigurerAdapte
※不繼承,server 端不會有問題,差在 client 端要連的時候會報 Cannot execute request on any known server 的錯
※用戶端連 eureka 時,只要在 application.yml 的 defaultZone 改一下就可以,如
http://xxx:ooo@xxx.ooo9051:9051/eureka
就是在原本的網址加上「帳號:密碼@」
沒有留言:
張貼留言