mirror of
https://github.com/spring-cloud/spring-cloud-netflix.git
synced 2026-09-18 08:09:07 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
85b29b436c | ||
|
|
f501e887be | ||
|
|
afbb8fd97a | ||
|
|
3ce1e124af | ||
|
|
c89d7f13d6 | ||
|
|
f6795eefeb | ||
|
|
0654980024 | ||
|
|
9ebf9cff58 | ||
|
|
5a1391f196 | ||
|
|
1556cbc5a2 | ||
|
|
f8f3082460 | ||
|
|
6cc39452dc | ||
|
|
51884beff4 | ||
|
|
925db750b7 | ||
|
|
47b2feb15a | ||
|
|
ede54db95f | ||
|
|
e64ecc7f85 | ||
|
|
0847c816cb | ||
|
|
889984ca48 | ||
|
|
fe1538d298 | ||
|
|
b3c573a146 | ||
|
|
65a8b97459 | ||
|
|
d1032a9bb4 | ||
|
|
cc51cd8735 | ||
|
|
8a1569162b | ||
|
|
b2d3f8225b | ||
|
|
f37374d472 | ||
|
|
4c1b865012 | ||
|
|
2d567b1d8b | ||
|
|
004caa8192 | ||
|
|
17e7a17f23 | ||
|
|
640658cf76 | ||
|
|
a48f6f5b36 | ||
|
|
2ab399a0fd | ||
|
|
0df610d62e | ||
|
|
3b6ba97cd8 | ||
|
|
c9d9905237 | ||
|
|
6bbda54f62 | ||
|
|
4a7b540cf9 | ||
|
|
ab72b970c0 | ||
|
|
70788002d0 | ||
|
|
cae667d82a | ||
|
|
5ad0371e97 | ||
|
|
68eaa21dc2 | ||
|
|
3fa392a27d | ||
|
|
6d102063e9 | ||
|
|
36703d873a | ||
|
|
fee8feb984 | ||
|
|
72bffe037f | ||
|
|
c354057488 | ||
|
|
42f4149ff8 | ||
|
|
4d374ee357 | ||
|
|
9117a25069 | ||
|
|
25e725e854 | ||
|
|
dd72a3e684 | ||
|
|
54fa25f9c5 | ||
|
|
f84e17324d | ||
|
|
db8be6af5a | ||
|
|
68b32f5b87 | ||
|
|
d08a176b17 | ||
|
|
b70c400c53 | ||
|
|
2a998461e7 | ||
|
|
12f426a85a | ||
|
|
7cd9878aa1 | ||
|
|
bb66fcd1b5 | ||
|
|
c497d39fc6 | ||
|
|
cf12bee60e | ||
|
|
08e02ad0c9 | ||
|
|
c0d9f1fa5c | ||
|
|
daab658d8f | ||
|
|
be1e756370 | ||
|
|
7878fb5f8a | ||
|
|
3f36565a36 | ||
|
|
1a381ddc93 | ||
|
|
b6353637c9 | ||
|
|
253f9c1d18 | ||
|
|
c1af2d65e9 | ||
|
|
49476de4c8 | ||
|
|
77b73b65f9 | ||
|
|
cfbaef0c50 | ||
|
|
95441aef81 | ||
|
|
0855dd64ac | ||
|
|
cae32c8d53 | ||
|
|
c0e31237f2 | ||
|
|
92e355543b | ||
|
|
7818b881db | ||
|
|
6aa989eb18 | ||
|
|
55d1253d38 | ||
|
|
ced9207db9 | ||
|
|
8060bd35a7 | ||
|
|
9bb3eb87c9 | ||
|
|
e7a0ecbf78 | ||
|
|
21f50f8a28 | ||
|
|
4a3ba2be64 | ||
|
|
64ecafca42 | ||
|
|
8da42d23d7 | ||
|
|
6b0c74b854 | ||
|
|
dd2d5cd013 | ||
|
|
5c080a48b3 | ||
|
|
9601dc04fa | ||
|
|
39bd9aa0c6 | ||
|
|
1ee84b68b4 | ||
|
|
bdccd8d5bb | ||
|
|
bdaacaac28 | ||
|
|
9e9785a1d9 | ||
|
|
404fb89fe9 | ||
|
|
651c035fb4 | ||
|
|
d33aa03ff2 | ||
|
|
e7e265feba | ||
|
|
45a6657800 | ||
|
|
4fdf471acd | ||
|
|
c318efa173 | ||
|
|
a607986345 | ||
|
|
33215dc079 | ||
|
|
866dfe1a83 | ||
|
|
47f989fa7b | ||
|
|
798d6ba29a | ||
|
|
4f181b65e1 | ||
|
|
fda86f94f0 | ||
|
|
aa49ce6171 | ||
|
|
d83fbc8176 | ||
|
|
41ef79beb8 | ||
|
|
f01832b08d | ||
|
|
25de83e70b | ||
|
|
44bc8a0f26 | ||
|
|
f722baa811 | ||
|
|
c935fd79ec | ||
|
|
1314715c19 | ||
|
|
34c1b9d9e2 | ||
|
|
d104c36968 | ||
|
|
d8afd906c5 | ||
|
|
9be3229249 | ||
|
|
e570ec275b | ||
|
|
2122fa420c | ||
|
|
cb47274dc7 | ||
|
|
3277e5558a | ||
|
|
cc432a4c1a | ||
|
|
ce229a7ac3 | ||
|
|
eba4fa8cda | ||
|
|
a0368c39fa | ||
|
|
3ad1ac3448 | ||
|
|
a1fddaf139 | ||
|
|
d429c7623f | ||
|
|
b6c087232c | ||
|
|
37cb7d369b | ||
|
|
ab76ec72e9 | ||
|
|
00ade3f8d3 | ||
|
|
6ba1684ced | ||
|
|
9274d7cebe | ||
|
|
224e06856b | ||
|
|
12f664ab76 | ||
|
|
4f9d969a78 | ||
|
|
ad30b66f94 | ||
|
|
fdd72f5ac9 | ||
|
|
ccedad0c94 | ||
|
|
590e5a2175 | ||
|
|
9dbf8dc87a | ||
|
|
dd8855dfe6 | ||
|
|
53ef874148 | ||
|
|
d2e3d4bf37 | ||
|
|
6840f4f169 | ||
|
|
bafa368133 | ||
|
|
a469382dae | ||
|
|
eb04c42889 | ||
|
|
4178e721d2 | ||
|
|
ac302a26a5 | ||
|
|
bdea755c7d | ||
|
|
6efc38d972 | ||
|
|
e71bed3610 | ||
|
|
8e5a21179d | ||
|
|
97ed49d29a | ||
|
|
d21cfa9c63 | ||
|
|
eab96b8535 | ||
|
|
a706bfcc9e | ||
|
|
4db3c7f45d | ||
|
|
6a5d8c36ab | ||
|
|
0b3683a500 | ||
|
|
06e41db342 | ||
|
|
ed6afeccb5 | ||
|
|
714c3dd285 | ||
|
|
a7e6088b99 |
@@ -0,0 +1,13 @@
|
||||
name: Build Release
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Build Release
|
||||
shell: bash
|
||||
# If we are on Java 8 we need to build the docs zip for jubilee projects so it is distributed as part of the release
|
||||
run: |
|
||||
if java -version 2>&1 | grep -q '1\.8\.'; then
|
||||
./mvnw --batch-mode --settings release-train-settings.xml clean deploy --activate-profiles releaseTrain,docs -DaltDeploymentRepository="release-train::default::file://$(pwd)/deployment-repository" -Dmaven-deploy-plugin.deployZipUrl="file://$(pwd)/deployment-repository" -Dmaven-deploy-plugin-default.phase=deploy -Dupload-docs-zip.packaging=zip -DskipTests
|
||||
else
|
||||
./mvnw --batch-mode --settings release-train-settings.xml clean deploy --activate-profiles releaseTrain -DaltDeploymentRepository="release-train::default::file://$(pwd)/deployment-repository" -DskipTests
|
||||
fi
|
||||
@@ -0,0 +1,10 @@
|
||||
artifactory:
|
||||
artifacts:
|
||||
- pattern: "/**/spring-cloud-*-docs-*.zip"
|
||||
properties:
|
||||
zip.deployed: "false"
|
||||
zip.type: "docs"
|
||||
- pattern: "/**/spring-cloud-docs-*.zip"
|
||||
properties:
|
||||
zip.deployed: "false"
|
||||
zip.type: "docs"
|
||||
@@ -0,0 +1,7 @@
|
||||
name: Test Release
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Test Release
|
||||
shell: bash
|
||||
run: ./mvnw --batch-mode --settings release-train-settings.xml clean verify --activate-profiles releaseTrain
|
||||
+29
-39
@@ -1,52 +1,26 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
target-branch: "4.1.x" # oldest OSS supported branch
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
target-branch: "4.2.x"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
target-branch: "main"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
- package-ecosystem: maven
|
||||
directory: /
|
||||
schedule:
|
||||
interval: daily
|
||||
target-branch: 4.1.x
|
||||
ignore:
|
||||
# only upgrade patch versions for maintenance branch
|
||||
- dependency-name: "*"
|
||||
update-types:
|
||||
- version-update:semver-major
|
||||
- version-update:semver-minor
|
||||
- package-ecosystem: maven
|
||||
directory: /
|
||||
schedule:
|
||||
interval: daily
|
||||
target-branch: 4.2.x
|
||||
ignore:
|
||||
# only upgrade patch versions for maintenance branch
|
||||
- dependency-name: "*"
|
||||
update-types:
|
||||
- version-update:semver-major
|
||||
- version-update:semver-minor
|
||||
exclude-paths:
|
||||
- ".github/workflows/release-train-test.yml"
|
||||
- ".github/workflows/release-train-build.yml"
|
||||
- package-ecosystem: maven
|
||||
directory: /
|
||||
schedule:
|
||||
interval: daily
|
||||
target-branch: main
|
||||
ignore:
|
||||
# only upgrade by minor or patch
|
||||
# glob 7.2.3+ conflicts with jshint (minimatch) in wro4j-maven-plugin
|
||||
- dependency-name: "org.webjars.npm:glob"
|
||||
# only upgrade patch versions for maintenance branch
|
||||
- dependency-name: "*"
|
||||
update-types:
|
||||
- version-update:semver-major
|
||||
- version-update:semver-minor
|
||||
- package-ecosystem: npm
|
||||
target-branch: docs-build
|
||||
directory: /
|
||||
@@ -57,13 +31,29 @@ updates:
|
||||
directory: /docs
|
||||
schedule:
|
||||
interval: weekly
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
target-branch: "5.0.x"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
exclude-paths:
|
||||
- ".github/workflows/release-train-test.yml"
|
||||
- ".github/workflows/release-train-build.yml"
|
||||
- package-ecosystem: maven
|
||||
directory: /
|
||||
schedule:
|
||||
interval: daily
|
||||
target-branch: 5.0.x
|
||||
ignore:
|
||||
# glob 7.2.3+ conflicts with jshint (minimatch) in wro4j-maven-plugin
|
||||
- dependency-name: "org.webjars.npm:glob"
|
||||
# only upgrade patch versions for maintenance branch
|
||||
- dependency-name: "*"
|
||||
update-types:
|
||||
- version-update:semver-major
|
||||
- version-update:semver-minor
|
||||
- package-ecosystem: npm
|
||||
target-branch: 4.1.x
|
||||
directory: /docs
|
||||
schedule:
|
||||
interval: weekly
|
||||
- package-ecosystem: npm
|
||||
target-branch: 4.2.x
|
||||
target-branch: 5.0.x
|
||||
directory: /docs
|
||||
schedule:
|
||||
interval: weekly
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
workflow:
|
||||
generator:
|
||||
project:
|
||||
java:
|
||||
versions:
|
||||
primary: 17
|
||||
workflows:
|
||||
release-train:
|
||||
build:
|
||||
env:
|
||||
COMMERCIAL_REPO_USERNAME: secrets.COMMERCIAL_ARTIFACTORY_USERNAME
|
||||
COMMERCIAL_REPO_PASSWORD: secrets.COMMERCIAL_ARTIFACTORY_PASSWORD
|
||||
GH_ACTIONS_REPO_TOKEN: secrets.GH_ACTIONS_REPO_TOKEN
|
||||
test:
|
||||
env:
|
||||
COMMERCIAL_REPO_USERNAME: secrets.COMMERCIAL_ARTIFACTORY_USERNAME
|
||||
COMMERCIAL_REPO_PASSWORD: secrets.COMMERCIAL_ARTIFACTORY_PASSWORD
|
||||
@@ -3,6 +3,7 @@ name: Spring Cloud Netflix CI Job
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- 4.3.x
|
||||
|
||||
# Scheduled builds run daily at midnight UTC
|
||||
@@ -15,12 +16,12 @@ on:
|
||||
branches:
|
||||
description: "Which branch should be built (can be a comma-separated list of branches)"
|
||||
required: true
|
||||
default: '4.3.x'
|
||||
default: 'main'
|
||||
type: string
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
uses: spring-cloud/spring-cloud-github-actions/.github/workflows/deploy.yml@main
|
||||
uses: spring-cloud/spring-cloud-github-actions/.github/workflows/deploy.yml@b6a6b1963b8762420526591c3d363bd7d09e7d4b # v1.1.1
|
||||
with:
|
||||
branches: ${{ inputs.branches }}
|
||||
secrets:
|
||||
|
||||
@@ -1,30 +1,46 @@
|
||||
# Generated by the rollout-deploy-docs-trigger workflow in
|
||||
# spring-cloud/spring-cloud-github-actions.
|
||||
#
|
||||
# Do not edit this file directly - update examples/deploy-docs-trigger.yml
|
||||
# there and re-run the rollout, otherwise your change will be overwritten.
|
||||
|
||||
name: Deploy Docs
|
||||
|
||||
on:
|
||||
push:
|
||||
branches-ignore: [ gh-pages ]
|
||||
# Allow-list of exactly this branch. A topic or Dependabot branch cut from
|
||||
# it carries this file too, and without this filter every push to one of
|
||||
# those would dispatch a full docs build for a ref that is not in the
|
||||
# Antora playbook.
|
||||
branches:
|
||||
- main
|
||||
tags: '**'
|
||||
repository_dispatch:
|
||||
types: request-build-reference # legacy
|
||||
#schedule:
|
||||
#- cron: '0 10 * * *' # Once per day at 10am UTC
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
actions: write
|
||||
contents: read # required to check out private commercial repositories
|
||||
actions: write # required to dispatch the docs build
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
# if: github.repository_owner == 'spring-cloud'
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
ref: docs-build
|
||||
fetch-depth: 1
|
||||
|
||||
# A branch push rebuilds just that branch's docs; a tag push rebuilds
|
||||
# everything so the new version appears in the version dropdown.
|
||||
- name: Dispatch (partial build)
|
||||
if: github.ref_type == 'branch'
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: gh workflow run deploy-docs.yml -r $(git rev-parse --abbrev-ref HEAD) -f build-refname=${{ github.ref_name }}
|
||||
|
||||
- name: Dispatch (full build)
|
||||
if: github.ref_type == 'tag'
|
||||
env:
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
# This workflow will build a Java project with Maven
|
||||
# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven
|
||||
|
||||
name: Build
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [ main, 4.3.x, 4.2.x ]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
java: ["17"]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- name: Set up JDK ${{ matrix.java }}
|
||||
uses: actions/setup-java@v5
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: ${{ matrix.java }}
|
||||
cache: 'maven'
|
||||
- name: Build with Maven
|
||||
run: ./mvnw clean install -B -U -P sonar
|
||||
- uses: codecov/codecov-action@v6
|
||||
with:
|
||||
fail_ci_if_error: false
|
||||
@@ -0,0 +1,9 @@
|
||||
name: PR
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [ main, 4.3.x ]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
uses: spring-cloud/spring-cloud-github-actions/.github/workflows/pr.yml@b6a6b1963b8762420526591c3d363bd7d09e7d4b # v1.1.1
|
||||
@@ -0,0 +1,91 @@
|
||||
# This file was auto-generated by github-actions-workflow-generator 0.0.6. Do not edit.
|
||||
# To update it, modify .github/workflow-generator.yml as needed and re-run the generator.
|
||||
|
||||
name: "Release Train – Build"
|
||||
run-name: "${{ inputs.callback-ref }} – Build"
|
||||
"on":
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
callback:
|
||||
description: "Repository to which a callback should be made upon completion"
|
||||
required: true
|
||||
type: "string"
|
||||
callback-ref:
|
||||
description: "Ref in the callback repository to which a callback should be made upon completion"
|
||||
required: true
|
||||
type: "string"
|
||||
release-train-maven-repository-url:
|
||||
description: "URL of a Maven repository to be used to resolve artifacts of projects earlier in the train"
|
||||
required: true
|
||||
type: "string"
|
||||
permissions:
|
||||
contents: "read"
|
||||
concurrency:
|
||||
group: "${{ github.workflow }}-${{ github.ref }}"
|
||||
jobs:
|
||||
build-release:
|
||||
name: "Build Release"
|
||||
runs-on: "ubuntu22-2-8"
|
||||
steps:
|
||||
- name: "Prevent Re-runs"
|
||||
id: "prevent-re-runs"
|
||||
run: |-
|
||||
if [ "$GITHUB_RUN_ATTEMPT" -gt 1 ]; then
|
||||
echo "Re-runs are prohibited. Use the 'Release Train – Retry' workflow to retry build failures"
|
||||
exit 1
|
||||
fi
|
||||
- name: "Set up Java"
|
||||
id: "set-up-java"
|
||||
uses: "actions/setup-java@03ad4de0992f5dab5e18fcb136590ce7c4a0ac95" # v5.6.0
|
||||
with:
|
||||
distribution: "liberica"
|
||||
java-version: "17"
|
||||
- name: "Check Out Code"
|
||||
id: "check-out-code"
|
||||
uses: "actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0" # v7.0.0
|
||||
- name: "Build Release"
|
||||
id: "build-release"
|
||||
uses: "./.github/actions/release-train-build"
|
||||
env:
|
||||
COMMERCIAL_REPO_PASSWORD: "${{ secrets.COMMERCIAL_ARTIFACTORY_PASSWORD }}"
|
||||
COMMERCIAL_REPO_USERNAME: "${{ secrets.COMMERCIAL_ARTIFACTORY_USERNAME }}"
|
||||
GH_ACTIONS_REPO_TOKEN: "${{ secrets.GH_ACTIONS_REPO_TOKEN }}"
|
||||
RELEASE_TRAIN_MAVEN_REPOSITORY_PASSWORD: "${{ secrets.RELEASE_TRAIN_PARTICIPANT_MAVEN_REPOSITORY_PASSWORD }}"
|
||||
RELEASE_TRAIN_MAVEN_REPOSITORY_URL: "${{ inputs.release-train-maven-repository-url }}"
|
||||
RELEASE_TRAIN_MAVEN_REPOSITORY_USERNAME: "${{ secrets.RELEASE_TRAIN_PARTICIPANT_MAVEN_REPOSITORY_USERNAME }}"
|
||||
- name: "Upload Deployment Repository"
|
||||
id: "upload-deployment-repository"
|
||||
uses: "actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a" # v7.0.1
|
||||
with:
|
||||
name: "deployment-repository"
|
||||
path: "deployment-repository/**"
|
||||
- name: "Upload Deployment Spec"
|
||||
id: "upload-deployment-spec"
|
||||
uses: "actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a" # v7.0.1
|
||||
with:
|
||||
archive: "false"
|
||||
if-no-files-found: "ignore"
|
||||
name: "deployment-spec"
|
||||
path: ".github/actions/release-train-build/deployment-spec.yml"
|
||||
- name: "Save Build System Caches"
|
||||
id: "save-build-system-caches"
|
||||
uses: "actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9" # v6.1.0
|
||||
with:
|
||||
key: "release-train-${{ inputs.callback-ref }}-${{ github.ref_name }}"
|
||||
path: "~/.m2/repository"
|
||||
- name: "Send Callback"
|
||||
id: "send-callback"
|
||||
if: "${{ !cancelled() }}"
|
||||
env:
|
||||
GH_TOKEN: "${{ secrets.RELEASE_TRAIN_PARTICIPANT_GITHUB_TOKEN }}"
|
||||
run: |-
|
||||
gh workflow run callback \
|
||||
--repo ${{ inputs.callback }} \
|
||||
--ref ${{ inputs.callback-ref }} \
|
||||
--field commit-hash=${{ steps.check-out-code.outputs.commit }} \
|
||||
--field deployment-repository-artifact-identifier=${{ steps.upload-deployment-repository.outputs.artifact-id }} \
|
||||
--field deployment-spec-artifact-identifier=${{ steps.upload-deployment-spec.outputs.artifact-id }} \
|
||||
--field release-branch=${{ github.ref_name }} \
|
||||
--field release-repository=${{ github.repository }} \
|
||||
--field result=${{ job.status == 'success' && 'built' || 'build-failed' }} \
|
||||
--field workflow-run-url=${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
|
||||
@@ -0,0 +1,55 @@
|
||||
# This file was auto-generated by github-actions-workflow-generator 0.0.6. Do not edit.
|
||||
# To update it, modify .github/workflow-generator.yml as needed and re-run the generator.
|
||||
|
||||
name: "Release Train – Join"
|
||||
run-name: "${{ inputs.release-train }} – Join"
|
||||
"on":
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
deployment-destination:
|
||||
description: "Destination to which the release should be deployed"
|
||||
options:
|
||||
- "Maven Central"
|
||||
- "Spring Enterprise"
|
||||
required: true
|
||||
type: "choice"
|
||||
release-train:
|
||||
description: "Release train"
|
||||
required: true
|
||||
type: "string"
|
||||
release-train-repository:
|
||||
default: "spring-io/release-train"
|
||||
description: "Release train repository"
|
||||
required: true
|
||||
type: "string"
|
||||
permissions:
|
||||
contents: "none"
|
||||
jobs:
|
||||
join-release-train:
|
||||
name: "Join Release Train"
|
||||
runs-on: "ubuntu-latest"
|
||||
steps:
|
||||
- name: "Join Release Train"
|
||||
id: "join-release-train"
|
||||
env:
|
||||
GH_TOKEN: "${{ secrets.RELEASE_TRAIN_PARTICIPANT_GITHUB_TOKEN }}"
|
||||
run: |-
|
||||
run_url=$(
|
||||
gh workflow run join \
|
||||
--repo ${{ inputs.release-train-repository }} \
|
||||
--ref ${{ inputs.release-train }} \
|
||||
--field commit-hash=${{ github.sha }} \
|
||||
--field deployment-destination=${{ inputs.deployment-destination == 'Maven Central' && 'maven-central' || 'spring-enterprise' }} \
|
||||
--field release-branch=${{ github.ref_name }} \
|
||||
--field release-repository=${{ github.repository }}
|
||||
)
|
||||
echo "Dispatched workflow run. Waiting for $run_url to complete."
|
||||
run_id=${run_url##*/}
|
||||
watch_exit_code=0
|
||||
gh run watch $run_id --repo ${{ inputs.release-train-repository }} --exit-status --interval=3 > /dev/null 2>&1 || watch_exit_code=$?
|
||||
if [[ $watch_exit_code -eq 0 ]]; then
|
||||
echo "Workflow run succeeded."
|
||||
else
|
||||
echo "Workflow run failed."
|
||||
fi
|
||||
exit $watch_exit_code
|
||||
@@ -0,0 +1,46 @@
|
||||
# This file was auto-generated by github-actions-workflow-generator 0.0.6. Do not edit.
|
||||
# To update it, modify .github/workflow-generator.yml as needed and re-run the generator.
|
||||
|
||||
name: "Release Train – Leave"
|
||||
run-name: "${{ inputs.release-train }} – Leave"
|
||||
"on":
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
release-train:
|
||||
description: "Release train"
|
||||
required: true
|
||||
type: "string"
|
||||
release-train-repository:
|
||||
default: "spring-io/release-train"
|
||||
description: "Release train repository"
|
||||
required: true
|
||||
type: "string"
|
||||
permissions:
|
||||
contents: "none"
|
||||
jobs:
|
||||
leave:
|
||||
name: "Leave"
|
||||
runs-on: "ubuntu-latest"
|
||||
steps:
|
||||
- name: "Leave"
|
||||
id: "leave"
|
||||
env:
|
||||
GH_TOKEN: "${{ secrets.RELEASE_TRAIN_PARTICIPANT_GITHUB_TOKEN }}"
|
||||
run: |-
|
||||
run_url=$(
|
||||
gh workflow run leave \
|
||||
--repo ${{ inputs.release-train-repository }} \
|
||||
--ref ${{ inputs.release-train }} \
|
||||
--field release-branch=${{ github.ref_name }} \
|
||||
--field release-repository=${{ github.repository }}
|
||||
)
|
||||
echo "Dispatched workflow run. Waiting for $run_url to complete."
|
||||
run_id=${run_url##*/}
|
||||
watch_exit_code=0
|
||||
gh run watch $run_id --repo ${{ inputs.release-train-repository }} --exit-status --interval=3 > /dev/null 2>&1 || watch_exit_code=$?
|
||||
if [[ $watch_exit_code -eq 0 ]]; then
|
||||
echo "Workflow run succeeded."
|
||||
else
|
||||
echo "Workflow run failed."
|
||||
fi
|
||||
exit $watch_exit_code
|
||||
@@ -0,0 +1,47 @@
|
||||
# This file was auto-generated by github-actions-workflow-generator 0.0.6. Do not edit.
|
||||
# To update it, modify .github/workflow-generator.yml as needed and re-run the generator.
|
||||
|
||||
name: "Release Train – Ready"
|
||||
run-name: "${{ inputs.release-train }} – Ready"
|
||||
"on":
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
release-train:
|
||||
description: "Release train"
|
||||
required: true
|
||||
type: "string"
|
||||
release-train-repository:
|
||||
default: "spring-io/release-train"
|
||||
description: "Release train repository"
|
||||
required: true
|
||||
type: "string"
|
||||
permissions:
|
||||
contents: "none"
|
||||
jobs:
|
||||
ready:
|
||||
name: "Ready"
|
||||
runs-on: "ubuntu-latest"
|
||||
steps:
|
||||
- name: "Ready"
|
||||
id: "ready"
|
||||
env:
|
||||
GH_TOKEN: "${{ secrets.RELEASE_TRAIN_PARTICIPANT_GITHUB_TOKEN }}"
|
||||
run: |-
|
||||
run_url=$(
|
||||
gh workflow run ready \
|
||||
--repo ${{ inputs.release-train-repository }} \
|
||||
--ref ${{ inputs.release-train }} \
|
||||
--field commit-hash=${{ github.sha }} \
|
||||
--field release-branch=${{ github.ref_name }} \
|
||||
--field release-repository=${{ github.repository }}
|
||||
)
|
||||
echo "Dispatched workflow run. Waiting for $run_url to complete."
|
||||
run_id=${run_url##*/}
|
||||
watch_exit_code=0
|
||||
gh run watch $run_id --repo ${{ inputs.release-train-repository }} --exit-status --interval=3 > /dev/null 2>&1 || watch_exit_code=$?
|
||||
if [[ $watch_exit_code -eq 0 ]]; then
|
||||
echo "Workflow run succeeded."
|
||||
else
|
||||
echo "Workflow run failed."
|
||||
fi
|
||||
exit $watch_exit_code
|
||||
@@ -0,0 +1,34 @@
|
||||
# This file was auto-generated by github-actions-workflow-generator 0.0.6. Do not edit.
|
||||
# To update it, modify .github/workflow-generator.yml as needed and re-run the generator.
|
||||
|
||||
name: "Release Train – Retry"
|
||||
run-name: "${{ inputs.release-train }} – Retry"
|
||||
"on":
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
release-train:
|
||||
description: "Release train"
|
||||
required: true
|
||||
type: "string"
|
||||
release-train-repository:
|
||||
default: "spring-io/release-train"
|
||||
description: "Release train repository"
|
||||
required: true
|
||||
type: "string"
|
||||
permissions:
|
||||
contents: "none"
|
||||
jobs:
|
||||
trigger-retry:
|
||||
name: "Trigger Retry"
|
||||
runs-on: "ubuntu-latest"
|
||||
steps:
|
||||
- name: "Trigger Retry"
|
||||
id: "trigger-retry"
|
||||
env:
|
||||
GH_TOKEN: "${{ secrets.RELEASE_TRAIN_PARTICIPANT_GITHUB_TOKEN }}"
|
||||
run: |-
|
||||
gh workflow run retry \
|
||||
--repo ${{ inputs.release-train-repository }} \
|
||||
--ref ${{ inputs.release-train }} \
|
||||
--field release-branch=${{ github.ref_name }} \
|
||||
--field release-repository=${{ github.repository }}
|
||||
@@ -0,0 +1,83 @@
|
||||
# This file was auto-generated by github-actions-workflow-generator 0.0.6. Do not edit.
|
||||
# To update it, modify .github/workflow-generator.yml as needed and re-run the generator.
|
||||
|
||||
name: "Release Train – Test"
|
||||
run-name: "${{ inputs.callback-ref }} – Test"
|
||||
"on":
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
callback:
|
||||
description: "Repository to which a callback should be made upon completion"
|
||||
required: true
|
||||
type: "string"
|
||||
callback-ref:
|
||||
description: "Ref in the callback repository to which a callback should be made upon completion"
|
||||
required: true
|
||||
type: "string"
|
||||
release-train-maven-repository-url:
|
||||
description: "URL of a Maven repository to be used to resolve artifacts of projects earlier in the train"
|
||||
required: true
|
||||
type: "string"
|
||||
permissions:
|
||||
contents: "read"
|
||||
concurrency:
|
||||
group: "${{ github.workflow }}-${{ github.ref }}"
|
||||
jobs:
|
||||
test-release:
|
||||
name: "Test Release"
|
||||
runs-on: "ubuntu22-2-8"
|
||||
steps:
|
||||
- name: "Prevent Re-runs"
|
||||
id: "prevent-re-runs"
|
||||
run: |-
|
||||
if [ "$GITHUB_RUN_ATTEMPT" -gt 1 ]; then
|
||||
echo "Re-runs are prohibited. Use the 'Release Train – Retry' workflow to retry test failures"
|
||||
exit 1
|
||||
fi
|
||||
- name: "Set up Java"
|
||||
id: "set-up-java"
|
||||
uses: "actions/setup-java@03ad4de0992f5dab5e18fcb136590ce7c4a0ac95" # v5.6.0
|
||||
with:
|
||||
distribution: "liberica"
|
||||
java-version: "17"
|
||||
- name: "Check Out Code"
|
||||
id: "check-out-code"
|
||||
uses: "actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0" # v7.0.0
|
||||
- name: "Restore Build System Caches"
|
||||
id: "restore-build-system-caches"
|
||||
uses: "actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9" # v6.1.0
|
||||
with:
|
||||
key: "release-train-${{ inputs.callback-ref }}-${{ github.ref_name }}"
|
||||
path: "~/.m2/repository"
|
||||
- name: "Test Release"
|
||||
id: "test-release"
|
||||
uses: "./.github/actions/release-train-test"
|
||||
env:
|
||||
COMMERCIAL_REPO_PASSWORD: "${{ secrets.COMMERCIAL_ARTIFACTORY_PASSWORD }}"
|
||||
COMMERCIAL_REPO_USERNAME: "${{ secrets.COMMERCIAL_ARTIFACTORY_USERNAME }}"
|
||||
RELEASE_TRAIN_MAVEN_REPOSITORY_PASSWORD: "${{ secrets.RELEASE_TRAIN_PARTICIPANT_MAVEN_REPOSITORY_PASSWORD }}"
|
||||
RELEASE_TRAIN_MAVEN_REPOSITORY_URL: "${{ inputs.release-train-maven-repository-url }}"
|
||||
RELEASE_TRAIN_MAVEN_REPOSITORY_USERNAME: "${{ secrets.RELEASE_TRAIN_PARTICIPANT_MAVEN_REPOSITORY_USERNAME }}"
|
||||
- name: "Send Callback"
|
||||
id: "send-callback"
|
||||
if: "${{ !cancelled() }}"
|
||||
env:
|
||||
GH_TOKEN: "${{ secrets.RELEASE_TRAIN_PARTICIPANT_GITHUB_TOKEN }}"
|
||||
run: |-
|
||||
gh workflow run callback \
|
||||
--repo ${{ inputs.callback }} \
|
||||
--ref ${{ inputs.callback-ref }} \
|
||||
--field commit-hash=${{ steps.check-out-code.outputs.commit }} \
|
||||
--field release-branch=${{ github.ref_name }} \
|
||||
--field release-repository=${{ github.repository }} \
|
||||
--field result=${{ job.status == 'success' && 'tested' || 'test-failed' }} \
|
||||
--field workflow-run-url=${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
|
||||
- name: "Upload Build System Reports"
|
||||
id: "upload-build-system-reports"
|
||||
if: "${{ failure() }}"
|
||||
uses: "actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a" # v7.0.1
|
||||
with:
|
||||
name: "build-system-reports"
|
||||
path: |-
|
||||
**/target/surefire-reports
|
||||
**/target/failsafe-reports
|
||||
Vendored
BIN
Binary file not shown.
+4
-18
@@ -1,18 +1,4 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.4/apache-maven-3.9.4-bin.zip
|
||||
wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar
|
||||
wrapperVersion=3.3.4
|
||||
distributionType=bin
|
||||
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.16/apache-maven-3.9.16-bin.zip
|
||||
wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.3.4/maven-wrapper-3.3.4.jar
|
||||
|
||||
@@ -65,6 +65,13 @@ parsing or rendering it, just copying it to `${main.basedir}`
|
||||
any changes in the README it will then show up after a Maven build as
|
||||
a modified file in the correct place. Just commit it and push the change.
|
||||
|
||||
You can generate the docs site using the following command:
|
||||
|
||||
[indent=0]
|
||||
----
|
||||
./mvnw -pl docs -P docs antora:antora
|
||||
----
|
||||
|
||||
[[working-with-the-code]]
|
||||
== Working with the code
|
||||
If you don't have an IDE preference we would recommend that you use
|
||||
|
||||
@@ -1,6 +1,257 @@
|
||||
[[features]]
|
||||
= Spring Cloud Netflix Features
|
||||
|
||||
[[spring-cloud-eureka-server]]
|
||||
== Service Discovery: Eureka Server
|
||||
|
||||
Eureka Server acts as a service registry that Eureka clients use to discover other services.
|
||||
You can run Eureka as a standalone server or configure multiple peer-aware servers for higher availability.
|
||||
|
||||
The following sections show how to get started with Eureka Server and then describe standalone and peer-aware deployments.
|
||||
|
||||
[[netflix-eureka-server-starter]]
|
||||
=== How to Include Eureka Server
|
||||
|
||||
To include Eureka Server in your project, use the starter with a group ID of `org.springframework.cloud` and an artifact ID of `spring-cloud-starter-netflix-eureka-server`.
|
||||
See the https://projects.spring.io/spring-cloud/[Spring Cloud Project page] for details on setting up your build system with the current Spring Cloud Release Train.
|
||||
|
||||
NOTE: If your project already uses Thymeleaf as its template engine, the Freemarker templates of the Eureka server may not be loaded correctly. In this case it is necessary to configure the template loader manually:
|
||||
|
||||
.application.yml
|
||||
----
|
||||
spring:
|
||||
freemarker:
|
||||
template-loader-path: classpath:/templates/
|
||||
prefer-file-system-access: false
|
||||
----
|
||||
|
||||
[[spring-cloud-running-eureka-server]]
|
||||
=== Quick Start
|
||||
|
||||
The following example shows a minimal Eureka server:
|
||||
|
||||
[source,java,indent=0]
|
||||
----
|
||||
@SpringBootApplication
|
||||
@EnableEurekaServer
|
||||
public class Application {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(Application.class, args);
|
||||
}
|
||||
|
||||
}
|
||||
----
|
||||
|
||||
For a single standalone Eureka server, disable the client-side behavior so that the server does not attempt to register with or fetch the registry from a peer:
|
||||
|
||||
.application.yml
|
||||
----
|
||||
eureka:
|
||||
client:
|
||||
registerWithEureka: false
|
||||
fetchRegistry: false
|
||||
----
|
||||
|
||||
|
||||
The server has a home page with a UI and HTTP API endpoints for the normal Eureka functionality under `/eureka/*`.
|
||||
|
||||
[TIP]
|
||||
====
|
||||
Due to Gradle's dependency resolution rules and the lack of a parent bom feature, depending on `spring-cloud-starter-netflix-eureka-server` can cause failures on application startup.
|
||||
To remedy this issue, add the Spring Boot Gradle plugin and import the Spring cloud starter parent bom as follows:
|
||||
|
||||
.build.gradle
|
||||
[source,java,indent=0]
|
||||
----
|
||||
buildscript {
|
||||
dependencies {
|
||||
classpath("org.springframework.boot:spring-boot-gradle-plugin:{spring-boot-docs-version}")
|
||||
}
|
||||
}
|
||||
|
||||
apply plugin: "spring-boot"
|
||||
|
||||
dependencyManagement {
|
||||
imports {
|
||||
mavenBom "org.springframework.cloud:spring-cloud-dependencies:{spring-cloud-version}"
|
||||
}
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
=== `defaultOpenForTrafficCount` and its effect on EurekaServer warmup time
|
||||
|
||||
Netflix Eureka's `waitTimeInMsWhenSyncEmpty` setting is not taken into account in Spring Cloud Eureka server at the beginning. In order to enable the warmup time, set `eureka.server.defaultOpenForTrafficCount=0`.
|
||||
|
||||
[[spring-cloud-eureka-server-zones-and-regions]]
|
||||
=== High Availability, Zones and Regions
|
||||
|
||||
The Eureka server does not have a back end store, but the service instances in the registry all have to send heartbeats to keep their registrations up to date (so this can be done in memory).
|
||||
Clients also have an in-memory cache of Eureka registrations (so they do not have to go to the registry for every request to a service).
|
||||
|
||||
By default, every Eureka server is also a Eureka client and requires (at least one) service URL to locate a peer.
|
||||
If you do not provide it, the service runs and works, but it fills your logs with a lot of noise about not being able to register with the peer.
|
||||
|
||||
[[spring-cloud-eureka-server-standalone-mode]]
|
||||
=== Standalone Mode
|
||||
|
||||
The combination of the two caches (client and server) and the heartbeats make a standalone Eureka server fairly resilient to failure, as long as there is some sort of monitor or elastic runtime (such as Cloud Foundry) keeping it alive.
|
||||
In standalone mode, you might prefer to switch off the client side behavior so that it does not keep trying and failing to reach its peers.
|
||||
The following example shows how to switch off the client-side behavior:
|
||||
|
||||
.application.yml (Standalone Eureka Server)
|
||||
----
|
||||
server:
|
||||
port: 8761
|
||||
|
||||
eureka:
|
||||
instance:
|
||||
hostname: localhost
|
||||
client:
|
||||
registerWithEureka: false
|
||||
fetchRegistry: false
|
||||
serviceUrl:
|
||||
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
|
||||
----
|
||||
|
||||
Notice that the `serviceUrl` is pointing to the same host as the local instance.
|
||||
|
||||
[[spring-cloud-eureka-server-peer-awareness]]
|
||||
=== Peer Awareness
|
||||
|
||||
Eureka can be made even more resilient and available by running multiple instances and asking them to register with each other.
|
||||
In fact, this is the default behavior, so all you need to do to make it work is add a valid `serviceUrl` to a peer, as shown in the following example:
|
||||
|
||||
.application.yml (Two Peer Aware Eureka Servers)
|
||||
----
|
||||
|
||||
---
|
||||
spring:
|
||||
profiles: peer1
|
||||
eureka:
|
||||
instance:
|
||||
hostname: peer1
|
||||
client:
|
||||
serviceUrl:
|
||||
defaultZone: https://peer2/eureka/
|
||||
|
||||
---
|
||||
spring:
|
||||
profiles: peer2
|
||||
eureka:
|
||||
instance:
|
||||
hostname: peer2
|
||||
client:
|
||||
serviceUrl:
|
||||
defaultZone: https://peer1/eureka/
|
||||
----
|
||||
|
||||
In the preceding example, we have a YAML file that can be used to run the same server on two hosts (`peer1` and `peer2`) by running it in different Spring profiles.
|
||||
You could use this configuration to test the peer awareness on a single host (there is not much value in doing that in production) by manipulating `/etc/hosts` to resolve the host names.
|
||||
In fact, the `eureka.instance.hostname` is not needed if you are running on a machine that knows its own hostname (by default, it is looked up by using `java.net.InetAddress`).
|
||||
|
||||
You can add multiple peers to a system, and, as long as they are all connected to each other by at least one edge, they synchronize
|
||||
the registrations amongst themselves.
|
||||
If the peers are physically separated (inside a data center or between multiple data centers), then the system can, in principle, survive "`split-brain`" type failures.
|
||||
You can add multiple peers to a system, and as long as they are all
|
||||
directly connected to each other, they will synchronize
|
||||
the registrations amongst themselves.
|
||||
|
||||
.application.yml (Three Peer Aware Eureka Servers)
|
||||
----
|
||||
eureka:
|
||||
client:
|
||||
serviceUrl:
|
||||
defaultZone: https://peer1/eureka/,http://peer2/eureka/,http://peer3/eureka/
|
||||
|
||||
---
|
||||
spring:
|
||||
profiles: peer1
|
||||
eureka:
|
||||
instance:
|
||||
hostname: peer1
|
||||
|
||||
---
|
||||
spring:
|
||||
profiles: peer2
|
||||
eureka:
|
||||
instance:
|
||||
hostname: peer2
|
||||
|
||||
---
|
||||
spring:
|
||||
profiles: peer3
|
||||
eureka:
|
||||
instance:
|
||||
hostname: peer3
|
||||
----
|
||||
|
||||
[[spring-cloud-eureka-server-prefer-ip-address]]
|
||||
=== When to Prefer IP Address
|
||||
|
||||
In some cases, it is preferable for Eureka to advertise the IP addresses of services rather than the hostname.
|
||||
Set `eureka.instance.preferIpAddress` to `true` and, when the application registers with eureka, it uses its IP address rather than its hostname.
|
||||
|
||||
[TIP]
|
||||
====
|
||||
If the hostname cannot be determined by Java, then the IP address is sent to Eureka.
|
||||
Only explicit way of setting the hostname is by setting `eureka.instance.hostname` property.
|
||||
You can set your hostname at the run-time by using an environment variable -- for example, `eureka.instance.hostname=$\{HOST_NAME}`.
|
||||
====
|
||||
|
||||
=== Securing The Eureka Server
|
||||
|
||||
You can secure your Eureka server simply by adding Spring Security to your
|
||||
server's classpath via `spring-boot-starter-security`. By default, when Spring Security is on the classpath it will require that
|
||||
a valid CSRF token be sent with every request to the app. Eureka clients will not generally possess a valid
|
||||
cross site request forgery (CSRF) token you will need to disable this requirement for the `/eureka/**` endpoints.
|
||||
For example:
|
||||
|
||||
[source,java,indent=0]
|
||||
----
|
||||
@Bean
|
||||
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
|
||||
http.authorizeHttpRequests((authz) -> authz
|
||||
.anyRequest().authenticated())
|
||||
.httpBasic(withDefaults());
|
||||
http.csrf().ignoringRequestMatchers("/eureka/**");
|
||||
return http.build();
|
||||
}
|
||||
----
|
||||
|
||||
For more information on CSRF see the https://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#csrf[Spring Security documentation].
|
||||
|
||||
A demo Eureka Server can be found in the Spring Cloud Samples https://github.com/spring-cloud-samples/eureka/tree/Eureka-With-Security-4.x[repo].
|
||||
|
||||
=== JDK 11 Support
|
||||
|
||||
The JAXB modules which the Eureka server depends upon were removed in JDK 11. If you intend to use JDK 11
|
||||
when running a Eureka server you must include these dependencies in your POM or Gradle file.
|
||||
|
||||
[source,xml,indent=0]
|
||||
----
|
||||
<dependency>
|
||||
<groupId>org.glassfish.jaxb</groupId>
|
||||
<artifactId>jaxb-runtime</artifactId>
|
||||
</dependency>
|
||||
----
|
||||
|
||||
=== AOT and Native Image Support
|
||||
|
||||
Spring Cloud Netflix Eureka Server does not support Spring AOT transformations or native images.
|
||||
|
||||
=== Metrics
|
||||
|
||||
`EurekaInstanceMonitor` listens to events related to Eureka instance registration and creates/updates `Gauge`s for Eureka instance information in Micrometer's `MeterRegistry`. By default, this behavior is disabled. If you want to enable it, you need to set `eureka.server.metrics.enabled` to `true`.
|
||||
|
||||
By default, the `Gauge`s are named `eureka.server.instances` and have the following tags:
|
||||
|
||||
- `application`: application name
|
||||
- `status`: instance status (`UP`, `DOWN`, `STARTING`, `OUT_OF_SERVICE`, `UNKNOWN`, see: `com.netflix.appinfo.InstanceInfo.InstanceStatus`)
|
||||
|
||||
You can add additional tags by injecting your own implementation of `EurekaInstanceTagsProvider`.
|
||||
|
||||
== Service Discovery: Eureka Clients
|
||||
|
||||
Service Discovery is one of the key tenets of a microservice-based architecture.
|
||||
@@ -59,6 +310,8 @@ WARNING: The `defaultZone` property is case sensitive and requires camel case be
|
||||
|
||||
The default application name (that is, the service ID), virtual host, and non-secure port (taken from the `Environment`) are `${spring.application.name}`, `${spring.application.name}` and `${server.port}`, respectively.
|
||||
|
||||
NOTE: By default, the Eureka application name and virtual host are both derived from `spring.application.name`. If you configure `eureka.instance.virtualHostName` differently, use the virtual host name when looking up instances through Spring Cloud's `DiscoveryClient`.
|
||||
|
||||
Having `spring-cloud-starter-netflix-eureka-client` on the classpath makes the app into both a Eureka "`instance`" (that is, it registers itself) and a "`client`" (it can query the registry to locate other services).
|
||||
The instance behaviour is driven by `eureka.instance.*` configuration keys, but the defaults are fine if you ensure that your application has a value for `spring.application.name` (this is the default for the Eureka service ID or VIP).
|
||||
|
||||
@@ -96,9 +349,9 @@ The `eureka.client.tls.enabled` needs to be true to enable Eureka client side TL
|
||||
|
||||
NOTE: Because of a limitation in Eureka, it is not possible to support per-server basic auth credentials, so only the first set that are found is used.
|
||||
|
||||
If you want to customize the RestTemplate used by the Eureka HTTP Client you may want to create a bean of `EurekaClientHttpRequestFactorySupplier` and provide your own logic for generating a `ClientHttpRequestFactory` instance.
|
||||
If you want to customize the `RestClient` used by the Eureka HTTP Client you may want to create a bean of `EurekaClientHttpRequestFactorySupplier` and provide your own logic for generating a `ClientHttpRequestFactory` instance.
|
||||
|
||||
All default timeout-related properties for RestTemplate and RestClient used by the Eureka HTTP Client are set to 3 minutes (in keeping with Apache HC5 default `RequestConfig` and `SocketConfig`). Therefore, to specify the timeout values, you must specify the value directly with the properties in `eureka.client.rest-template-timeout` or `eureka.client.restclient.timeout`. All timeout properties are in milliseconds.
|
||||
All default timeout-related properties for `RestClient` used by the Eureka HTTP Client are set to 3 minutes (in keeping with Apache HC5 default `RequestConfig` and `SocketConfig`). Therefore, to specify the timeout values, you must specify the value directly with the properties in `eureka.client.timeout`. All timeout properties are in milliseconds.
|
||||
|
||||
.application.yml
|
||||
[source,yaml]
|
||||
@@ -290,11 +543,11 @@ It is initialized in a `SmartLifecycle` (with `phase=0`), so the earliest you ca
|
||||
|
||||
==== Underlying HTTP clients
|
||||
|
||||
`EurekaClient` uses either `RestClient`, `RestTemplate`, `WebClient` or `JerseyClient` under the hood. In order to use the `EurekaClient`, you need to have one of the supported HTTP clients on your classpath.
|
||||
`EurekaClient` uses either `RestClient`, `WebClient` or `JerseyClient` under the hood. In order to use the `EurekaClient`, you need to have one of the supported HTTP clients on your classpath.
|
||||
|
||||
To use `RestTemplate` or `RestClient`, add `spring-boot-starter-web` to your dependencies. To use `WebClient`, add `spring-boot-starter-webflux` to your dependencies. If both `spring-boot-starter-web`
|
||||
and `spring-boot-starter-webflux` are included in the dependencies and the `eureka.client.webclient.enabled` flag is set to `true`,
|
||||
then `WebClient` will be used. If that's not the case and `eureka.client.restclient.enabled` is set to `true`, `RestClient` will be used. Otherwise, `RestTemplate` will be used.
|
||||
To use `RestClient`, add `spring-boot-restclient` to your dependencies. To use `WebClient`, add `spring-boot-webclient` to your dependencies. If both `spring-boot-restclient`
|
||||
and `spring-boot-webclient` are included in the dependencies and the `eureka.client.webclient.enabled` flag is set to `true`,
|
||||
then `WebClient` will be used. If that's not the case, `RestClient` will be used.
|
||||
|
||||
NOTE: For any of those client implementations, if there's a builder bean available, it will be used to create the underlying client.
|
||||
|
||||
@@ -407,249 +660,9 @@ WARNING: If you want to run Eureka Client in AOT or native image modes, make sur
|
||||
|
||||
NOTE: Given the AOT and native image closed-world assumption, using random port with Eureka clients is not supported for ahead of time compilation or native images.
|
||||
|
||||
[[spring-cloud-eureka-server]]
|
||||
== Service Discovery: Eureka Server
|
||||
|
||||
This section describes how to set up a Eureka server.
|
||||
|
||||
[[netflix-eureka-server-starter]]
|
||||
=== How to Include Eureka Server
|
||||
|
||||
To include Eureka Server in your project, use the starter with a group ID of `org.springframework.cloud` and an artifact ID of `spring-cloud-starter-netflix-eureka-server`.
|
||||
See the https://projects.spring.io/spring-cloud/[Spring Cloud Project page] for details on setting up your build system with the current Spring Cloud Release Train.
|
||||
|
||||
NOTE: If your project already uses Thymeleaf as its template engine, the Freemarker templates of the Eureka server may not be loaded correctly. In this case it is necessary to configure the template loader manually:
|
||||
|
||||
.application.yml
|
||||
----
|
||||
spring:
|
||||
freemarker:
|
||||
template-loader-path: classpath:/templates/
|
||||
prefer-file-system-access: false
|
||||
----
|
||||
|
||||
[[spring-cloud-running-eureka-server]]
|
||||
=== How to Run a Eureka Server
|
||||
|
||||
The following example shows a minimal Eureka server:
|
||||
|
||||
[source,java,indent=0]
|
||||
----
|
||||
@SpringBootApplication
|
||||
@EnableEurekaServer
|
||||
public class Application {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(CustomerServiceTestApplication.class, args);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
----
|
||||
|
||||
The server has a home page with a UI and HTTP API endpoints for the normal Eureka functionality under `/eureka/*`.
|
||||
|
||||
The following links have some Eureka background reading: https://github.com/cfregly/fluxcapacitor/wiki/NetflixOSS-FAQ#eureka-service-discovery-load-balancer[flux capacitor] and https://groups.google.com/forum/?fromgroups#!topic/eureka_netflix/g3p2r7gHnN0[google group discussion].
|
||||
|
||||
[TIP]
|
||||
====
|
||||
Due to Gradle's dependency resolution rules and the lack of a parent bom feature, depending on `spring-cloud-starter-netflix-eureka-server` can cause failures on application startup.
|
||||
To remedy this issue, add the Spring Boot Gradle plugin and import the Spring cloud starter parent bom as follows:
|
||||
|
||||
.build.gradle
|
||||
[source,java,indent=0]
|
||||
----
|
||||
buildscript {
|
||||
dependencies {
|
||||
classpath("org.springframework.boot:spring-boot-gradle-plugin:{spring-boot-docs-version}")
|
||||
}
|
||||
}
|
||||
|
||||
apply plugin: "spring-boot"
|
||||
|
||||
dependencyManagement {
|
||||
imports {
|
||||
mavenBom "org.springframework.cloud:spring-cloud-dependencies:{spring-cloud-version}"
|
||||
}
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
=== `defaultOpenForTrafficCount` and its effect on EurekaServer warmup time
|
||||
|
||||
Netflix Eureka's `waitTimeInMsWhenSyncEmpty` setting is not taken into account in Spring Cloud Eureka server at the beginning. In order to enable the warmup time, set `eureka.server.defaultOpenForTrafficCount=0`.
|
||||
|
||||
[[spring-cloud-eureka-server-zones-and-regions]]
|
||||
=== High Availability, Zones and Regions
|
||||
|
||||
The Eureka server does not have a back end store, but the service instances in the registry all have to send heartbeats to keep their registrations up to date (so this can be done in memory).
|
||||
Clients also have an in-memory cache of Eureka registrations (so they do not have to go to the registry for every request to a service).
|
||||
|
||||
By default, every Eureka server is also a Eureka client and requires (at least one) service URL to locate a peer.
|
||||
If you do not provide it, the service runs and works, but it fills your logs with a lot of noise about not being able to register with the peer.
|
||||
|
||||
[[spring-cloud-eureka-server-standalone-mode]]
|
||||
=== Standalone Mode
|
||||
|
||||
The combination of the two caches (client and server) and the heartbeats make a standalone Eureka server fairly resilient to failure, as long as there is some sort of monitor or elastic runtime (such as Cloud Foundry) keeping it alive.
|
||||
In standalone mode, you might prefer to switch off the client side behavior so that it does not keep trying and failing to reach its peers.
|
||||
The following example shows how to switch off the client-side behavior:
|
||||
|
||||
.application.yml (Standalone Eureka Server)
|
||||
----
|
||||
server:
|
||||
port: 8761
|
||||
|
||||
eureka:
|
||||
instance:
|
||||
hostname: localhost
|
||||
client:
|
||||
registerWithEureka: false
|
||||
fetchRegistry: false
|
||||
serviceUrl:
|
||||
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
|
||||
----
|
||||
|
||||
Notice that the `serviceUrl` is pointing to the same host as the local instance.
|
||||
|
||||
[[spring-cloud-eureka-server-peer-awareness]]
|
||||
=== Peer Awareness
|
||||
|
||||
Eureka can be made even more resilient and available by running multiple instances and asking them to register with each other.
|
||||
In fact, this is the default behavior, so all you need to do to make it work is add a valid `serviceUrl` to a peer, as shown in the following example:
|
||||
|
||||
.application.yml (Two Peer Aware Eureka Servers)
|
||||
----
|
||||
|
||||
---
|
||||
spring:
|
||||
profiles: peer1
|
||||
eureka:
|
||||
instance:
|
||||
hostname: peer1
|
||||
client:
|
||||
serviceUrl:
|
||||
defaultZone: https://peer2/eureka/
|
||||
|
||||
---
|
||||
spring:
|
||||
profiles: peer2
|
||||
eureka:
|
||||
instance:
|
||||
hostname: peer2
|
||||
client:
|
||||
serviceUrl:
|
||||
defaultZone: https://peer1/eureka/
|
||||
----
|
||||
|
||||
In the preceding example, we have a YAML file that can be used to run the same server on two hosts (`peer1` and `peer2`) by running it in different Spring profiles.
|
||||
You could use this configuration to test the peer awareness on a single host (there is not much value in doing that in production) by manipulating `/etc/hosts` to resolve the host names.
|
||||
In fact, the `eureka.instance.hostname` is not needed if you are running on a machine that knows its own hostname (by default, it is looked up by using `java.net.InetAddress`).
|
||||
|
||||
You can add multiple peers to a system, and, as long as they are all connected to each other by at least one edge, they synchronize
|
||||
the registrations amongst themselves.
|
||||
If the peers are physically separated (inside a data center or between multiple data centers), then the system can, in principle, survive "`split-brain`" type failures.
|
||||
You can add multiple peers to a system, and as long as they are all
|
||||
directly connected to each other, they will synchronize
|
||||
the registrations amongst themselves.
|
||||
|
||||
.application.yml (Three Peer Aware Eureka Servers)
|
||||
----
|
||||
eureka:
|
||||
client:
|
||||
serviceUrl:
|
||||
defaultZone: https://peer1/eureka/,http://peer2/eureka/,http://peer3/eureka/
|
||||
|
||||
---
|
||||
spring:
|
||||
profiles: peer1
|
||||
eureka:
|
||||
instance:
|
||||
hostname: peer1
|
||||
|
||||
---
|
||||
spring:
|
||||
profiles: peer2
|
||||
eureka:
|
||||
instance:
|
||||
hostname: peer2
|
||||
|
||||
---
|
||||
spring:
|
||||
profiles: peer3
|
||||
eureka:
|
||||
instance:
|
||||
hostname: peer3
|
||||
----
|
||||
|
||||
[[spring-cloud-eureka-server-prefer-ip-address]]
|
||||
=== When to Prefer IP Address
|
||||
|
||||
In some cases, it is preferable for Eureka to advertise the IP addresses of services rather than the hostname.
|
||||
Set `eureka.instance.preferIpAddress` to `true` and, when the application registers with eureka, it uses its IP address rather than its hostname.
|
||||
|
||||
[TIP]
|
||||
====
|
||||
If the hostname cannot be determined by Java, then the IP address is sent to Eureka.
|
||||
Only explict way of setting the hostname is by setting `eureka.instance.hostname` property.
|
||||
You can set your hostname at the run-time by using an environment variable -- for example, `eureka.instance.hostname=$\{HOST_NAME}`.
|
||||
====
|
||||
|
||||
=== Securing The Eureka Server
|
||||
|
||||
You can secure your Eureka server simply by adding Spring Security to your
|
||||
server's classpath via `spring-boot-starter-security`. By default, when Spring Security is on the classpath it will require that
|
||||
a valid CSRF token be sent with every request to the app. Eureka clients will not generally possess a valid
|
||||
cross site request forgery (CSRF) token you will need to disable this requirement for the `/eureka/**` endpoints.
|
||||
For example:
|
||||
|
||||
[source,java,indent=0]
|
||||
----
|
||||
@Bean
|
||||
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
|
||||
http.authorizeHttpRequests((authz) -> authz
|
||||
.anyRequest().authenticated())
|
||||
.httpBasic(withDefaults());
|
||||
http.csrf().ignoringRequestMatchers("/eureka/**");
|
||||
return http.build();
|
||||
}
|
||||
----
|
||||
|
||||
For more information on CSRF see the https://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#csrf[Spring Security documentation].
|
||||
|
||||
A demo Eureka Server can be found in the Spring Cloud Samples https://github.com/spring-cloud-samples/eureka/tree/Eureka-With-Security-4.x[repo].
|
||||
|
||||
=== JDK 11 Support
|
||||
|
||||
The JAXB modules which the Eureka server depends upon were removed in JDK 11. If you intend to use JDK 11
|
||||
when running a Eureka server you must include these dependencies in your POM or Gradle file.
|
||||
|
||||
[source,xml,indent=0]
|
||||
----
|
||||
<dependency>
|
||||
<groupId>org.glassfish.jaxb</groupId>
|
||||
<artifactId>jaxb-runtime</artifactId>
|
||||
</dependency>
|
||||
----
|
||||
|
||||
=== AOT and Native Image Support
|
||||
|
||||
Spring Cloud Netflix Eureka Server does not support Spring AOT transformations or native images.
|
||||
|
||||
=== Metrics
|
||||
|
||||
`EurekaInstanceMonitor` listens to events related to Eureka instance registration and creates/updates `Gauge`s for Eureka instance information in Micrometer's `MeterRegistry`. By default, this behavior is disabled. If you want to enable it, you need to set `eureka.server.metrics.enabled` to `true`.
|
||||
|
||||
By default, the `Gauge`s are named `eureka.server.instances` and have the following tags:
|
||||
|
||||
- `application`: application name
|
||||
- `status`: instance status (`UP`, `DOWN`, `STARTING`, `OUT_OF_SERVICE`, `UNKNOWN`, see: `com.netflix.appinfo.InstanceInfo.InstanceStatus`)
|
||||
|
||||
You can add additional tags by injecting your own implementation of `EurekaInstanceTagsProvider`.
|
||||
To see the list of all Spring Cloud Netflix related configuration properties please check link:appendix.html[the Appendix page].
|
||||
|
||||
== Configuration properties
|
||||
|
||||
To see the list of all Spring Cloud Netflix related configuration properties please check link:appendix.html[the Appendix page].
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -46,16 +46,12 @@
|
||||
|eureka.client.register-with-eureka | `+++true+++` | Indicates whether or not this instance should register its information with eureka server for discovery by others. In some cases, you do not want your instances to be discovered whereas you just want do discover other instances.
|
||||
|eureka.client.registry-fetch-interval-seconds | `+++30+++` | Indicates how often(in seconds) to fetch the registry information from the eureka server.
|
||||
|eureka.client.registry-refresh-single-vip-address | | Indicates whether the client is only interested in the registry information for a single VIP.
|
||||
|eureka.client.rest-template-timeout.connect-request-timeout | `+++180000+++` |
|
||||
|eureka.client.rest-template-timeout.connect-timeout | `+++180000+++` | Default values are set to 180000, in keeping with {@link RequestConfig} and {@link SocketConfig} defaults.
|
||||
|eureka.client.rest-template-timeout.socket-timeout | `+++180000+++` |
|
||||
|eureka.client.restclient.enabled | `+++false+++` | Enables the use of RestClient for Eureka HTTP Client.
|
||||
|eureka.client.restclient.timeout.connect-request-timeout | `+++180000+++` |
|
||||
|eureka.client.restclient.timeout.connect-timeout | `+++180000+++` | Default values are set to 180000, in keeping with {@link RequestConfig} and {@link SocketConfig} defaults.
|
||||
|eureka.client.restclient.timeout.socket-timeout | `+++180000+++` |
|
||||
|eureka.client.service-url | | Map of availability zone to list of fully qualified URLs to communicate with eureka server. Each value can be a single URL or a comma separated list of alternative locations. Typically the eureka server URLs carry protocol,host,port,context and version information if any. Example: https://ec2-256-156-243-129.compute-1.amazonaws.com:7001/eureka/ The changes are effective at runtime at the next service url refresh cycle as specified by eurekaServiceUrlPollIntervalSeconds.
|
||||
|eureka.client.should-enforce-registration-at-init | `+++false+++` | Indicates whether the client should enforce registration during initialization. Defaults to false.
|
||||
|eureka.client.should-unregister-on-shutdown | `+++true+++` | Indicates whether the client should explicitly unregister itself from the remote server on client shutdown.
|
||||
|eureka.client.timeout.connect-request-timeout | `+++180000+++` |
|
||||
|eureka.client.timeout.connect-timeout | `+++180000+++` | Default values are set to 180000, in keeping with {@link RequestConfig} and {@link SocketConfig} defaults.
|
||||
|eureka.client.timeout.socket-timeout | `+++180000+++` |
|
||||
|eureka.client.tls.enabled | |
|
||||
|eureka.client.tls.key-password | |
|
||||
|eureka.client.tls.key-store | |
|
||||
@@ -78,15 +74,15 @@
|
||||
|eureka.instance.default-address-resolution-order | `+++[]+++` |
|
||||
|eureka.instance.environment | |
|
||||
|eureka.instance.health-check-url | | Gets the absolute health check page URL for this instance. The users can provide the healthCheckUrlPath if the health check page resides in the same instance talking to eureka, else in the cases where the instance is a proxy for some other server, users can provide the full URL. If the full URL is provided it takes precedence. <p> It is normally used for making educated decisions based on the health of the instance - for example, it can be used to determine whether to proceed deployments to an entire farm or stop the deployments without causing further damage. The full URL should follow the format http://${eureka.hostname}:7001/ where the value ${eureka.hostname} is replaced at runtime.
|
||||
|eureka.instance.health-check-url-path | | Gets the relative health check URL path for this instance. The health check page URL is then constructed out of the hostname and the type of communication - secure or unsecure as specified in securePort and nonSecurePort. It is normally used for making educated decisions based on the health of the instance - for example, it can be used to determine whether to proceed deployments to an entire farm or stop the deployments without causing further damage.
|
||||
|eureka.instance.health-check-url-path | | Gets the relative health check URL path for this instance. The health check page URL is then constructed out of the hostname and the type of communication - secure or insecure as specified in securePort and nonSecurePort. It is normally used for making educated decisions based on the health of the instance - for example, it can be used to determine whether to proceed deployments to an entire farm or stop the deployments without causing further damage.
|
||||
|eureka.instance.home-page-url | | Gets the absolute home page URL for this instance. The users can provide the homePageUrlPath if the home page resides in the same instance talking to eureka, else in the cases where the instance is a proxy for some other server, users can provide the full URL. If the full URL is provided it takes precedence. It is normally used for informational purposes for other services to use it as a landing page. The full URL should follow the format http://${eureka.hostname}:7001/ where the value ${eureka.hostname} is replaced at runtime.
|
||||
|eureka.instance.home-page-url-path | `+++/+++` | Gets the relative home page URL Path for this instance. The home page URL is then constructed out of the hostName and the type of communication - secure or unsecure. It is normally used for informational purposes for other services to use it as a landing page.
|
||||
|eureka.instance.home-page-url-path | `+++/+++` | Gets the relative home page URL Path for this instance. The home page URL is then constructed out of the hostName and the type of communication - secure or insecure. It is normally used for informational purposes for other services to use it as a landing page.
|
||||
|eureka.instance.hostname | | The hostname if it can be determined at configuration time (otherwise it will be guessed from OS primitives).
|
||||
|eureka.instance.initial-status | `+++up+++` | Initial status to register with remote Eureka server.
|
||||
|eureka.instance.instance-enabled-onit | `+++false+++` | Indicates whether the instance should be enabled for taking traffic as soon as it is registered with eureka. Sometimes the application might need to do some pre-processing before it is ready to take traffic.
|
||||
|eureka.instance.instance-id | | Get the unique Id (within the scope of the appName) of this instance to be registered with eureka.
|
||||
|eureka.instance.ip-address | | Get the IPAdress of the instance. This information is for academic purposes only as the communication from other instances primarily happen using the information supplied in {@link #getHostName(boolean)}.
|
||||
|eureka.instance.lease-expiration-duration-in-seconds | `+++90+++` | Indicates the time in seconds that the eureka server waits since it received the last heartbeat before it can remove this instance from its view and there by disallowing traffic to this instance. Setting this value too long could mean that the traffic could be routed to the instance even though the instance is not alive. Setting this value too small could mean, the instance may be taken out of traffic because of temporary network glitches.This value to be set to atleast higher than the value specified in leaseRenewalIntervalInSeconds.
|
||||
|eureka.instance.lease-expiration-duration-in-seconds | `+++90+++` | Indicates the time in seconds that the eureka server waits since it received the last heartbeat before it can remove this instance from its view and there by disallowing traffic to this instance. Setting this value too long could mean that the traffic could be routed to the instance even though the instance is not alive. Setting this value too small could mean, the instance may be taken out of traffic because of temporary network glitches.This value to be set to at least higher than the value specified in leaseRenewalIntervalInSeconds.
|
||||
|eureka.instance.lease-renewal-interval-in-seconds | `+++30+++` | Indicates how often (in seconds) the eureka client needs to send heartbeats to eureka server to indicate that it is still alive. If the heartbeats are not received for the period specified in leaseExpirationDurationInSeconds, eureka server will remove the instance from its view, there by disallowing traffic to this instance. Note that the instance could still not take traffic if it implements HealthCheckCallback and then decides to make itself unavailable.
|
||||
|eureka.instance.metadata-map | | Gets the metadata name/value pairs associated with this instance. This information is sent to eureka server and can be used by other instances.
|
||||
|eureka.instance.metadata-map.weight | `+++1+++` | The weight of service instance for weighted load balancing.
|
||||
@@ -101,7 +97,7 @@
|
||||
|eureka.instance.secure-port-enabled | `+++false+++` | Indicates whether the secure port should be enabled for traffic or not.
|
||||
|eureka.instance.secure-virtual-host-name | `+++unknown+++` | Gets the secure virtual host name defined for this instance. This is typically the way other instance would find this instance by using the secure virtual host name.Think of this as similar to the fully qualified domain name, that the users of your services will need to find this instance.
|
||||
|eureka.instance.status-page-url | | Gets the absolute status page URL path for this instance. The users can provide the statusPageUrlPath if the status page resides in the same instance talking to eureka, else in the cases where the instance is a proxy for some other server, users can provide the full URL. If the full URL is provided it takes precedence. It is normally used for informational purposes for other services to find about the status of this instance. Users can provide a simple HTML indicating what is the current status of the instance.
|
||||
|eureka.instance.status-page-url-path | | Gets the relative status page URL path for this instance. The status page URL is then constructed out of the hostName and the type of communication - secure or unsecure as specified in securePort and nonSecurePort. It is normally used for informational purposes for other services to find about the status of this instance. Users can provide a simple HTML indicating what is the current status of the instance.
|
||||
|eureka.instance.status-page-url-path | | Gets the relative status page URL path for this instance. The status page URL is then constructed out of the hostName and the type of communication - secure or insecure as specified in securePort and nonSecurePort. It is normally used for informational purposes for other services to find about the status of this instance. Users can provide a simple HTML indicating what is the current status of the instance.
|
||||
|eureka.instance.virtual-host-name | `+++unknown+++` | Gets the virtual host name defined for this instance. This is typically the way other instance would find this instance by using the virtual host name.Think of this as similar to the fully qualified domain name, that the users of your services will need to find this instance.
|
||||
|eureka.server.a-s-g-cache-expiry-timeout-ms | `+++600000+++` |
|
||||
|eureka.server.a-s-g-query-timeout-ms | `+++300+++` |
|
||||
@@ -180,7 +176,7 @@
|
||||
|eureka.server.use-read-only-response-cache | `+++true+++` |
|
||||
|eureka.server.wait-time-in-ms-when-sync-empty | `+++300000+++` |
|
||||
|eureka.server.xml-codec-name | |
|
||||
|spring.cloud.compatibility-verifier.compatible-boot-versions | `+++3.5.x+++` | Default accepted versions for the Spring Boot dependency. You can set {@code x} for the patch version if you don't want to specify a concrete value. Example: {@code 3.5.x}
|
||||
|spring.cloud.compatibility-verifier.compatible-boot-versions | | Default accepted versions for the Spring Boot dependency. You can set {@code x} for the patch version if you don't want to specify a concrete value. Example: {@code 3.5.x}
|
||||
|spring.cloud.compatibility-verifier.enabled | `+++false+++` | Enables creation of Spring Cloud compatibility verification.
|
||||
|spring.cloud.config.allow-override | `+++true+++` | Flag to indicate that {@link #isOverrideSystemProperties() systemPropertiesOverride} can be used. Set to false to prevent users from changing the default accidentally. Default true.
|
||||
|spring.cloud.config.initialize-on-context-refresh | `+++false+++` | Flag to initialize bootstrap configuration on context refresh event. Default false.
|
||||
@@ -212,6 +208,13 @@
|
||||
|spring.cloud.inetutils.preferred-networks | | List of Java regular expressions for network addresses that will be preferred.
|
||||
|spring.cloud.inetutils.timeout-seconds | `+++1+++` | Timeout, in seconds, for calculating hostname.
|
||||
|spring.cloud.inetutils.use-only-site-local-interfaces | `+++false+++` | Whether to use only interfaces with site local addresses. See {@link InetAddress#isSiteLocalAddress()} for more details.
|
||||
|spring.cloud.loadbalancer.api-version.default | | Sets default version that should be used for each request.
|
||||
|spring.cloud.loadbalancer.api-version.fallback-to-available-instances | `+++false+++` | Indicates whether all the available instances should be returned if no instances for the specified version are available.
|
||||
|spring.cloud.loadbalancer.api-version.header | | Uses the HTTP header with the given name to obtain the version.
|
||||
|spring.cloud.loadbalancer.api-version.media-type-parameters | | Uses the media type parameter with the given name to obtain the version.
|
||||
|spring.cloud.loadbalancer.api-version.path-segment | | Uses the path segment at the given index to obtain the version.
|
||||
|spring.cloud.loadbalancer.api-version.query-parameter | | Uses the query parameter with the given name to obtain the version.
|
||||
|spring.cloud.loadbalancer.api-version.required | `+++false+++` | Indicates whether the API version is required with each request.
|
||||
|spring.cloud.loadbalancer.cache.caffeine.spec | | The spec to use to create caches. See CaffeineSpec for more details on the spec format.
|
||||
|spring.cloud.loadbalancer.cache.capacity | `+++256+++` | Initial cache capacity expressed as int.
|
||||
|spring.cloud.loadbalancer.cache.enabled | `+++true+++` | Enables Spring Cloud LoadBalancer caching mechanism.
|
||||
@@ -257,6 +260,7 @@
|
||||
|spring.cloud.refresh.enabled | `+++true+++` | Enables autoconfiguration for the refresh scope and associated features.
|
||||
|spring.cloud.refresh.extra-refreshable | `+++true+++` | Additional bean names or class names for beans to post process into refresh scope.
|
||||
|spring.cloud.refresh.never-refreshable | `+++true+++` | Comma separated list of bean names or class names for beans to never be refreshed or rebound.
|
||||
|spring.cloud.refresh.never-reset-nested-types | | Fully qualified class name prefixes of nested configuration properties values that should never be recursively reset when a bean is rebound. JDK and standard API types are always skipped; use this to additionally exclude library types whose object graphs are cyclic or hold internal state that must not be mutated. Each entry is matched against the fully qualified class name using a prefix comparison, so either a package or an individual class name can be supplied.
|
||||
|spring.cloud.refresh.on-restart.enabled | `+++true+++` | Enable refreshing context on start.
|
||||
|spring.cloud.service-registry.auto-registration.enabled | `+++true+++` | Whether service auto-registration is enabled. Defaults to true.
|
||||
|spring.cloud.service-registry.auto-registration.fail-fast | `+++false+++` | Whether startup fails if there is no AutoServiceRegistration. Defaults to false.
|
||||
|
||||
+2
-2
@@ -1,10 +1,10 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"antora": "3.2.0-alpha.11",
|
||||
"antora": "3.2.0",
|
||||
"@antora/atlas-extension": "1.0.0-alpha.5",
|
||||
"@antora/collector-extension": "1.0.3",
|
||||
"@asciidoctor/tabs": "1.0.0-beta.6",
|
||||
"@springio/antora-extensions": "1.14.9",
|
||||
"@springio/antora-extensions": "1.14.13",
|
||||
"@springio/asciidoctor-extensions": "1.0.0-alpha.18"
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-netflix</artifactId>
|
||||
<version>4.3.2</version>
|
||||
<version>5.1.0-SNAPSHOT</version>
|
||||
<relativePath>..</relativePath>
|
||||
</parent>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# Apache Maven Wrapper startup batch script, version 3.2.0
|
||||
# Apache Maven Wrapper startup batch script, version 3.3.4
|
||||
#
|
||||
# Required ENV vars:
|
||||
# ------------------
|
||||
@@ -33,75 +33,84 @@
|
||||
# MAVEN_SKIP_RC - flag to disable loading of mavenrc files
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
if [ -z "$MAVEN_SKIP_RC" ] ; then
|
||||
if [ -z "$MAVEN_SKIP_RC" ]; then
|
||||
|
||||
if [ -f /usr/local/etc/mavenrc ] ; then
|
||||
if [ -f /usr/local/etc/mavenrc ]; then
|
||||
. /usr/local/etc/mavenrc
|
||||
fi
|
||||
|
||||
if [ -f /etc/mavenrc ] ; then
|
||||
if [ -f /etc/mavenrc ]; then
|
||||
. /etc/mavenrc
|
||||
fi
|
||||
|
||||
if [ -f "$HOME/.mavenrc" ] ; then
|
||||
if [ -f "$HOME/.mavenrc" ]; then
|
||||
. "$HOME/.mavenrc"
|
||||
fi
|
||||
|
||||
fi
|
||||
|
||||
# OS specific support. $var _must_ be set to either true or false.
|
||||
cygwin=false;
|
||||
darwin=false;
|
||||
cygwin=false
|
||||
darwin=false
|
||||
mingw=false
|
||||
case "$(uname)" in
|
||||
CYGWIN*) cygwin=true ;;
|
||||
MINGW*) mingw=true;;
|
||||
Darwin*) darwin=true
|
||||
# Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
|
||||
# See https://developer.apple.com/library/mac/qa/qa1170/_index.html
|
||||
if [ -z "$JAVA_HOME" ]; then
|
||||
if [ -x "/usr/libexec/java_home" ]; then
|
||||
JAVA_HOME="$(/usr/libexec/java_home)"; export JAVA_HOME
|
||||
else
|
||||
JAVA_HOME="/Library/Java/Home"; export JAVA_HOME
|
||||
fi
|
||||
CYGWIN*) cygwin=true ;;
|
||||
MINGW*) mingw=true ;;
|
||||
Darwin*)
|
||||
darwin=true
|
||||
# Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
|
||||
# See https://developer.apple.com/library/mac/qa/qa1170/_index.html
|
||||
if [ -z "$JAVA_HOME" ]; then
|
||||
if [ -x "/usr/libexec/java_home" ]; then
|
||||
JAVA_HOME="$(/usr/libexec/java_home)"
|
||||
export JAVA_HOME
|
||||
else
|
||||
JAVA_HOME="/Library/Java/Home"
|
||||
export JAVA_HOME
|
||||
fi
|
||||
;;
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ -z "$JAVA_HOME" ] ; then
|
||||
if [ -r /etc/gentoo-release ] ; then
|
||||
if [ -z "$JAVA_HOME" ]; then
|
||||
if [ -r /etc/gentoo-release ]; then
|
||||
JAVA_HOME=$(java-config --jre-home)
|
||||
fi
|
||||
fi
|
||||
|
||||
# For Cygwin, ensure paths are in UNIX format before anything is touched
|
||||
if $cygwin ; then
|
||||
[ -n "$JAVA_HOME" ] &&
|
||||
JAVA_HOME=$(cygpath --unix "$JAVA_HOME")
|
||||
[ -n "$CLASSPATH" ] &&
|
||||
CLASSPATH=$(cygpath --path --unix "$CLASSPATH")
|
||||
if $cygwin; then
|
||||
[ -n "$JAVA_HOME" ] \
|
||||
&& JAVA_HOME=$(cygpath --unix "$JAVA_HOME")
|
||||
[ -n "$CLASSPATH" ] \
|
||||
&& CLASSPATH=$(cygpath --path --unix "$CLASSPATH")
|
||||
fi
|
||||
|
||||
# For Mingw, ensure paths are in UNIX format before anything is touched
|
||||
if $mingw ; then
|
||||
[ -n "$JAVA_HOME" ] && [ -d "$JAVA_HOME" ] &&
|
||||
JAVA_HOME="$(cd "$JAVA_HOME" || (echo "cannot cd into $JAVA_HOME."; exit 1); pwd)"
|
||||
if $mingw; then
|
||||
[ -n "$JAVA_HOME" ] && [ -d "$JAVA_HOME" ] \
|
||||
&& JAVA_HOME="$(
|
||||
cd "$JAVA_HOME" || (
|
||||
echo "cannot cd into $JAVA_HOME." >&2
|
||||
exit 1
|
||||
)
|
||||
pwd
|
||||
)"
|
||||
fi
|
||||
|
||||
if [ -z "$JAVA_HOME" ]; then
|
||||
javaExecutable="$(which javac)"
|
||||
if [ -n "$javaExecutable" ] && ! [ "$(expr "\"$javaExecutable\"" : '\([^ ]*\)')" = "no" ]; then
|
||||
if [ -n "$javaExecutable" ] && ! [ "$(expr "$javaExecutable" : '\([^ ]*\)')" = "no" ]; then
|
||||
# readlink(1) is not available as standard on Solaris 10.
|
||||
readLink=$(which readlink)
|
||||
if [ ! "$(expr "$readLink" : '\([^ ]*\)')" = "no" ]; then
|
||||
if $darwin ; then
|
||||
javaHome="$(dirname "\"$javaExecutable\"")"
|
||||
javaExecutable="$(cd "\"$javaHome\"" && pwd -P)/javac"
|
||||
if $darwin; then
|
||||
javaHome="$(dirname "$javaExecutable")"
|
||||
javaExecutable="$(cd "$javaHome" && pwd -P)/javac"
|
||||
else
|
||||
javaExecutable="$(readlink -f "\"$javaExecutable\"")"
|
||||
javaExecutable="$(readlink -f "$javaExecutable")"
|
||||
fi
|
||||
javaHome="$(dirname "\"$javaExecutable\"")"
|
||||
javaHome="$(dirname "$javaExecutable")"
|
||||
javaHome=$(expr "$javaHome" : '\(.*\)/bin')
|
||||
JAVA_HOME="$javaHome"
|
||||
export JAVA_HOME
|
||||
@@ -109,52 +118,60 @@ if [ -z "$JAVA_HOME" ]; then
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -z "$JAVACMD" ] ; then
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
if [ -z "$JAVACMD" ]; then
|
||||
if [ -n "$JAVA_HOME" ]; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ]; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
fi
|
||||
else
|
||||
JAVACMD="$(\unset -f command 2>/dev/null; \command -v java)"
|
||||
JAVACMD="$(
|
||||
\unset -f command 2>/dev/null
|
||||
\command -v java
|
||||
)"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
if [ ! -x "$JAVACMD" ]; then
|
||||
echo "Error: JAVA_HOME is not defined correctly." >&2
|
||||
echo " We cannot execute $JAVACMD" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$JAVA_HOME" ] ; then
|
||||
echo "Warning: JAVA_HOME environment variable is not set."
|
||||
if [ -z "$JAVA_HOME" ]; then
|
||||
echo "Warning: JAVA_HOME environment variable is not set." >&2
|
||||
fi
|
||||
|
||||
# traverses directory structure from process work directory to filesystem root
|
||||
# first directory with .mvn subdirectory is considered project base directory
|
||||
find_maven_basedir() {
|
||||
if [ -z "$1" ]
|
||||
then
|
||||
echo "Path not specified to find_maven_basedir"
|
||||
if [ -z "$1" ]; then
|
||||
echo "Path not specified to find_maven_basedir" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
basedir="$1"
|
||||
wdir="$1"
|
||||
while [ "$wdir" != '/' ] ; do
|
||||
if [ -d "$wdir"/.mvn ] ; then
|
||||
while [ "$wdir" != '/' ]; do
|
||||
if [ -d "$wdir"/.mvn ]; then
|
||||
basedir=$wdir
|
||||
break
|
||||
fi
|
||||
# workaround for JBEAP-8937 (on Solaris 10/Sparc)
|
||||
if [ -d "${wdir}" ]; then
|
||||
wdir=$(cd "$wdir/.." || exit 1; pwd)
|
||||
wdir=$(
|
||||
cd "$wdir/.." || exit 1
|
||||
pwd
|
||||
)
|
||||
fi
|
||||
# end of workaround
|
||||
done
|
||||
printf '%s' "$(cd "$basedir" || exit 1; pwd)"
|
||||
printf '%s' "$(
|
||||
cd "$basedir" || exit 1
|
||||
pwd
|
||||
)"
|
||||
}
|
||||
|
||||
# concatenates all lines of a file
|
||||
@@ -165,7 +182,7 @@ concat_lines() {
|
||||
# enabled. Otherwise, we may read lines that are delimited with
|
||||
# \r\n and produce $'-Xarg\r' rather than -Xarg due to word
|
||||
# splitting rules.
|
||||
tr -s '\r\n' ' ' < "$1"
|
||||
tr -s '\r\n' ' ' <"$1"
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -177,75 +194,85 @@ log() {
|
||||
|
||||
BASE_DIR=$(find_maven_basedir "$(dirname "$0")")
|
||||
if [ -z "$BASE_DIR" ]; then
|
||||
exit 1;
|
||||
exit 1
|
||||
fi
|
||||
|
||||
MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}; export MAVEN_PROJECTBASEDIR
|
||||
MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}
|
||||
export MAVEN_PROJECTBASEDIR
|
||||
log "$MAVEN_PROJECTBASEDIR"
|
||||
|
||||
trim() {
|
||||
# MWRAPPER-139:
|
||||
# Trims trailing and leading whitespace, carriage returns, tabs, and linefeeds.
|
||||
# Needed for removing poorly interpreted newline sequences when running in more
|
||||
# exotic environments such as mingw bash on Windows.
|
||||
printf "%s" "${1}" | tr -d '[:space:]'
|
||||
}
|
||||
|
||||
##########################################################################################
|
||||
# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
|
||||
# This allows using the maven wrapper in projects that prohibit checking in binary data.
|
||||
##########################################################################################
|
||||
wrapperJarPath="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar"
|
||||
if [ -r "$wrapperJarPath" ]; then
|
||||
log "Found $wrapperJarPath"
|
||||
log "Found $wrapperJarPath"
|
||||
else
|
||||
log "Couldn't find $wrapperJarPath, downloading it ..."
|
||||
log "Couldn't find $wrapperJarPath, downloading it ..."
|
||||
|
||||
if [ -n "$MVNW_REPOURL" ]; then
|
||||
wrapperUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar"
|
||||
if [ -n "$MVNW_REPOURL" ]; then
|
||||
wrapperUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.3.4/maven-wrapper-3.3.4.jar"
|
||||
else
|
||||
wrapperUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.3.4/maven-wrapper-3.3.4.jar"
|
||||
fi
|
||||
while IFS="=" read -r key value; do
|
||||
case "$key" in wrapperUrl)
|
||||
wrapperUrl=$(trim "${value-}")
|
||||
break
|
||||
;;
|
||||
esac
|
||||
done <"$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties"
|
||||
log "Downloading from: $wrapperUrl"
|
||||
|
||||
if $cygwin; then
|
||||
wrapperJarPath=$(cygpath --path --windows "$wrapperJarPath")
|
||||
fi
|
||||
|
||||
if command -v wget >/dev/null; then
|
||||
log "Found wget ... using wget"
|
||||
[ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--quiet"
|
||||
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
|
||||
wget ${QUIET:+"$QUIET"} "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath"
|
||||
else
|
||||
wrapperUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar"
|
||||
wget ${QUIET:+"$QUIET"} --http-user="$MVNW_USERNAME" --http-password="$MVNW_PASSWORD" "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath"
|
||||
fi
|
||||
while IFS="=" read -r key value; do
|
||||
# Remove '\r' from value to allow usage on windows as IFS does not consider '\r' as a separator ( considers space, tab, new line ('\n'), and custom '=' )
|
||||
safeValue=$(echo "$value" | tr -d '\r')
|
||||
case "$key" in (wrapperUrl) wrapperUrl="$safeValue"; break ;;
|
||||
esac
|
||||
done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties"
|
||||
log "Downloading from: $wrapperUrl"
|
||||
|
||||
elif command -v curl >/dev/null; then
|
||||
log "Found curl ... using curl"
|
||||
[ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--silent"
|
||||
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
|
||||
curl ${QUIET:+"$QUIET"} -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath"
|
||||
else
|
||||
curl ${QUIET:+"$QUIET"} --user "$MVNW_USERNAME:$MVNW_PASSWORD" -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath"
|
||||
fi
|
||||
else
|
||||
log "Falling back to using Java to download"
|
||||
javaSource="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.java"
|
||||
javaClass="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.class"
|
||||
# For Cygwin, switch paths to Windows format before running javac
|
||||
if $cygwin; then
|
||||
wrapperJarPath=$(cygpath --path --windows "$wrapperJarPath")
|
||||
javaSource=$(cygpath --path --windows "$javaSource")
|
||||
javaClass=$(cygpath --path --windows "$javaClass")
|
||||
fi
|
||||
|
||||
if command -v wget > /dev/null; then
|
||||
log "Found wget ... using wget"
|
||||
[ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--quiet"
|
||||
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
|
||||
wget $QUIET "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath"
|
||||
else
|
||||
wget $QUIET --http-user="$MVNW_USERNAME" --http-password="$MVNW_PASSWORD" "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath"
|
||||
fi
|
||||
elif command -v curl > /dev/null; then
|
||||
log "Found curl ... using curl"
|
||||
[ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--silent"
|
||||
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
|
||||
curl $QUIET -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath"
|
||||
else
|
||||
curl $QUIET --user "$MVNW_USERNAME:$MVNW_PASSWORD" -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath"
|
||||
fi
|
||||
else
|
||||
log "Falling back to using Java to download"
|
||||
javaSource="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.java"
|
||||
javaClass="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.class"
|
||||
# For Cygwin, switch paths to Windows format before running javac
|
||||
if $cygwin; then
|
||||
javaSource=$(cygpath --path --windows "$javaSource")
|
||||
javaClass=$(cygpath --path --windows "$javaClass")
|
||||
fi
|
||||
if [ -e "$javaSource" ]; then
|
||||
if [ ! -e "$javaClass" ]; then
|
||||
log " - Compiling MavenWrapperDownloader.java ..."
|
||||
("$JAVA_HOME/bin/javac" "$javaSource")
|
||||
fi
|
||||
if [ -e "$javaClass" ]; then
|
||||
log " - Running MavenWrapperDownloader.java ..."
|
||||
("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$wrapperUrl" "$wrapperJarPath") || rm -f "$wrapperJarPath"
|
||||
fi
|
||||
fi
|
||||
if [ -e "$javaSource" ]; then
|
||||
if [ ! -e "$javaClass" ]; then
|
||||
log " - Compiling MavenWrapperDownloader.java ..."
|
||||
("$JAVA_HOME/bin/javac" "$javaSource")
|
||||
fi
|
||||
if [ -e "$javaClass" ]; then
|
||||
log " - Running MavenWrapperDownloader.java ..."
|
||||
("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$wrapperUrl" "$wrapperJarPath") || rm -f "$wrapperJarPath"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
##########################################################################################
|
||||
# End of extension
|
||||
@@ -254,22 +281,25 @@ fi
|
||||
# If specified, validate the SHA-256 sum of the Maven wrapper jar file
|
||||
wrapperSha256Sum=""
|
||||
while IFS="=" read -r key value; do
|
||||
case "$key" in (wrapperSha256Sum) wrapperSha256Sum=$value; break ;;
|
||||
case "$key" in wrapperSha256Sum)
|
||||
wrapperSha256Sum=$(trim "${value-}")
|
||||
break
|
||||
;;
|
||||
esac
|
||||
done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties"
|
||||
done <"$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties"
|
||||
if [ -n "$wrapperSha256Sum" ]; then
|
||||
wrapperSha256Result=false
|
||||
if command -v sha256sum > /dev/null; then
|
||||
if echo "$wrapperSha256Sum $wrapperJarPath" | sha256sum -c > /dev/null 2>&1; then
|
||||
if command -v sha256sum >/dev/null; then
|
||||
if echo "$wrapperSha256Sum $wrapperJarPath" | sha256sum -c - >/dev/null 2>&1; then
|
||||
wrapperSha256Result=true
|
||||
fi
|
||||
elif command -v shasum > /dev/null; then
|
||||
if echo "$wrapperSha256Sum $wrapperJarPath" | shasum -a 256 -c > /dev/null 2>&1; then
|
||||
elif command -v shasum >/dev/null; then
|
||||
if echo "$wrapperSha256Sum $wrapperJarPath" | shasum -a 256 -c >/dev/null 2>&1; then
|
||||
wrapperSha256Result=true
|
||||
fi
|
||||
else
|
||||
echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available."
|
||||
echo "Please install either command, or disable validation by removing 'wrapperSha256Sum' from your maven-wrapper.properties."
|
||||
echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." >&2
|
||||
echo "Please install either command, or disable validation by removing 'wrapperSha256Sum' from your maven-wrapper.properties." >&2
|
||||
exit 1
|
||||
fi
|
||||
if [ $wrapperSha256Result = false ]; then
|
||||
@@ -284,12 +314,12 @@ MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
|
||||
|
||||
# For Cygwin, switch paths to Windows format before running java
|
||||
if $cygwin; then
|
||||
[ -n "$JAVA_HOME" ] &&
|
||||
JAVA_HOME=$(cygpath --path --windows "$JAVA_HOME")
|
||||
[ -n "$CLASSPATH" ] &&
|
||||
CLASSPATH=$(cygpath --path --windows "$CLASSPATH")
|
||||
[ -n "$MAVEN_PROJECTBASEDIR" ] &&
|
||||
MAVEN_PROJECTBASEDIR=$(cygpath --path --windows "$MAVEN_PROJECTBASEDIR")
|
||||
[ -n "$JAVA_HOME" ] \
|
||||
&& JAVA_HOME=$(cygpath --path --windows "$JAVA_HOME")
|
||||
[ -n "$CLASSPATH" ] \
|
||||
&& CLASSPATH=$(cygpath --path --windows "$CLASSPATH")
|
||||
[ -n "$MAVEN_PROJECTBASEDIR" ] \
|
||||
&& MAVEN_PROJECTBASEDIR=$(cygpath --path --windows "$MAVEN_PROJECTBASEDIR")
|
||||
fi
|
||||
|
||||
# Provide a "standardized" way to retrieve the CLI args that will
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
@REM ----------------------------------------------------------------------------
|
||||
|
||||
@REM ----------------------------------------------------------------------------
|
||||
@REM Apache Maven Wrapper startup batch script, version 3.2.0
|
||||
@REM Apache Maven Wrapper startup batch script, version 3.3.4
|
||||
@REM
|
||||
@REM Required ENV vars:
|
||||
@REM JAVA_HOME - location of a JDK home dir
|
||||
@@ -59,22 +59,22 @@ set ERROR_CODE=0
|
||||
@REM ==== START VALIDATION ====
|
||||
if not "%JAVA_HOME%" == "" goto OkJHome
|
||||
|
||||
echo.
|
||||
echo. >&2
|
||||
echo Error: JAVA_HOME not found in your environment. >&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the >&2
|
||||
echo location of your Java installation. >&2
|
||||
echo.
|
||||
echo. >&2
|
||||
goto error
|
||||
|
||||
:OkJHome
|
||||
if exist "%JAVA_HOME%\bin\java.exe" goto init
|
||||
|
||||
echo.
|
||||
echo. >&2
|
||||
echo Error: JAVA_HOME is set to an invalid directory. >&2
|
||||
echo JAVA_HOME = "%JAVA_HOME%" >&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the >&2
|
||||
echo location of your Java installation. >&2
|
||||
echo.
|
||||
echo. >&2
|
||||
goto error
|
||||
|
||||
@REM ==== END VALIDATION ====
|
||||
@@ -119,7 +119,7 @@ SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
|
||||
set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
|
||||
set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
|
||||
|
||||
set WRAPPER_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar"
|
||||
set WRAPPER_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.3.4/maven-wrapper-3.3.4.jar"
|
||||
|
||||
FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
|
||||
IF "%%A"=="wrapperUrl" SET WRAPPER_URL=%%B
|
||||
@@ -133,7 +133,7 @@ if exist %WRAPPER_JAR% (
|
||||
)
|
||||
) else (
|
||||
if not "%MVNW_REPOURL%" == "" (
|
||||
SET WRAPPER_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar"
|
||||
SET WRAPPER_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.3.4/maven-wrapper-3.3.4.jar"
|
||||
)
|
||||
if "%MVNW_VERBOSE%" == "true" (
|
||||
echo Couldn't find %WRAPPER_JAR%, downloading it ...
|
||||
@@ -160,11 +160,12 @@ FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapp
|
||||
)
|
||||
IF NOT %WRAPPER_SHA_256_SUM%=="" (
|
||||
powershell -Command "&{"^
|
||||
"Import-Module $PSHOME\Modules\Microsoft.PowerShell.Utility -Function Get-FileHash;"^
|
||||
"$hash = (Get-FileHash \"%WRAPPER_JAR%\" -Algorithm SHA256).Hash.ToLower();"^
|
||||
"If('%WRAPPER_SHA_256_SUM%' -ne $hash){"^
|
||||
" Write-Output 'Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised.';"^
|
||||
" Write-Output 'Investigate or delete %WRAPPER_JAR% to attempt a clean download.';"^
|
||||
" Write-Output 'If you updated your Maven version, you need to update the specified wrapperSha256Sum property.';"^
|
||||
" Write-Error 'Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised.';"^
|
||||
" Write-Error 'Investigate or delete %WRAPPER_JAR% to attempt a clean download.';"^
|
||||
" Write-Error 'If you updated your Maven version, you need to update the specified wrapperSha256Sum property.';"^
|
||||
" exit 1;"^
|
||||
"}"^
|
||||
"}"
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
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>
|
||||
<artifactId>spring-cloud-netflix</artifactId>
|
||||
<version>4.3.2</version>
|
||||
<version>5.1.0-SNAPSHOT</version>
|
||||
<packaging>pom</packaging>
|
||||
<name>Spring Cloud Netflix</name>
|
||||
<description>Spring Cloud Netflix</description>
|
||||
@@ -11,7 +11,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-build</artifactId>
|
||||
<version>4.3.3</version>
|
||||
<version>5.1.0-SNAPSHOT</version>
|
||||
<relativePath />
|
||||
</parent>
|
||||
<scm>
|
||||
@@ -80,8 +80,8 @@
|
||||
</developers>
|
||||
<properties>
|
||||
<bintray.package>netflix</bintray.package>
|
||||
<spring-cloud-commons.version>4.3.2</spring-cloud-commons.version>
|
||||
<spring-cloud-config.version>4.3.2</spring-cloud-config.version>
|
||||
<spring-cloud-commons.version>5.1.0-SNAPSHOT</spring-cloud-commons.version>
|
||||
<spring-cloud-config.version>5.1.0-SNAPSHOT</spring-cloud-config.version>
|
||||
<testcontainers.version>1.21.4</testcontainers.version>
|
||||
<mockserverclient.version>5.15.0</mockserverclient.version>
|
||||
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd">
|
||||
|
||||
<servers>
|
||||
<server>
|
||||
<id>release-train</id>
|
||||
<username>${env.RELEASE_TRAIN_MAVEN_REPOSITORY_USERNAME}</username>
|
||||
<password>${env.RELEASE_TRAIN_MAVEN_REPOSITORY_PASSWORD}</password>
|
||||
</server>
|
||||
<server>
|
||||
<id>spring-commercial-snapshot</id>
|
||||
<username>${env.COMMERCIAL_REPO_USERNAME}</username>
|
||||
<password>${env.COMMERCIAL_REPO_PASSWORD}</password>
|
||||
</server>
|
||||
<server>
|
||||
<id>spring-commercial-release</id>
|
||||
<username>${env.COMMERCIAL_REPO_USERNAME}</username>
|
||||
<password>${env.COMMERCIAL_REPO_PASSWORD}</password>
|
||||
</server>
|
||||
<server>
|
||||
<id>repo-spring-io-spring-commercial-snapshot</id>
|
||||
<username>${env.COMMERCIAL_REPO_USERNAME}</username>
|
||||
<password>${env.COMMERCIAL_REPO_PASSWORD}</password>
|
||||
</server>
|
||||
<server>
|
||||
<id>repo-spring-io-spring-commercial-release</id>
|
||||
<username>${env.COMMERCIAL_REPO_USERNAME}</username>
|
||||
<password>${env.COMMERCIAL_REPO_PASSWORD}</password>
|
||||
</server>
|
||||
</servers>
|
||||
|
||||
<mirrors>
|
||||
<mirror>
|
||||
<!-- This redirects the spring-snapshots repo to the release-train repo -->
|
||||
<id>release-train</id>
|
||||
<mirrorOf>spring-snapshots</mirrorOf>
|
||||
<url>${env.RELEASE_TRAIN_MAVEN_REPOSITORY_URL}</url>
|
||||
</mirror>
|
||||
</mirrors>
|
||||
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>releaseTrain</id>
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>release-train</id>
|
||||
<url>${env.RELEASE_TRAIN_MAVEN_REPOSITORY_URL}</url>
|
||||
<releases>
|
||||
<enabled>true</enabled>
|
||||
</releases>
|
||||
<snapshots>
|
||||
<enabled>true</enabled>
|
||||
<updatePolicy>always</updatePolicy>
|
||||
</snapshots>
|
||||
</repository>
|
||||
</repositories>
|
||||
<pluginRepositories>
|
||||
<pluginRepository>
|
||||
<id>release-train</id>
|
||||
<url>${env.RELEASE_TRAIN_MAVEN_REPOSITORY_URL}</url>
|
||||
<releases>
|
||||
<enabled>true</enabled>
|
||||
</releases>
|
||||
<snapshots>
|
||||
<enabled>true</enabled>
|
||||
<updatePolicy>always</updatePolicy>
|
||||
</snapshots>
|
||||
</pluginRepository>
|
||||
</pluginRepositories>
|
||||
</profile>
|
||||
</profiles>
|
||||
</settings>
|
||||
@@ -5,11 +5,11 @@
|
||||
<parent>
|
||||
<artifactId>spring-cloud-dependencies-parent</artifactId>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<version>4.3.3</version>
|
||||
<version>5.1.0-SNAPSHOT</version>
|
||||
<relativePath/>
|
||||
</parent>
|
||||
<artifactId>spring-cloud-netflix-dependencies</artifactId>
|
||||
<version>4.3.2</version>
|
||||
<version>5.1.0-SNAPSHOT</version>
|
||||
<packaging>pom</packaging>
|
||||
<name>spring-cloud-netflix-dependencies</name>
|
||||
<description>Spring Cloud Netflix Dependencies</description>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-netflix</artifactId>
|
||||
<version>4.3.2</version>
|
||||
<version>5.1.0-SNAPSHOT</version>
|
||||
<relativePath>..</relativePath> <!-- lookup parent from repository -->
|
||||
</parent>
|
||||
<artifactId>spring-cloud-netflix-eureka-client-tls-tests</artifactId>
|
||||
@@ -22,7 +22,6 @@
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-netflix-eureka-server</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot</artifactId>
|
||||
@@ -48,6 +47,10 @@
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-webflux</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-annotations</artifactId>
|
||||
@@ -70,7 +73,7 @@
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-aop</artifactId>
|
||||
<artifactId>spring-boot-starter-aspectj</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
@@ -102,11 +105,14 @@
|
||||
<artifactId>junit-platform-suite-engine</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.bouncycastle</groupId>
|
||||
<artifactId>bcpkix-jdk15on</artifactId>
|
||||
<version>1.70</version>
|
||||
<artifactId>bcpkix-jdk18on</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-restclient</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
+1
-1
@@ -26,7 +26,7 @@ import org.junit.platform.suite.api.Suite;
|
||||
* That means that when the new context starts we will fail cause the executor service is
|
||||
* already shutdown.
|
||||
*/
|
||||
@SelectClasses({ EurekaClientTests.class, RestTemplateEurekaClientTests.class })
|
||||
@SelectClasses({ EurekaClientTests.class, RestClientEurekaClientTests.class, WebClientEurekaClientTests.class })
|
||||
@Suite
|
||||
public class EurekaClientSuite {
|
||||
|
||||
|
||||
+11
-9
@@ -25,10 +25,11 @@ import org.junit.jupiter.api.BeforeAll;
|
||||
import org.springframework.boot.SpringBootConfiguration;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.cloud.netflix.eureka.http.DefaultEurekaClientHttpRequestFactorySupplier;
|
||||
import org.springframework.cloud.netflix.eureka.http.RestTemplateDiscoveryClientOptionalArgs;
|
||||
import org.springframework.cloud.netflix.eureka.http.RestTemplateTransportClientFactories;
|
||||
import org.springframework.cloud.netflix.eureka.http.RestClientDiscoveryClientOptionalArgs;
|
||||
import org.springframework.cloud.netflix.eureka.http.RestClientTransportClientFactories;
|
||||
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.web.client.RestClient;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@@ -44,7 +45,7 @@ public class EurekaClientTests extends BaseCertTests {
|
||||
public static void setupAll() {
|
||||
server = startEurekaServer(EurekaClientTests.TestEurekaServer.class);
|
||||
service = startService(server, EurekaClientTests.TestApp.class);
|
||||
assertThat(service.discoveryClientOptionalArgs()).isInstanceOf(RestTemplateDiscoveryClientOptionalArgs.class);
|
||||
assertThat(service.discoveryClientOptionalArgs()).isInstanceOf(RestClientDiscoveryClientOptionalArgs.class);
|
||||
LOG.info("Successfully asserted that Jersey will be used");
|
||||
waitForRegistration(() -> new EurekaClientTests().createEurekaClient());
|
||||
}
|
||||
@@ -59,15 +60,16 @@ public class EurekaClientTests extends BaseCertTests {
|
||||
public static class TestApp {
|
||||
|
||||
@Bean
|
||||
public RestTemplateTransportClientFactories forceRestTemplateTransportClientFactories(
|
||||
RestTemplateDiscoveryClientOptionalArgs discoveryClientOptionalArgs) {
|
||||
return new RestTemplateTransportClientFactories(discoveryClientOptionalArgs);
|
||||
public RestClientTransportClientFactories forceRestClientTransportClientFactories(
|
||||
RestClientDiscoveryClientOptionalArgs discoveryClientOptionalArgs) {
|
||||
return new RestClientTransportClientFactories(discoveryClientOptionalArgs);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public RestTemplateDiscoveryClientOptionalArgs discoveryClientOptionalArgs() {
|
||||
return new RestTemplateDiscoveryClientOptionalArgs(new DefaultEurekaClientHttpRequestFactorySupplier(
|
||||
new RestTemplateTimeoutProperties(), Collections.emptySet()));
|
||||
public RestClientDiscoveryClientOptionalArgs discoveryClientOptionalArgs() {
|
||||
return new RestClientDiscoveryClientOptionalArgs(
|
||||
new DefaultEurekaClientHttpRequestFactorySupplier(new TimeoutProperties(), Collections.emptySet()),
|
||||
RestClient::builder);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+8
@@ -18,6 +18,7 @@ package org.springframework.cloud.netflix.eureka;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.util.Collections;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
@@ -27,6 +28,7 @@ import org.junit.jupiter.api.BeforeAll;
|
||||
import org.springframework.boot.SpringBootConfiguration;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.cloud.configuration.TlsProperties;
|
||||
import org.springframework.cloud.netflix.eureka.http.DefaultEurekaClientHttpRequestFactorySupplier;
|
||||
import org.springframework.cloud.netflix.eureka.http.EurekaClientHttpRequestFactorySupplier;
|
||||
import org.springframework.cloud.netflix.eureka.http.RestClientDiscoveryClientOptionalArgs;
|
||||
import org.springframework.cloud.netflix.eureka.http.RestClientTransportClientFactories;
|
||||
@@ -94,6 +96,12 @@ public class RestClientEurekaClientTests extends BaseCertTests {
|
||||
return new RestClientTransportClientFactories(discoveryClientOptionalArgs);
|
||||
}
|
||||
|
||||
@Bean
|
||||
EurekaClientHttpRequestFactorySupplier defaultEurekaClientHttpRequestFactorySupplier(
|
||||
TimeoutProperties timeoutProperties) {
|
||||
return new DefaultEurekaClientHttpRequestFactorySupplier(timeoutProperties, Collections.emptySet());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@SpringBootConfiguration
|
||||
|
||||
+22
-29
@@ -26,21 +26,24 @@ import org.junit.jupiter.api.BeforeAll;
|
||||
|
||||
import org.springframework.boot.SpringBootConfiguration;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.web.client.RestTemplateBuilder;
|
||||
import org.springframework.cloud.configuration.TlsProperties;
|
||||
import org.springframework.cloud.netflix.eureka.http.DefaultEurekaClientHttpRequestFactorySupplier;
|
||||
import org.springframework.cloud.netflix.eureka.http.EurekaClientHttpRequestFactorySupplier;
|
||||
import org.springframework.cloud.netflix.eureka.http.RestTemplateDiscoveryClientOptionalArgs;
|
||||
import org.springframework.cloud.netflix.eureka.http.RestTemplateTransportClientFactories;
|
||||
import org.springframework.cloud.netflix.eureka.http.WebClientDiscoveryClientOptionalArgs;
|
||||
import org.springframework.cloud.netflix.eureka.http.WebClientTransportClientFactories;
|
||||
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.springframework.cloud.netflix.eureka.config.DiscoveryClientOptionalArgsConfiguration.setupTLS;
|
||||
|
||||
public class RestTemplateEurekaClientTests extends BaseCertTests {
|
||||
/**
|
||||
* Tests for verifying TLS setup with {@link WebClientTransportClientFactories}.
|
||||
*
|
||||
* @author Yash Chauhan
|
||||
*/
|
||||
public class WebClientEurekaClientTests extends BaseCertTests {
|
||||
|
||||
private static final Log log = LogFactory.getLog(RestTemplateEurekaClientTests.class);
|
||||
private static final Log LOG = LogFactory.getLog(WebClientEurekaClientTests.class);
|
||||
|
||||
private static EurekaServerRunner server;
|
||||
|
||||
@@ -49,11 +52,10 @@ public class RestTemplateEurekaClientTests extends BaseCertTests {
|
||||
@BeforeAll
|
||||
public static void setupAll() {
|
||||
server = startEurekaServer(TestEurekaServer.class);
|
||||
service = startService(server, RestTemplateEurekaClientTests.RestTemplateTestApp.class);
|
||||
// Will use RestTemplate
|
||||
assertThat(service.discoveryClientOptionalArgs()).isInstanceOf(RestTemplateDiscoveryClientOptionalArgs.class);
|
||||
log.info("Successfully asserted that RestTemplate will be used");
|
||||
waitForRegistration(() -> new RestTemplateEurekaClientTests().createEurekaClient());
|
||||
service = startService(server, TestApp.class);
|
||||
assertThat(service.discoveryClientOptionalArgs()).isInstanceOf(WebClientDiscoveryClientOptionalArgs.class);
|
||||
LOG.info("Successfully asserted that WebClient will be used");
|
||||
waitForRegistration(() -> new WebClientEurekaClientTests().createEurekaClient());
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
@@ -64,34 +66,25 @@ public class RestTemplateEurekaClientTests extends BaseCertTests {
|
||||
|
||||
@Override
|
||||
EurekaClientRunner createEurekaClient() {
|
||||
return new EurekaClientRunner(RestTemplateTestApp.class, server);
|
||||
return new EurekaClientRunner(TestApp.class, server);
|
||||
}
|
||||
|
||||
@SpringBootConfiguration
|
||||
@EnableAutoConfiguration
|
||||
public static class RestTemplateTestApp {
|
||||
public static class TestApp {
|
||||
|
||||
@Bean
|
||||
public RestTemplateDiscoveryClientOptionalArgs forceRestTemplateDiscoveryClientOptionalArgs(
|
||||
TlsProperties tlsProperties,
|
||||
EurekaClientHttpRequestFactorySupplier eurekaClientHttpRequestFactorySupplier)
|
||||
throws GeneralSecurityException, IOException {
|
||||
RestTemplateDiscoveryClientOptionalArgs result = new RestTemplateDiscoveryClientOptionalArgs(
|
||||
eurekaClientHttpRequestFactorySupplier, RestTemplateBuilder::new);
|
||||
public WebClientDiscoveryClientOptionalArgs forceWebClientDiscoveryClientOptionalArgs(
|
||||
TlsProperties tlsProperties) throws GeneralSecurityException, IOException {
|
||||
WebClientDiscoveryClientOptionalArgs result = new WebClientDiscoveryClientOptionalArgs(WebClient::builder);
|
||||
result.setHostnameVerifier((hostname, session) -> true);
|
||||
setupTLS(result, tlsProperties);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public RestTemplateTransportClientFactories forceRestTemplateTransportClientFactories(
|
||||
RestTemplateDiscoveryClientOptionalArgs discoveryClientOptionalArgs) {
|
||||
return new RestTemplateTransportClientFactories(discoveryClientOptionalArgs);
|
||||
}
|
||||
|
||||
@Bean
|
||||
EurekaClientHttpRequestFactorySupplier defaultEurekaClientHttpRequestFactorySupplier(
|
||||
RestTemplateTimeoutProperties restTemplateTimeoutProperties) {
|
||||
return new DefaultEurekaClientHttpRequestFactorySupplier(restTemplateTimeoutProperties);
|
||||
public WebClientTransportClientFactories forceWebClientTransportClientFactories() {
|
||||
return new WebClientTransportClientFactories(WebClient::builder);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-netflix</artifactId>
|
||||
<version>4.3.2</version>
|
||||
<version>5.1.0-SNAPSHOT</version>
|
||||
<relativePath>..</relativePath> <!-- lookup parent from repository -->
|
||||
</parent>
|
||||
<artifactId>spring-cloud-netflix-eureka-client</artifactId>
|
||||
@@ -18,11 +18,30 @@
|
||||
<maven.javadoc.failOnError>false</maven.javadoc.failOnError>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-jackson2</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-http-codec</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-restclient</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-webclient</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||
|
||||
+3
-2
@@ -56,8 +56,6 @@ import org.springframework.aot.hint.RuntimeHintsRegistrar;
|
||||
import org.springframework.aot.hint.TypeReference;
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.actuate.autoconfigure.health.ConditionalOnEnabledHealthIndicator;
|
||||
import org.springframework.boot.actuate.health.Health;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
|
||||
import org.springframework.boot.autoconfigure.condition.AnyNestedCondition;
|
||||
@@ -68,6 +66,8 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClas
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.autoconfigure.condition.SearchStrategy;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.boot.health.autoconfigure.contributor.ConditionalOnEnabledHealthIndicator;
|
||||
import org.springframework.boot.health.contributor.Health;
|
||||
import org.springframework.cloud.autoconfigure.RefreshAutoConfiguration;
|
||||
import org.springframework.cloud.client.CommonsClientAutoConfiguration;
|
||||
import org.springframework.cloud.client.ConditionalOnDiscoveryEnabled;
|
||||
@@ -399,6 +399,7 @@ public class EurekaClientAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
@ConditionalOnClass(ConditionalOnEnabledHealthIndicator.class)
|
||||
@ConditionalOnEnabledHealthIndicator("eureka")
|
||||
public EurekaHealthIndicator eurekaHealthIndicator(EurekaClient eurekaClient,
|
||||
EurekaInstanceConfig instanceConfig, EurekaClientConfig clientConfig) {
|
||||
|
||||
+2
-2
@@ -21,12 +21,12 @@ import com.netflix.discovery.EurekaClient;
|
||||
import com.netflix.discovery.EurekaClientConfig;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.actuate.health.SimpleStatusAggregator;
|
||||
import org.springframework.boot.actuate.health.StatusAggregator;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.boot.health.actuate.endpoint.SimpleStatusAggregator;
|
||||
import org.springframework.boot.health.actuate.endpoint.StatusAggregator;
|
||||
import org.springframework.cloud.client.ConditionalOnBlockingDiscoveryEnabled;
|
||||
import org.springframework.cloud.client.ConditionalOnDiscoveryEnabled;
|
||||
import org.springframework.cloud.context.scope.refresh.RefreshScopeRefreshedEvent;
|
||||
|
||||
+38
-25
@@ -24,19 +24,22 @@ import java.util.Set;
|
||||
import com.netflix.appinfo.HealthCheckHandler;
|
||||
import com.netflix.appinfo.InstanceInfo;
|
||||
import com.netflix.appinfo.InstanceInfo.InstanceStatus;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.boot.actuate.health.CompositeHealthContributor;
|
||||
import org.springframework.boot.actuate.health.CompositeReactiveHealthContributor;
|
||||
import org.springframework.boot.actuate.health.Health;
|
||||
import org.springframework.boot.actuate.health.HealthContributor;
|
||||
import org.springframework.boot.actuate.health.HealthIndicator;
|
||||
import org.springframework.boot.actuate.health.NamedContributor;
|
||||
import org.springframework.boot.actuate.health.ReactiveHealthContributor;
|
||||
import org.springframework.boot.actuate.health.ReactiveHealthIndicator;
|
||||
import org.springframework.boot.actuate.health.Status;
|
||||
import org.springframework.boot.actuate.health.StatusAggregator;
|
||||
import org.springframework.boot.health.actuate.endpoint.StatusAggregator;
|
||||
import org.springframework.boot.health.contributor.CompositeHealthContributor;
|
||||
import org.springframework.boot.health.contributor.CompositeReactiveHealthContributor;
|
||||
import org.springframework.boot.health.contributor.Health;
|
||||
import org.springframework.boot.health.contributor.HealthContributor;
|
||||
import org.springframework.boot.health.contributor.HealthContributors;
|
||||
import org.springframework.boot.health.contributor.HealthIndicator;
|
||||
import org.springframework.boot.health.contributor.ReactiveHealthContributor;
|
||||
import org.springframework.boot.health.contributor.ReactiveHealthContributors;
|
||||
import org.springframework.boot.health.contributor.ReactiveHealthIndicator;
|
||||
import org.springframework.boot.health.contributor.Status;
|
||||
import org.springframework.cloud.client.discovery.health.DiscoveryCompositeHealthContributor;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
@@ -67,6 +70,8 @@ import org.springframework.util.Assert;
|
||||
public class EurekaHealthCheckHandler
|
||||
implements HealthCheckHandler, ApplicationContextAware, InitializingBean, Ordered, Lifecycle {
|
||||
|
||||
private static final Log log = LogFactory.getLog(EurekaHealthCheckHandler.class);
|
||||
|
||||
private static final Map<Status, InstanceInfo.InstanceStatus> STATUS_MAPPING = new HashMap<>() {
|
||||
{
|
||||
put(Status.UNKNOWN, InstanceStatus.UNKNOWN);
|
||||
@@ -126,7 +131,11 @@ public class EurekaHealthCheckHandler
|
||||
@Override
|
||||
public InstanceStatus getStatus(InstanceStatus instanceStatus) {
|
||||
if (running) {
|
||||
return getHealthStatus();
|
||||
InstanceStatus status = getHealthStatus();
|
||||
if (status != instanceStatus) {
|
||||
log.info("Eureka health status changed to " + status);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
else {
|
||||
// Return nothing if the context is not running, so the status held by the
|
||||
@@ -142,37 +151,41 @@ public class EurekaHealthCheckHandler
|
||||
}
|
||||
|
||||
protected Status getStatus(StatusAggregator statusAggregator) {
|
||||
Set<Status> statusSet = new HashSet<>();
|
||||
for (HealthContributor contributor : healthContributors.values()) {
|
||||
processContributor(statusSet, contributor);
|
||||
Set<Status> statuses = new HashSet<>();
|
||||
for (Map.Entry<String, HealthContributor> entry : healthContributors.entrySet()) {
|
||||
processContributor(statuses, entry.getKey(), entry.getValue());
|
||||
}
|
||||
for (ReactiveHealthContributor contributor : reactiveHealthContributors.values()) {
|
||||
processContributor(statusSet, contributor);
|
||||
for (Map.Entry<String, ReactiveHealthContributor> entry : reactiveHealthContributors.entrySet()) {
|
||||
processContributor(statuses, entry.getKey(), entry.getValue());
|
||||
}
|
||||
return statusAggregator.getAggregateStatus(statusSet);
|
||||
return statusAggregator.getAggregateStatus(statuses);
|
||||
}
|
||||
|
||||
private void processContributor(Set<Status> statusSet, HealthContributor contributor) {
|
||||
private void processContributor(Set<Status> statuses, String name, HealthContributor contributor) {
|
||||
if (contributor instanceof CompositeHealthContributor) {
|
||||
for (NamedContributor<HealthContributor> contrib : (CompositeHealthContributor) contributor) {
|
||||
processContributor(statusSet, contrib.getContributor());
|
||||
for (HealthContributors.Entry contrib : (CompositeHealthContributor) contributor) {
|
||||
processContributor(statuses, contrib.name(), contrib.contributor());
|
||||
}
|
||||
}
|
||||
else if (contributor instanceof HealthIndicator) {
|
||||
statusSet.add(((HealthIndicator) contributor).health().getStatus());
|
||||
Status status = ((HealthIndicator) contributor).health().getStatus();
|
||||
log.debug("Health contributor " + name + " has status " + status);
|
||||
statuses.add(status);
|
||||
}
|
||||
}
|
||||
|
||||
private void processContributor(Set<Status> statusSet, ReactiveHealthContributor contributor) {
|
||||
private void processContributor(Set<Status> statuses, String name, ReactiveHealthContributor contributor) {
|
||||
if (contributor instanceof CompositeReactiveHealthContributor) {
|
||||
for (NamedContributor<ReactiveHealthContributor> contrib : (CompositeReactiveHealthContributor) contributor) {
|
||||
processContributor(statusSet, contrib.getContributor());
|
||||
for (ReactiveHealthContributors.Entry contrib : (CompositeReactiveHealthContributor) contributor) {
|
||||
processContributor(statuses, contrib.name(), contrib.contributor());
|
||||
}
|
||||
}
|
||||
else if (contributor instanceof ReactiveHealthIndicator) {
|
||||
Health health = ((ReactiveHealthIndicator) contributor).health().block();
|
||||
if (health != null) {
|
||||
statusSet.add(health.getStatus());
|
||||
Status status = health.getStatus();
|
||||
log.debug("Health contributor " + name + " has status " + status);
|
||||
statuses.add(status);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+3
-3
@@ -28,9 +28,9 @@ import com.netflix.discovery.shared.Application;
|
||||
import com.netflix.discovery.shared.Applications;
|
||||
|
||||
import org.springframework.aop.support.AopUtils;
|
||||
import org.springframework.boot.actuate.health.Health;
|
||||
import org.springframework.boot.actuate.health.Health.Builder;
|
||||
import org.springframework.boot.actuate.health.Status;
|
||||
import org.springframework.boot.health.contributor.Health;
|
||||
import org.springframework.boot.health.contributor.Health.Builder;
|
||||
import org.springframework.boot.health.contributor.Status;
|
||||
import org.springframework.cloud.client.discovery.health.DiscoveryHealthIndicator;
|
||||
import org.springframework.cloud.util.ProxyUtils;
|
||||
|
||||
|
||||
+4
-4
@@ -111,7 +111,7 @@ public class EurekaInstanceConfigBean implements CloudEurekaInstanceConfig, Envi
|
||||
* Setting this value too long could mean that the traffic could be routed to the
|
||||
* instance even though the instance is not alive. Setting this value too small could
|
||||
* mean, the instance may be taken out of traffic because of temporary network
|
||||
* glitches.This value to be set to atleast higher than the value specified in
|
||||
* glitches.This value to be set to at least higher than the value specified in
|
||||
* leaseRenewalIntervalInSeconds.
|
||||
*/
|
||||
private int leaseExpirationDurationInSeconds = 90;
|
||||
@@ -169,7 +169,7 @@ public class EurekaInstanceConfigBean implements CloudEurekaInstanceConfig, Envi
|
||||
/**
|
||||
* Gets the relative status page URL path for this instance. The status page URL is
|
||||
* then constructed out of the hostName and the type of communication - secure or
|
||||
* unsecure as specified in securePort and nonSecurePort.
|
||||
* insecure as specified in securePort and nonSecurePort.
|
||||
*
|
||||
* It is normally used for informational purposes for other services to find about the
|
||||
* status of this instance. Users can provide a simple HTML indicating what is the
|
||||
@@ -191,7 +191,7 @@ public class EurekaInstanceConfigBean implements CloudEurekaInstanceConfig, Envi
|
||||
|
||||
/**
|
||||
* Gets the relative home page URL Path for this instance. The home page URL is then
|
||||
* constructed out of the hostName and the type of communication - secure or unsecure.
|
||||
* constructed out of the hostName and the type of communication - secure or insecure.
|
||||
*
|
||||
* It is normally used for informational purposes for other services to use it as a
|
||||
* landing page.
|
||||
@@ -213,7 +213,7 @@ public class EurekaInstanceConfigBean implements CloudEurekaInstanceConfig, Envi
|
||||
/**
|
||||
* Gets the relative health check URL path for this instance. The health check page
|
||||
* URL is then constructed out of the hostname and the type of communication - secure
|
||||
* or unsecure as specified in securePort and nonSecurePort.
|
||||
* or insecure as specified in securePort and nonSecurePort.
|
||||
*
|
||||
* It is normally used for making educated decisions based on the health of the
|
||||
* instance - for example, it can be used to determine whether to proceed deployments
|
||||
|
||||
+1
-2
@@ -22,7 +22,6 @@ import java.util.Objects;
|
||||
|
||||
import com.netflix.appinfo.InstanceInfo;
|
||||
|
||||
import org.springframework.cloud.client.DefaultServiceInstance;
|
||||
import org.springframework.cloud.client.ServiceInstance;
|
||||
import org.springframework.core.style.ToStringCreator;
|
||||
import org.springframework.util.Assert;
|
||||
@@ -81,7 +80,7 @@ public class EurekaServiceInstance implements ServiceInstance {
|
||||
|
||||
@Override
|
||||
public URI getUri() {
|
||||
return DefaultServiceInstance.getUri(this);
|
||||
return ServiceInstance.createUri(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
-37
@@ -1,37 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-present the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.eureka;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.web.client.RestClient;
|
||||
|
||||
/**
|
||||
* A {@link RestClient}-specific {@link TimeoutProperties} implementation.
|
||||
*
|
||||
* @author Olga Maciaszek-Sharma
|
||||
* @since 4.2.0
|
||||
*/
|
||||
@ConfigurationProperties("eureka.client.restclient.timeout")
|
||||
public class RestClientTimeoutProperties extends TimeoutProperties {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "RestClientTimeoutProperties{" + ", connectTimeout=" + connectTimeout + ", connectRequestTimeout="
|
||||
+ connectRequestTimeout + ", socketTimeout=" + socketTimeout + '}';
|
||||
}
|
||||
|
||||
}
|
||||
-43
@@ -1,43 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-present the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.eureka;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.web.client.RestClient;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
/**
|
||||
* A {@link RestTemplate}-specific {@link TimeoutProperties} implementation.
|
||||
*
|
||||
* @author Jiwon Jeon
|
||||
* @author Mooyong Lee
|
||||
* @author Olga Maciaszek-Sharma
|
||||
* @since 3.1.6
|
||||
* @deprecated {@link RestTemplate}-based implementation to be removed in favour of
|
||||
* {@link RestClient}-based implementation.
|
||||
*/
|
||||
@Deprecated(forRemoval = true)
|
||||
@ConfigurationProperties("eureka.client.rest-template-timeout")
|
||||
public class RestTemplateTimeoutProperties extends TimeoutProperties {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "RestTemplateTimeoutProperties{" + ", connectTimeout=" + connectTimeout + ", connectRequestTimeout="
|
||||
+ connectRequestTimeout + ", socketTimeout=" + socketTimeout + '}';
|
||||
}
|
||||
|
||||
}
|
||||
+6
-4
@@ -22,10 +22,11 @@ import com.netflix.discovery.shared.transport.EurekaHttpClient;
|
||||
import org.apache.hc.client5.http.config.RequestConfig;
|
||||
import org.apache.hc.core5.http.io.SocketConfig;
|
||||
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.web.client.RestClient;
|
||||
|
||||
/**
|
||||
* Properties for configuring timeouts used in {@link RestTemplate} required by
|
||||
* Properties for configuring timeouts used in {@link RestClient} required by
|
||||
* {@link EurekaHttpClient}.
|
||||
*
|
||||
* @author Jiwon Jeon
|
||||
@@ -33,7 +34,8 @@ import org.springframework.web.client.RestTemplate;
|
||||
* @author Olga Maciaszek-Sharma
|
||||
* @since 4.2.0
|
||||
*/
|
||||
public abstract class TimeoutProperties {
|
||||
@ConfigurationProperties("eureka.client.timeout")
|
||||
public class TimeoutProperties {
|
||||
|
||||
/**
|
||||
* Default values are set to 180000, in keeping with {@link RequestConfig} and
|
||||
@@ -78,7 +80,7 @@ public abstract class TimeoutProperties {
|
||||
return false;
|
||||
}
|
||||
|
||||
RestTemplateTimeoutProperties that = (RestTemplateTimeoutProperties) o;
|
||||
TimeoutProperties that = (TimeoutProperties) o;
|
||||
|
||||
return connectTimeout == that.connectTimeout && connectRequestTimeout == that.connectRequestTimeout
|
||||
&& socketTimeout == that.socketTimeout;
|
||||
|
||||
+13
-102
@@ -36,24 +36,19 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.autoconfigure.condition.SearchStrategy;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.boot.web.client.RestTemplateBuilder;
|
||||
import org.springframework.cloud.configuration.SSLContextFactory;
|
||||
import org.springframework.cloud.configuration.TlsProperties;
|
||||
import org.springframework.cloud.netflix.eureka.RestClientTimeoutProperties;
|
||||
import org.springframework.cloud.netflix.eureka.RestTemplateTimeoutProperties;
|
||||
import org.springframework.cloud.netflix.eureka.TimeoutProperties;
|
||||
import org.springframework.cloud.netflix.eureka.http.DefaultEurekaClientHttpRequestFactorySupplier;
|
||||
import org.springframework.cloud.netflix.eureka.http.EurekaClientHttpRequestFactorySupplier;
|
||||
import org.springframework.cloud.netflix.eureka.http.RestClientDiscoveryClientOptionalArgs;
|
||||
import org.springframework.cloud.netflix.eureka.http.RestClientTransportClientFactories;
|
||||
import org.springframework.cloud.netflix.eureka.http.RestTemplateDiscoveryClientOptionalArgs;
|
||||
import org.springframework.cloud.netflix.eureka.http.RestTemplateTransportClientFactories;
|
||||
import org.springframework.cloud.netflix.eureka.http.WebClientDiscoveryClientOptionalArgs;
|
||||
import org.springframework.cloud.netflix.eureka.http.WebClientTransportClientFactories;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.client.RestClient;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
|
||||
/**
|
||||
@@ -63,10 +58,10 @@ import org.springframework.web.reactive.function.client.WebClient;
|
||||
* @author Wonchul Heo
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableConfigurationProperties({ RestTemplateTimeoutProperties.class, RestClientTimeoutProperties.class })
|
||||
@EnableConfigurationProperties({ TimeoutProperties.class })
|
||||
public class DiscoveryClientOptionalArgsConfiguration {
|
||||
|
||||
protected static final Log logger = LogFactory.getLog(DiscoveryClientOptionalArgsConfiguration.class);
|
||||
protected static final Log LOG = LogFactory.getLog(DiscoveryClientOptionalArgsConfiguration.class);
|
||||
|
||||
@Bean
|
||||
@ConfigurationProperties("eureka.client.tls")
|
||||
@@ -83,49 +78,6 @@ public class DiscoveryClientOptionalArgsConfiguration {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated {@link RestTemplate}-based implementation to be removed in favour of
|
||||
* {@link RestClient}-based implementation.
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@Conditional(OnRestTemplatePresentAndEnabledCondition.class)
|
||||
@Deprecated
|
||||
static class RestTemplateConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
EurekaClientHttpRequestFactorySupplier defaultEurekaClientHttpRequestFactorySupplier(
|
||||
RestTemplateTimeoutProperties restTemplateTimeoutProperties,
|
||||
Set<EurekaClientHttpRequestFactorySupplier.RequestConfigCustomizer> requestConfigCustomizers) {
|
||||
return new DefaultEurekaClientHttpRequestFactorySupplier(restTemplateTimeoutProperties,
|
||||
requestConfigCustomizers);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(value = { AbstractDiscoveryClientOptionalArgs.class },
|
||||
search = SearchStrategy.CURRENT)
|
||||
public RestTemplateDiscoveryClientOptionalArgs restTemplateDiscoveryClientOptionalArgs(
|
||||
TlsProperties tlsProperties,
|
||||
EurekaClientHttpRequestFactorySupplier eurekaClientHttpRequestFactorySupplier,
|
||||
ObjectProvider<RestTemplateBuilder> restTemplateBuilders) throws GeneralSecurityException, IOException {
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Eureka HTTP Client uses RestTemplate.");
|
||||
}
|
||||
RestTemplateDiscoveryClientOptionalArgs result = new RestTemplateDiscoveryClientOptionalArgs(
|
||||
eurekaClientHttpRequestFactorySupplier, restTemplateBuilders::getIfAvailable);
|
||||
setupTLS(result, tlsProperties);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(value = { TransportClientFactories.class }, search = SearchStrategy.CURRENT)
|
||||
public RestTemplateTransportClientFactories restTemplateTransportClientFactories(
|
||||
RestTemplateDiscoveryClientOptionalArgs optionalArgs) {
|
||||
return new RestTemplateTransportClientFactories(optionalArgs);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@Conditional(OnJerseyClientPresentAndEnabledCondition.class)
|
||||
@ConditionalOnBean(value = AbstractDiscoveryClientOptionalArgs.class, search = SearchStrategy.CURRENT)
|
||||
@@ -133,8 +85,8 @@ public class DiscoveryClientOptionalArgsConfiguration {
|
||||
|
||||
DiscoveryClientOptionalArgsTlsConfiguration(TlsProperties tlsProperties,
|
||||
AbstractDiscoveryClientOptionalArgs optionalArgs) throws GeneralSecurityException, IOException {
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Eureka HTTP Client uses Jersey");
|
||||
if (LOG.isInfoEnabled()) {
|
||||
LOG.info("Eureka HTTP Client uses Jersey");
|
||||
}
|
||||
setupTLS(optionalArgs, tlsProperties);
|
||||
}
|
||||
@@ -149,12 +101,12 @@ public class DiscoveryClientOptionalArgsConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(
|
||||
value = { AbstractDiscoveryClientOptionalArgs.class, RestTemplateDiscoveryClientOptionalArgs.class },
|
||||
value = { AbstractDiscoveryClientOptionalArgs.class, RestClientDiscoveryClientOptionalArgs.class },
|
||||
search = SearchStrategy.CURRENT)
|
||||
public WebClientDiscoveryClientOptionalArgs webClientDiscoveryClientOptionalArgs(TlsProperties tlsProperties,
|
||||
ObjectProvider<WebClient.Builder> builder) throws GeneralSecurityException, IOException {
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Eureka HTTP Client uses WebClient.");
|
||||
if (LOG.isInfoEnabled()) {
|
||||
LOG.info("Eureka HTTP Client uses WebClient.");
|
||||
}
|
||||
WebClientDiscoveryClientOptionalArgs result = new WebClientDiscoveryClientOptionalArgs(
|
||||
builder::getIfAvailable);
|
||||
@@ -178,9 +130,8 @@ public class DiscoveryClientOptionalArgsConfiguration {
|
||||
protected static class WebClientNotFoundConfiguration {
|
||||
|
||||
public WebClientNotFoundConfiguration() {
|
||||
throw new IllegalStateException(
|
||||
"eureka.client.webclient.enabled is true, " + "but WebClient is not on the classpath. Please add "
|
||||
+ "spring-boot-starter-webflux as a dependency.");
|
||||
throw new IllegalStateException("eureka.client.webclient.enabled is true, "
|
||||
+ "but WebClient is not on the classpath. Please add " + "spring-boot-webclient as a dependency.");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -192,7 +143,7 @@ public class DiscoveryClientOptionalArgsConfiguration {
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
EurekaClientHttpRequestFactorySupplier defaultEurekaClientHttpRequestFactorySupplier(
|
||||
RestClientTimeoutProperties restClientTimeoutProperties,
|
||||
TimeoutProperties restClientTimeoutProperties,
|
||||
Set<EurekaClientHttpRequestFactorySupplier.RequestConfigCustomizer> requestConfigCustomizers) {
|
||||
return new DefaultEurekaClientHttpRequestFactorySupplier(restClientTimeoutProperties,
|
||||
requestConfigCustomizers);
|
||||
@@ -205,8 +156,8 @@ public class DiscoveryClientOptionalArgsConfiguration {
|
||||
EurekaClientHttpRequestFactorySupplier eurekaClientHttpRequestFactorySupplier,
|
||||
ObjectProvider<RestClient.Builder> restClientBuilderProvider)
|
||||
throws GeneralSecurityException, IOException {
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Eureka HTTP Client uses RestClient.");
|
||||
if (LOG.isInfoEnabled()) {
|
||||
LOG.info("Eureka HTTP Client uses RestClient.");
|
||||
}
|
||||
RestClientDiscoveryClientOptionalArgs result = new RestClientDiscoveryClientOptionalArgs(
|
||||
eurekaClientHttpRequestFactorySupplier,
|
||||
@@ -260,41 +211,6 @@ public class DiscoveryClientOptionalArgsConfiguration {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated {@link RestTemplate}-based implementation to be removed in favour of
|
||||
* {@link RestClient}-based implementation.
|
||||
*/
|
||||
@Deprecated(forRemoval = true)
|
||||
static class OnRestTemplatePresentAndEnabledCondition extends AllNestedConditions {
|
||||
|
||||
OnRestTemplatePresentAndEnabledCondition() {
|
||||
super(ConfigurationPhase.REGISTER_BEAN);
|
||||
}
|
||||
|
||||
@ConditionalOnClass(name = "org.springframework.web.client.RestTemplate")
|
||||
static class OnRestTemplatePresent {
|
||||
|
||||
}
|
||||
|
||||
@Conditional(OnJerseyClientNotPresentOrNotEnabledCondition.class)
|
||||
static class OnJerseyClientNotPresentOrNotEnabled {
|
||||
|
||||
}
|
||||
|
||||
@ConditionalOnProperty(prefix = "eureka.client", name = "webclient.enabled", matchIfMissing = true,
|
||||
havingValue = "false")
|
||||
static class OnWebClientDisabled {
|
||||
|
||||
}
|
||||
|
||||
@ConditionalOnProperty(prefix = "eureka.client", name = "restclient.enabled", havingValue = "false",
|
||||
matchIfMissing = true)
|
||||
static class OnRestClientDisabled {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class OnRestClientPresentAndEnabledCondition extends AllNestedConditions {
|
||||
|
||||
OnRestClientPresentAndEnabledCondition() {
|
||||
@@ -317,11 +233,6 @@ public class DiscoveryClientOptionalArgsConfiguration {
|
||||
|
||||
}
|
||||
|
||||
@ConditionalOnProperty(prefix = "eureka.client", name = "restclient.enabled", havingValue = "true")
|
||||
static class OnRestClientEnabled {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+7
-79
@@ -28,22 +28,18 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.autoconfigure.condition.SearchStrategy;
|
||||
import org.springframework.boot.autoconfigure.http.codec.CodecsAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientAutoConfiguration;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.boot.web.client.RestTemplateBuilder;
|
||||
import org.springframework.boot.http.codec.autoconfigure.CodecsAutoConfiguration;
|
||||
import org.springframework.boot.webclient.autoconfigure.WebClientAutoConfiguration;
|
||||
import org.springframework.cloud.config.client.ConfigServerInstanceProvider;
|
||||
import org.springframework.cloud.config.client.ConfigServicePropertySourceLocator;
|
||||
import org.springframework.cloud.configuration.TlsProperties;
|
||||
import org.springframework.cloud.netflix.eureka.EurekaClientConfigBean;
|
||||
import org.springframework.cloud.netflix.eureka.RestClientTimeoutProperties;
|
||||
import org.springframework.cloud.netflix.eureka.RestTemplateTimeoutProperties;
|
||||
import org.springframework.cloud.netflix.eureka.TimeoutProperties;
|
||||
import org.springframework.cloud.netflix.eureka.http.DefaultEurekaClientHttpRequestFactorySupplier;
|
||||
import org.springframework.cloud.netflix.eureka.http.EurekaClientHttpRequestFactorySupplier;
|
||||
import org.springframework.cloud.netflix.eureka.http.RestClientEurekaHttpClient;
|
||||
import org.springframework.cloud.netflix.eureka.http.RestClientTransportClientFactory;
|
||||
import org.springframework.cloud.netflix.eureka.http.RestTemplateEurekaHttpClient;
|
||||
import org.springframework.cloud.netflix.eureka.http.RestTemplateTransportClientFactory;
|
||||
import org.springframework.cloud.netflix.eureka.http.WebClientEurekaHttpClient;
|
||||
import org.springframework.cloud.netflix.eureka.http.WebClientTransportClientFactory;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
@@ -52,7 +48,6 @@ import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.web.client.RestClient;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
|
||||
/**
|
||||
@@ -67,7 +62,7 @@ import org.springframework.web.reactive.function.client.WebClient;
|
||||
@ConditionalOnClass(ConfigServicePropertySourceLocator.class)
|
||||
@Conditional(EurekaConfigServerBootstrapConfiguration.EurekaConfigServerBootstrapCondition.class)
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableConfigurationProperties({ RestTemplateTimeoutProperties.class, RestClientTimeoutProperties.class })
|
||||
@EnableConfigurationProperties({ TimeoutProperties.class })
|
||||
public class EurekaConfigServerBootstrapConfiguration {
|
||||
|
||||
@Bean
|
||||
@@ -82,69 +77,8 @@ public class EurekaConfigServerBootstrapConfiguration {
|
||||
return new EurekaConfigServerInstanceProvider(client, config)::getInstances;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated {@link RestTemplate}-based implementation to be removed in favour of
|
||||
* {@link RestClient}-based implementation.
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@Conditional(RestTemplateConfiguration.OnRestTemplatePresentAndEnabledCondition.class)
|
||||
@Deprecated
|
||||
static class RestTemplateConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(EurekaHttpClient.class)
|
||||
public RestTemplateEurekaHttpClient configDiscoveryRestTemplateEurekaHttpClient(EurekaClientConfigBean config,
|
||||
Environment env, @Nullable TlsProperties properties,
|
||||
EurekaClientHttpRequestFactorySupplier eurekaClientHttpRequestFactorySupplier,
|
||||
ObjectProvider<RestTemplateBuilder> restTemplateBuilders) {
|
||||
return (RestTemplateEurekaHttpClient) new RestTemplateTransportClientFactory(properties,
|
||||
eurekaClientHttpRequestFactorySupplier, restTemplateBuilders::getIfAvailable)
|
||||
.newClient(HostnameBasedUrlRandomizer.randomEndpoint(config, env));
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
EurekaClientHttpRequestFactorySupplier defaultEurekaClientHttpRequestFactorySupplier(
|
||||
RestTemplateTimeoutProperties restTemplateTimeoutProperties,
|
||||
Set<EurekaClientHttpRequestFactorySupplier.RequestConfigCustomizer> requestConfigCustomizers) {
|
||||
return new DefaultEurekaClientHttpRequestFactorySupplier(restTemplateTimeoutProperties,
|
||||
requestConfigCustomizers);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated {@link RestTemplate}-based implementation to be removed in favour
|
||||
* of {@link RestClient}-based implementation.
|
||||
*/
|
||||
@Deprecated(forRemoval = true)
|
||||
static class OnRestTemplatePresentAndEnabledCondition extends AllNestedConditions {
|
||||
|
||||
OnRestTemplatePresentAndEnabledCondition() {
|
||||
super(ConfigurationPhase.REGISTER_BEAN);
|
||||
}
|
||||
|
||||
@ConditionalOnClass(name = "org.springframework.web.client.RestTemplate")
|
||||
static class OnRestTemplatePresent {
|
||||
|
||||
}
|
||||
|
||||
@ConditionalOnProperty(prefix = "eureka.client", name = "webclient.enabled", matchIfMissing = true,
|
||||
havingValue = "false")
|
||||
static class OnWebClientDisabled {
|
||||
|
||||
}
|
||||
|
||||
@ConditionalOnProperty(prefix = "eureka.client", name = "restclient.enabled", havingValue = "false",
|
||||
matchIfMissing = true)
|
||||
static class OnRestClientDisabled {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass(name = "org.springframework.web.reactive.function.client.WebClient")
|
||||
@ConditionalOnClass({ WebClient.class, WebClientAutoConfiguration.class, CodecsAutoConfiguration.class })
|
||||
@ConditionalOnProperty(prefix = "eureka.client", name = "webclient.enabled", havingValue = "true")
|
||||
@ImportAutoConfiguration({ CodecsAutoConfiguration.class, WebClientAutoConfiguration.class })
|
||||
protected static class WebClientConfiguration {
|
||||
@@ -178,10 +112,9 @@ public class EurekaConfigServerBootstrapConfiguration {
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
EurekaClientHttpRequestFactorySupplier defaultEurekaClientHttpRequestFactorySupplier(
|
||||
RestClientTimeoutProperties restClientTimeoutProperties,
|
||||
TimeoutProperties timeoutProperties,
|
||||
Set<EurekaClientHttpRequestFactorySupplier.RequestConfigCustomizer> requestConfigCustomizers) {
|
||||
return new DefaultEurekaClientHttpRequestFactorySupplier(restClientTimeoutProperties,
|
||||
requestConfigCustomizers);
|
||||
return new DefaultEurekaClientHttpRequestFactorySupplier(timeoutProperties, requestConfigCustomizers);
|
||||
}
|
||||
|
||||
static class OnRestClientPresentAndEnabledCondition extends AllNestedConditions {
|
||||
@@ -201,11 +134,6 @@ public class EurekaConfigServerBootstrapConfiguration {
|
||||
|
||||
}
|
||||
|
||||
@ConditionalOnProperty(prefix = "eureka.client", name = "restclient.enabled", havingValue = "true")
|
||||
static class OnRestClientEnabled {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+5
-5
@@ -20,9 +20,9 @@ import java.util.Collections;
|
||||
|
||||
import com.netflix.discovery.shared.transport.EurekaHttpClient;
|
||||
|
||||
import org.springframework.boot.BootstrapContext;
|
||||
import org.springframework.boot.BootstrapRegistry;
|
||||
import org.springframework.boot.BootstrapRegistryInitializer;
|
||||
import org.springframework.boot.bootstrap.BootstrapContext;
|
||||
import org.springframework.boot.bootstrap.BootstrapRegistry;
|
||||
import org.springframework.boot.bootstrap.BootstrapRegistryInitializer;
|
||||
import org.springframework.boot.context.properties.bind.BindHandler;
|
||||
import org.springframework.boot.context.properties.bind.Binder;
|
||||
import org.springframework.cloud.config.client.ConfigClientProperties;
|
||||
@@ -30,7 +30,7 @@ import org.springframework.cloud.config.client.ConfigServerConfigDataLocationRes
|
||||
import org.springframework.cloud.config.client.ConfigServerInstanceProvider;
|
||||
import org.springframework.cloud.configuration.TlsProperties;
|
||||
import org.springframework.cloud.netflix.eureka.EurekaClientConfigBean;
|
||||
import org.springframework.cloud.netflix.eureka.RestClientTimeoutProperties;
|
||||
import org.springframework.cloud.netflix.eureka.TimeoutProperties;
|
||||
import org.springframework.cloud.netflix.eureka.http.DefaultEurekaClientHttpRequestFactorySupplier;
|
||||
import org.springframework.cloud.netflix.eureka.http.EurekaClientHttpRequestFactorySupplier;
|
||||
import org.springframework.cloud.netflix.eureka.http.RestClientTransportClientFactory;
|
||||
@@ -61,7 +61,7 @@ public class EurekaConfigServerBootstrapper implements BootstrapRegistryInitiali
|
||||
EurekaHttpClient httpClient = new RestClientTransportClientFactory(
|
||||
context.getOrElse(TlsProperties.class, null),
|
||||
context.getOrElse(EurekaClientHttpRequestFactorySupplier.class,
|
||||
new DefaultEurekaClientHttpRequestFactorySupplier(new RestClientTimeoutProperties(),
|
||||
new DefaultEurekaClientHttpRequestFactorySupplier(new TimeoutProperties(),
|
||||
Collections.emptySet())))
|
||||
.newClient(HostnameBasedUrlRandomizer.randomEndpoint(config, getPropertyResolver(context)));
|
||||
return new EurekaConfigServerInstanceProvider(httpClient, config)::getInstances;
|
||||
|
||||
+10
-32
@@ -16,7 +16,6 @@
|
||||
|
||||
package org.springframework.cloud.netflix.eureka.http;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@@ -34,8 +33,8 @@ import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactoryBuilder;
|
||||
import org.apache.hc.core5.http.io.SocketConfig;
|
||||
import org.apache.hc.core5.util.Timeout;
|
||||
|
||||
import org.springframework.cloud.netflix.eureka.RestTemplateTimeoutProperties;
|
||||
import org.springframework.cloud.netflix.eureka.TimeoutProperties;
|
||||
import org.springframework.cloud.netflix.eureka.http.EurekaClientHttpRequestFactorySupplier.RequestConfigCustomizer;
|
||||
import org.springframework.http.client.ClientHttpRequestFactory;
|
||||
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
|
||||
import org.springframework.lang.Nullable;
|
||||
@@ -44,6 +43,13 @@ import org.springframework.lang.Nullable;
|
||||
* Supplier for the {@link ClientHttpRequestFactory} to be used by Eureka client that uses
|
||||
* {@link HttpClients}.
|
||||
*
|
||||
* <p>
|
||||
* This supplier is intentionally stateless: each call to {@link #get} builds a fresh
|
||||
* {@link CloseableHttpClient}. Caching and lifecycle management of the shared client is
|
||||
* the responsibility of the owning {@code TransportClientFactory}
|
||||
* ({@link RestClientTransportClientFactory}), which is already created once per Eureka
|
||||
* client and is the natural owner of that client's lifecycle.
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
* @author Olga Maciaszek-Sharma
|
||||
* @author Jiwon Jeon
|
||||
@@ -53,35 +59,7 @@ public class DefaultEurekaClientHttpRequestFactorySupplier implements EurekaClie
|
||||
|
||||
private final TimeoutProperties timeoutProperties;
|
||||
|
||||
// TODO: switch to final after removing deprecated interfaces
|
||||
private Set<RequestConfigCustomizer> requestConfigCustomizers = Collections.emptySet();
|
||||
|
||||
/**
|
||||
* @deprecated in favour of
|
||||
* {@link DefaultEurekaClientHttpRequestFactorySupplier#DefaultEurekaClientHttpRequestFactorySupplier(TimeoutProperties, Set)}
|
||||
*/
|
||||
@Deprecated(forRemoval = true)
|
||||
public DefaultEurekaClientHttpRequestFactorySupplier() {
|
||||
this.timeoutProperties = new RestTemplateTimeoutProperties();
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated in favour of
|
||||
* {@link DefaultEurekaClientHttpRequestFactorySupplier#DefaultEurekaClientHttpRequestFactorySupplier(TimeoutProperties, Set)}
|
||||
*/
|
||||
@Deprecated(forRemoval = true)
|
||||
public DefaultEurekaClientHttpRequestFactorySupplier(RestTemplateTimeoutProperties timeoutProperties) {
|
||||
this.timeoutProperties = timeoutProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated in favour of
|
||||
* {@link DefaultEurekaClientHttpRequestFactorySupplier#DefaultEurekaClientHttpRequestFactorySupplier(TimeoutProperties, Set)}
|
||||
*/
|
||||
@Deprecated(forRemoval = true)
|
||||
public DefaultEurekaClientHttpRequestFactorySupplier(TimeoutProperties timeoutProperties) {
|
||||
this.timeoutProperties = timeoutProperties;
|
||||
}
|
||||
private final Set<RequestConfigCustomizer> requestConfigCustomizers;
|
||||
|
||||
public DefaultEurekaClientHttpRequestFactorySupplier(TimeoutProperties timeoutProperties,
|
||||
Set<RequestConfigCustomizer> requestConfigCustomizers) {
|
||||
@@ -97,8 +75,8 @@ public class DefaultEurekaClientHttpRequestFactorySupplier implements EurekaClie
|
||||
.setConnectionManager(buildConnectionManager(sslContext, hostnameVerifier, timeoutProperties));
|
||||
}
|
||||
httpClientBuilder.setDefaultRequestConfig(buildRequestConfig());
|
||||
|
||||
CloseableHttpClient httpClient = httpClientBuilder.build();
|
||||
|
||||
HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
|
||||
requestFactory.setHttpClient(httpClient);
|
||||
return requestFactory;
|
||||
|
||||
+2
-2
@@ -24,8 +24,8 @@ import com.netflix.discovery.shared.Application;
|
||||
import com.netflix.discovery.shared.Applications;
|
||||
|
||||
/**
|
||||
* A simple wrapper class for {@link Applications} that insure proprer Jackson
|
||||
* serialization through the JsonPropert overwrites.
|
||||
* A simple wrapper class for {@link Applications} that insure proper Jackson
|
||||
* serialization through the JsonProperties overwrites.
|
||||
*
|
||||
* @author Daniel Lavoie
|
||||
*/
|
||||
|
||||
+1
-1
@@ -51,7 +51,7 @@ public class RestClientTransportClientFactories implements TransportClientFactor
|
||||
public TransportClientFactory newTransportClientFactory(final EurekaClientConfig clientConfig,
|
||||
final Collection<Void> additionalFilters, final InstanceInfo myInstanceInfo,
|
||||
final Optional<SSLContext> sslContext, final Optional<HostnameVerifier> hostnameVerifier) {
|
||||
return new RestClientTransportClientFactory(args.getSSLContext(), args.getHostnameVerifier(),
|
||||
return new RestClientTransportClientFactory(sslContext, hostnameVerifier,
|
||||
args.getEurekaClientHttpRequestFactorySupplier(), args.getRestClientBuilderSupplier());
|
||||
}
|
||||
|
||||
|
||||
+34
-3
@@ -16,6 +16,8 @@
|
||||
|
||||
package org.springframework.cloud.netflix.eureka.http;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
@@ -31,6 +33,7 @@ import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.HttpStatusCode;
|
||||
import org.springframework.http.client.ClientHttpRequestFactory;
|
||||
import org.springframework.http.client.ClientHttpResponse;
|
||||
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
|
||||
import org.springframework.http.client.support.BasicAuthenticationInterceptor;
|
||||
import org.springframework.web.client.RestClient;
|
||||
import org.springframework.web.util.UriComponentsBuilder;
|
||||
@@ -44,6 +47,15 @@ import static org.springframework.cloud.netflix.eureka.http.EurekaHttpClientUtil
|
||||
* {@link RestClientEurekaHttpClient}. Relies on Jackson for serialization and
|
||||
* deserialization.
|
||||
*
|
||||
* <p>
|
||||
* A single {@link ClientHttpRequestFactory} (and the underlying HTTP client it wraps) is
|
||||
* lazily built on the first call to {@link #newClient} and reused for every subsequent
|
||||
* call on this factory instance. Since each {@code RestClientTransportClientFactory} is
|
||||
* already scoped to a single Eureka client, caching the request factory here - rather
|
||||
* than in a potentially shared {@link EurekaClientHttpRequestFactorySupplier} - ties the
|
||||
* shared client's lifecycle directly to this factory instance, so {@link #shutdown()}
|
||||
* only ever closes a client owned exclusively by this factory.
|
||||
*
|
||||
* @author Wonchul Heo
|
||||
* @author Olga Maciaszek-Sharma
|
||||
* @since 4.2.0
|
||||
@@ -58,6 +70,8 @@ public class RestClientTransportClientFactory implements TransportClientFactory
|
||||
|
||||
private final Supplier<RestClient.Builder> builderSupplier;
|
||||
|
||||
private ClientHttpRequestFactory cachedRequestFactory;
|
||||
|
||||
public RestClientTransportClientFactory(Optional<SSLContext> sslContext,
|
||||
Optional<HostnameVerifier> hostnameVerifier,
|
||||
EurekaClientHttpRequestFactorySupplier eurekaClientHttpRequestFactorySupplier,
|
||||
@@ -84,8 +98,7 @@ public class RestClientTransportClientFactory implements TransportClientFactory
|
||||
// we want a copy to modify. Don't change the original
|
||||
final RestClient.Builder builder = builderSupplier.get().clone();
|
||||
|
||||
ClientHttpRequestFactory requestFactory = this.eurekaClientHttpRequestFactorySupplier
|
||||
.get(this.sslContext.orElse(null), this.hostnameVerifier.orElse(null));
|
||||
ClientHttpRequestFactory requestFactory = getOrCreateRequestFactory();
|
||||
|
||||
builder.requestFactory(requestFactory);
|
||||
setUrl(builder, endpoint.getServiceUrl());
|
||||
@@ -105,8 +118,26 @@ public class RestClientTransportClientFactory implements TransportClientFactory
|
||||
return new RestClientEurekaHttpClient(builder.build());
|
||||
}
|
||||
|
||||
private synchronized ClientHttpRequestFactory getOrCreateRequestFactory() {
|
||||
if (this.cachedRequestFactory == null) {
|
||||
this.cachedRequestFactory = this.eurekaClientHttpRequestFactorySupplier.get(this.sslContext.orElse(null),
|
||||
this.hostnameVerifier.orElse(null));
|
||||
}
|
||||
return this.cachedRequestFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shutdown() {
|
||||
public synchronized void shutdown() {
|
||||
if (this.cachedRequestFactory instanceof HttpComponentsClientHttpRequestFactory httpRequestFactory
|
||||
&& httpRequestFactory.getHttpClient() instanceof Closeable closeableHttpClient) {
|
||||
try {
|
||||
closeableHttpClient.close();
|
||||
}
|
||||
catch (IOException ex) {
|
||||
// best-effort close during shutdown; nothing actionable if it fails
|
||||
}
|
||||
}
|
||||
this.cachedRequestFactory = null;
|
||||
}
|
||||
|
||||
private static void setUrl(RestClient.Builder builder, String serviceUrl) {
|
||||
|
||||
-52
@@ -1,52 +0,0 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.eureka.http;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import com.netflix.discovery.AbstractDiscoveryClientOptionalArgs;
|
||||
|
||||
import org.springframework.boot.web.client.RestTemplateBuilder;
|
||||
import org.springframework.web.client.RestClient;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
/**
|
||||
* @author Daniel Lavoie
|
||||
* @author Armin Krezovic
|
||||
* @deprecated {@link RestTemplate}-based implementation to be removed in favour of
|
||||
* {@link RestClient}-based implementation.
|
||||
*/
|
||||
@Deprecated
|
||||
public class RestTemplateDiscoveryClientOptionalArgs extends AbstractDiscoveryClientOptionalArgs<Void> {
|
||||
|
||||
protected final EurekaClientHttpRequestFactorySupplier eurekaClientHttpRequestFactorySupplier;
|
||||
|
||||
protected final Supplier<RestTemplateBuilder> restTemplateBuilderSupplier;
|
||||
|
||||
public RestTemplateDiscoveryClientOptionalArgs(
|
||||
EurekaClientHttpRequestFactorySupplier eurekaClientHttpRequestFactorySupplier) {
|
||||
this(eurekaClientHttpRequestFactorySupplier, RestTemplateBuilder::new);
|
||||
}
|
||||
|
||||
public RestTemplateDiscoveryClientOptionalArgs(
|
||||
EurekaClientHttpRequestFactorySupplier eurekaClientHttpRequestFactorySupplier,
|
||||
Supplier<RestTemplateBuilder> restTemplateBuilderSupplier) {
|
||||
this.eurekaClientHttpRequestFactorySupplier = eurekaClientHttpRequestFactorySupplier;
|
||||
this.restTemplateBuilderSupplier = restTemplateBuilderSupplier;
|
||||
}
|
||||
|
||||
}
|
||||
-252
@@ -1,252 +0,0 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.eureka.http;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import com.netflix.appinfo.InstanceInfo;
|
||||
import com.netflix.appinfo.InstanceInfo.InstanceStatus;
|
||||
import com.netflix.discovery.shared.Application;
|
||||
import com.netflix.discovery.shared.Applications;
|
||||
import com.netflix.discovery.shared.transport.EurekaHttpClient;
|
||||
import com.netflix.discovery.shared.transport.EurekaHttpResponse;
|
||||
import com.netflix.discovery.shared.transport.EurekaHttpResponse.EurekaHttpResponseBuilder;
|
||||
import com.netflix.discovery.util.StringUtil;
|
||||
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.client.RestClient;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
import org.springframework.web.util.UriComponentsBuilder;
|
||||
|
||||
import static com.netflix.discovery.shared.transport.EurekaHttpResponse.anEurekaHttpResponse;
|
||||
|
||||
/**
|
||||
* @author Daniel Lavoie
|
||||
* @author Václav Plic
|
||||
* @deprecated {@link RestTemplate}-based implementation to be removed in favour of
|
||||
* {@link RestClient}-based implementation.
|
||||
*/
|
||||
@Deprecated(forRemoval = true)
|
||||
public class RestTemplateEurekaHttpClient implements EurekaHttpClient {
|
||||
|
||||
private final RestTemplate restTemplate;
|
||||
|
||||
private String serviceUrl;
|
||||
|
||||
public RestTemplateEurekaHttpClient(RestTemplate restTemplate, String serviceUrl) {
|
||||
this.restTemplate = restTemplate;
|
||||
this.serviceUrl = serviceUrl;
|
||||
if (!serviceUrl.endsWith("/")) {
|
||||
this.serviceUrl = this.serviceUrl + "/";
|
||||
}
|
||||
}
|
||||
|
||||
public String getServiceUrl() {
|
||||
return this.serviceUrl;
|
||||
}
|
||||
|
||||
public RestTemplate getRestTemplate() {
|
||||
return restTemplate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EurekaHttpResponse<Void> register(InstanceInfo info) {
|
||||
URI uri = UriComponentsBuilder.fromHttpUrl(serviceUrl)
|
||||
.path("apps/{appName}")
|
||||
.buildAndExpand(info.getAppName())
|
||||
.toUri();
|
||||
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.add(HttpHeaders.ACCEPT_ENCODING, "gzip");
|
||||
headers.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
|
||||
|
||||
ResponseEntity<Void> response = restTemplate.exchange(uri, HttpMethod.POST, new HttpEntity<>(info, headers),
|
||||
Void.class);
|
||||
|
||||
return anEurekaHttpResponse(response.getStatusCode().value()).headers(headersOf(response)).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public EurekaHttpResponse<Void> cancel(String appName, String id) {
|
||||
URI uri = UriComponentsBuilder.fromHttpUrl(serviceUrl)
|
||||
.path("apps/{appName}/{id}")
|
||||
.buildAndExpand(appName, id)
|
||||
.toUri();
|
||||
|
||||
ResponseEntity<Void> response = restTemplate.exchange(uri, HttpMethod.DELETE, null, Void.class);
|
||||
|
||||
return anEurekaHttpResponse(response.getStatusCode().value()).headers(headersOf(response)).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public EurekaHttpResponse<InstanceInfo> sendHeartBeat(String appName, String id, InstanceInfo info,
|
||||
InstanceStatus overriddenStatus) {
|
||||
UriComponentsBuilder uriBuilder = UriComponentsBuilder.fromHttpUrl(serviceUrl)
|
||||
.path("apps/{appName}/{id}")
|
||||
.queryParam("status", info.getStatus().toString())
|
||||
.queryParam("lastDirtyTimestamp", info.getLastDirtyTimestamp().toString());
|
||||
|
||||
if (overriddenStatus != null) {
|
||||
uriBuilder = uriBuilder.queryParam("overriddenstatus", overriddenStatus.name());
|
||||
}
|
||||
|
||||
URI uri = uriBuilder.buildAndExpand(appName, id).toUri();
|
||||
|
||||
ResponseEntity<InstanceInfo> response = restTemplate.exchange(uri, HttpMethod.PUT, null, InstanceInfo.class);
|
||||
|
||||
EurekaHttpResponseBuilder<InstanceInfo> eurekaResponseBuilder = anEurekaHttpResponse(
|
||||
response.getStatusCode().value(), InstanceInfo.class)
|
||||
.headers(headersOf(response));
|
||||
|
||||
if (response.hasBody()) {
|
||||
eurekaResponseBuilder.entity(response.getBody());
|
||||
}
|
||||
|
||||
return eurekaResponseBuilder.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public EurekaHttpResponse<Void> statusUpdate(String appName, String id, InstanceStatus newStatus,
|
||||
InstanceInfo info) {
|
||||
URI uri = UriComponentsBuilder.fromHttpUrl(serviceUrl)
|
||||
.path("apps/{appName}/{id}/status")
|
||||
.queryParam("value", newStatus.name())
|
||||
.queryParam("lastDirtyTimestamp", info.getLastDirtyTimestamp().toString())
|
||||
.buildAndExpand(appName, id)
|
||||
.toUri();
|
||||
|
||||
ResponseEntity<Void> response = restTemplate.exchange(uri, HttpMethod.PUT, null, Void.class);
|
||||
|
||||
return anEurekaHttpResponse(response.getStatusCode().value()).headers(headersOf(response)).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public EurekaHttpResponse<Void> deleteStatusOverride(String appName, String id, InstanceInfo info) {
|
||||
URI uri = UriComponentsBuilder.fromHttpUrl(serviceUrl)
|
||||
.path("apps/{appName}/{id}/status")
|
||||
.queryParam("lastDirtyTimestamp", info.getLastDirtyTimestamp().toString())
|
||||
.buildAndExpand(appName, id)
|
||||
.toUri();
|
||||
|
||||
ResponseEntity<Void> response = restTemplate.exchange(uri, HttpMethod.DELETE, null, Void.class);
|
||||
|
||||
return anEurekaHttpResponse(response.getStatusCode().value()).headers(headersOf(response)).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public EurekaHttpResponse<Applications> getApplications(String... regions) {
|
||||
return getApplicationsInternal("apps/", regions);
|
||||
}
|
||||
|
||||
private EurekaHttpResponse<Applications> getApplicationsInternal(String urlPath, String[] regions) {
|
||||
UriComponentsBuilder uriBuilder = UriComponentsBuilder.fromHttpUrl(serviceUrl).path(urlPath);
|
||||
|
||||
if (regions != null && regions.length > 0) {
|
||||
uriBuilder = uriBuilder.queryParam("regions", StringUtil.join(regions));
|
||||
}
|
||||
|
||||
URI uri = uriBuilder.build().toUri();
|
||||
|
||||
ResponseEntity<EurekaApplications> response = restTemplate.exchange(uri, HttpMethod.GET, null,
|
||||
EurekaApplications.class);
|
||||
|
||||
return anEurekaHttpResponse(response.getStatusCode().value(),
|
||||
response.getStatusCode().value() == HttpStatus.OK.value() && response.hasBody()
|
||||
? (Applications) response.getBody() : null)
|
||||
.headers(headersOf(response))
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public EurekaHttpResponse<Applications> getDelta(String... regions) {
|
||||
return getApplicationsInternal("apps/delta", regions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EurekaHttpResponse<Applications> getVip(String vipAddress, String... regions) {
|
||||
return getApplicationsInternal("vips/" + vipAddress, regions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EurekaHttpResponse<Applications> getSecureVip(String secureVipAddress, String... regions) {
|
||||
return getApplicationsInternal("svips/" + secureVipAddress, regions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EurekaHttpResponse<Application> getApplication(String appName) {
|
||||
URI uri = UriComponentsBuilder.fromHttpUrl(serviceUrl).path("apps/{appName}").buildAndExpand(appName).toUri();
|
||||
|
||||
ResponseEntity<Application> response = restTemplate.exchange(uri, HttpMethod.GET, null, Application.class);
|
||||
|
||||
Application application = response.getStatusCode().value() == HttpStatus.OK.value() && response.hasBody()
|
||||
? response.getBody() : null;
|
||||
|
||||
return anEurekaHttpResponse(response.getStatusCode().value(), application).headers(headersOf(response)).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public EurekaHttpResponse<InstanceInfo> getInstance(String appName, String id) {
|
||||
return getInstanceInternal("apps", appName, id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EurekaHttpResponse<InstanceInfo> getInstance(String id) {
|
||||
return getInstanceInternal("instances", id);
|
||||
}
|
||||
|
||||
private EurekaHttpResponse<InstanceInfo> getInstanceInternal(String... pathSegments) {
|
||||
URI uri = UriComponentsBuilder.fromHttpUrl(serviceUrl).pathSegment(pathSegments).build().toUri();
|
||||
|
||||
ResponseEntity<InstanceInfo> response = restTemplate.exchange(uri, HttpMethod.GET, null, InstanceInfo.class);
|
||||
|
||||
return anEurekaHttpResponse(response.getStatusCode().value(),
|
||||
response.getStatusCode().value() == HttpStatus.OK.value() && response.hasBody() ? response.getBody()
|
||||
: null)
|
||||
.headers(headersOf(response))
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shutdown() {
|
||||
// Nothing to do
|
||||
}
|
||||
|
||||
private static Map<String, String> headersOf(ResponseEntity<?> response) {
|
||||
HttpHeaders httpHeaders = response.getHeaders();
|
||||
if (httpHeaders == null || httpHeaders.isEmpty()) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
Map<String, String> headers = new HashMap<>();
|
||||
for (Entry<String, List<String>> entry : httpHeaders.entrySet()) {
|
||||
if (!entry.getValue().isEmpty()) {
|
||||
headers.put(entry.getKey(), entry.getValue().get(0));
|
||||
}
|
||||
}
|
||||
return headers;
|
||||
}
|
||||
|
||||
}
|
||||
-63
@@ -1,63 +0,0 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.eureka.http;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Optional;
|
||||
|
||||
import javax.net.ssl.HostnameVerifier;
|
||||
import javax.net.ssl.SSLContext;
|
||||
|
||||
import com.netflix.appinfo.InstanceInfo;
|
||||
import com.netflix.discovery.EurekaClientConfig;
|
||||
import com.netflix.discovery.shared.transport.TransportClientFactory;
|
||||
import com.netflix.discovery.shared.transport.jersey.TransportClientFactories;
|
||||
|
||||
import org.springframework.web.client.RestClient;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
/**
|
||||
* @author Daniel Lavoie
|
||||
* @author Armin Krezovic
|
||||
* @deprecated {@link RestTemplate}-based implementation to be removed in favour of
|
||||
* {@link RestClient}-based implementation.
|
||||
*/
|
||||
@Deprecated(forRemoval = true)
|
||||
public class RestTemplateTransportClientFactories implements TransportClientFactories<Void> {
|
||||
|
||||
private final RestTemplateDiscoveryClientOptionalArgs args;
|
||||
|
||||
public RestTemplateTransportClientFactories(RestTemplateDiscoveryClientOptionalArgs args) {
|
||||
this.args = args;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TransportClientFactory newTransportClientFactory(EurekaClientConfig clientConfig,
|
||||
Collection<Void> additionalFilters, InstanceInfo myInstanceInfo) {
|
||||
return new RestTemplateTransportClientFactory(args.getSSLContext(), args.getHostnameVerifier(),
|
||||
args.eurekaClientHttpRequestFactorySupplier, args.restTemplateBuilderSupplier);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TransportClientFactory newTransportClientFactory(final EurekaClientConfig clientConfig,
|
||||
final Collection<Void> additionalFilters, final InstanceInfo myInstanceInfo,
|
||||
final Optional<SSLContext> sslContext, final Optional<HostnameVerifier> hostnameVerifier) {
|
||||
return new RestTemplateTransportClientFactory(args.getSSLContext(), args.getHostnameVerifier(),
|
||||
args.eurekaClientHttpRequestFactorySupplier, args.restTemplateBuilderSupplier);
|
||||
}
|
||||
|
||||
}
|
||||
-177
@@ -1,177 +0,0 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.eureka.http;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import javax.net.ssl.HostnameVerifier;
|
||||
import javax.net.ssl.SSLContext;
|
||||
|
||||
import com.netflix.discovery.shared.resolver.EurekaEndpoint;
|
||||
import com.netflix.discovery.shared.transport.EurekaHttpClient;
|
||||
import com.netflix.discovery.shared.transport.TransportClientFactory;
|
||||
|
||||
import org.springframework.boot.web.client.RestTemplateBuilder;
|
||||
import org.springframework.cloud.configuration.TlsProperties;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.HttpStatusCode;
|
||||
import org.springframework.http.client.ClientHttpRequestFactory;
|
||||
import org.springframework.http.client.ClientHttpResponse;
|
||||
import org.springframework.http.client.support.BasicAuthenticationInterceptor;
|
||||
import org.springframework.web.client.DefaultResponseErrorHandler;
|
||||
import org.springframework.web.client.RestClient;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
import org.springframework.web.util.UriComponentsBuilder;
|
||||
|
||||
import static org.springframework.cloud.netflix.eureka.http.EurekaHttpClientUtils.context;
|
||||
import static org.springframework.cloud.netflix.eureka.http.EurekaHttpClientUtils.extractUserInfo;
|
||||
import static org.springframework.cloud.netflix.eureka.http.EurekaHttpClientUtils.mappingJacksonHttpMessageConverter;
|
||||
|
||||
/**
|
||||
* Provides the custom {@link RestTemplate} required by the
|
||||
* {@link RestTemplateEurekaHttpClient}. Relies on Jackson for serialization and
|
||||
* deserialization.
|
||||
*
|
||||
* @author Daniel Lavoie
|
||||
* @author Armin Krezovic
|
||||
* @author Wonchul Heo
|
||||
* @author Olga Maciaszek-Sharma
|
||||
* @deprecated {@link RestTemplate}-based implementation to be removed in favour of
|
||||
* {@link RestClient}-based implementation.
|
||||
*/
|
||||
@Deprecated(forRemoval = true)
|
||||
public class RestTemplateTransportClientFactory implements TransportClientFactory {
|
||||
|
||||
private final Optional<SSLContext> sslContext;
|
||||
|
||||
private final Optional<HostnameVerifier> hostnameVerifier;
|
||||
|
||||
private final EurekaClientHttpRequestFactorySupplier eurekaClientHttpRequestFactorySupplier;
|
||||
|
||||
private final Supplier<RestTemplateBuilder> restTemplateBuilderSupplier;
|
||||
|
||||
public RestTemplateTransportClientFactory(Optional<SSLContext> sslContext,
|
||||
Optional<HostnameVerifier> hostnameVerifier,
|
||||
EurekaClientHttpRequestFactorySupplier eurekaClientHttpRequestFactorySupplier,
|
||||
Supplier<RestTemplateBuilder> restTemplateBuilderSupplier) {
|
||||
this.sslContext = sslContext;
|
||||
this.hostnameVerifier = hostnameVerifier;
|
||||
this.eurekaClientHttpRequestFactorySupplier = eurekaClientHttpRequestFactorySupplier;
|
||||
this.restTemplateBuilderSupplier = restTemplateBuilderSupplier;
|
||||
}
|
||||
|
||||
public RestTemplateTransportClientFactory(TlsProperties tlsProperties,
|
||||
EurekaClientHttpRequestFactorySupplier eurekaClientHttpRequestFactorySupplier,
|
||||
Supplier<RestTemplateBuilder> restTemplateBuilderSupplier) {
|
||||
this(context(tlsProperties), Optional.empty(), eurekaClientHttpRequestFactorySupplier,
|
||||
restTemplateBuilderSupplier);
|
||||
}
|
||||
|
||||
public RestTemplateTransportClientFactory(TlsProperties tlsProperties,
|
||||
EurekaClientHttpRequestFactorySupplier eurekaClientHttpRequestFactorySupplier) {
|
||||
this(tlsProperties, eurekaClientHttpRequestFactorySupplier, RestTemplateBuilder::new);
|
||||
}
|
||||
|
||||
public RestTemplateTransportClientFactory(Optional<SSLContext> sslContext,
|
||||
Optional<HostnameVerifier> hostnameVerifier,
|
||||
EurekaClientHttpRequestFactorySupplier eurekaClientHttpRequestFactorySupplier) {
|
||||
|
||||
this(sslContext, hostnameVerifier, eurekaClientHttpRequestFactorySupplier, RestTemplateBuilder::new);
|
||||
}
|
||||
|
||||
// Visible for testing
|
||||
/**
|
||||
* @deprecated pass the default values while initialising object in test classes.
|
||||
*/
|
||||
@Deprecated(forRemoval = true)
|
||||
public RestTemplateTransportClientFactory() {
|
||||
this(Optional.empty(), Optional.empty(), new DefaultEurekaClientHttpRequestFactorySupplier());
|
||||
}
|
||||
|
||||
@Override
|
||||
public EurekaHttpClient newClient(EurekaEndpoint serviceUrl) {
|
||||
return new RestTemplateEurekaHttpClient(restTemplate(serviceUrl.getServiceUrl()),
|
||||
stripUserInfo(serviceUrl.getServiceUrl()));
|
||||
}
|
||||
|
||||
// apache http client 5.2 fails with non-null userinfo
|
||||
// basic auth added in restTemplate() below
|
||||
private String stripUserInfo(String serviceUrl) {
|
||||
return UriComponentsBuilder.fromUriString(serviceUrl).userInfo(null).toUriString();
|
||||
}
|
||||
|
||||
private RestTemplate restTemplate(String serviceUrl) {
|
||||
ClientHttpRequestFactory requestFactory = this.eurekaClientHttpRequestFactorySupplier
|
||||
.get(this.sslContext.orElse(null), this.hostnameVerifier.orElse(null));
|
||||
|
||||
RestTemplate restTemplate;
|
||||
|
||||
if (restTemplateBuilderSupplier != null && restTemplateBuilderSupplier.get() != null) {
|
||||
// Avoid using RestTemplateBuilder.requestFactory(() -> requestFactory)
|
||||
// when we have a concrete type, the reflective builder can throw errors if
|
||||
// there is custom configuration (ie Redirects.DONT_FOLLOW) gh-4423
|
||||
restTemplate = restTemplateBuilderSupplier.get().build();
|
||||
restTemplate.setRequestFactory(requestFactory);
|
||||
}
|
||||
else {
|
||||
restTemplate = new RestTemplate(requestFactory);
|
||||
}
|
||||
|
||||
final EurekaHttpClientUtils.UserInfo userInfo = extractUserInfo(serviceUrl);
|
||||
if (userInfo != null) {
|
||||
restTemplate.getInterceptors()
|
||||
.add(new BasicAuthenticationInterceptor(userInfo.username(), userInfo.password()));
|
||||
}
|
||||
|
||||
restTemplate.getMessageConverters().add(0, mappingJacksonHttpMessageConverter());
|
||||
restTemplate.setErrorHandler(new ErrorHandler());
|
||||
|
||||
restTemplate.getInterceptors().add((request, body, execution) -> {
|
||||
ClientHttpResponse response = execution.execute(request, body);
|
||||
if (!response.getStatusCode().equals(HttpStatus.NOT_FOUND)) {
|
||||
return response;
|
||||
}
|
||||
return new NotFoundHttpResponse(response);
|
||||
});
|
||||
|
||||
return restTemplate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shutdown() {
|
||||
}
|
||||
|
||||
class ErrorHandler extends DefaultResponseErrorHandler {
|
||||
|
||||
@Override
|
||||
protected boolean hasError(HttpStatusCode statusCode) {
|
||||
/**
|
||||
* When the Eureka server restarts and a client tries to send a heartbeat the
|
||||
* server will respond with a 404. By default, RestTemplate will throw an
|
||||
* exception in this case. What we want is to return the 404 to the upstream
|
||||
* code, so it will send another registration request to the server.
|
||||
*/
|
||||
if (statusCode.is4xxClientError()) {
|
||||
return false;
|
||||
}
|
||||
return super.hasError(statusCode);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+1
-1
@@ -52,7 +52,7 @@ public class WebClientTransportClientFactories implements TransportClientFactori
|
||||
public TransportClientFactory newTransportClientFactory(final EurekaClientConfig clientConfig,
|
||||
final Collection<Void> additionalFilters, final InstanceInfo myInstanceInfo,
|
||||
final Optional<SSLContext> sslContext, final Optional<HostnameVerifier> hostnameVerifier) {
|
||||
return new WebClientTransportClientFactory(builder);
|
||||
return new WebClientTransportClientFactory(builder, sslContext, hostnameVerifier);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+54
-2
@@ -16,15 +16,25 @@
|
||||
|
||||
package org.springframework.cloud.netflix.eureka.http;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import javax.net.ssl.HostnameVerifier;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.SSLEngine;
|
||||
import javax.net.ssl.SSLPeerUnverifiedException;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.netflix.discovery.shared.resolver.EurekaEndpoint;
|
||||
import com.netflix.discovery.shared.transport.EurekaHttpClient;
|
||||
import com.netflix.discovery.shared.transport.TransportClientFactory;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.handler.ssl.ClientAuth;
|
||||
import io.netty.handler.ssl.JdkSslContext;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.netty.http.client.HttpClient;
|
||||
import reactor.netty.http.client.HttpClientSecurityUtils;
|
||||
import reactor.netty.resources.ConnectionProvider;
|
||||
import reactor.netty.resources.LoopResources;
|
||||
|
||||
@@ -52,17 +62,29 @@ import static org.springframework.cloud.netflix.eureka.http.EurekaHttpClientUtil
|
||||
* @author Haytham Mohamed
|
||||
* @author Armin Krezovic
|
||||
* @author Wonchul Heo
|
||||
* @author Olga Maciaszek-Sharma
|
||||
*/
|
||||
public class WebClientTransportClientFactory implements TransportClientFactory {
|
||||
|
||||
private final Supplier<WebClient.Builder> builderSupplier;
|
||||
|
||||
private final Optional<SSLContext> sslContext;
|
||||
|
||||
private final Optional<HostnameVerifier> hostnameVerifier;
|
||||
|
||||
private final ConnectionProvider connectionProvider;
|
||||
|
||||
private final LoopResources loopResources;
|
||||
|
||||
public WebClientTransportClientFactory(Supplier<WebClient.Builder> builderSupplier) {
|
||||
this(builderSupplier, Optional.empty(), Optional.empty());
|
||||
}
|
||||
|
||||
public WebClientTransportClientFactory(Supplier<WebClient.Builder> builderSupplier, Optional<SSLContext> sslContext,
|
||||
Optional<HostnameVerifier> hostnameVerifier) {
|
||||
this.builderSupplier = builderSupplier;
|
||||
this.sslContext = sslContext;
|
||||
this.hostnameVerifier = hostnameVerifier;
|
||||
this.connectionProvider = ConnectionProvider.create("eureka-webclient");
|
||||
this.loopResources = LoopResources.create("eureka-webclient");
|
||||
}
|
||||
@@ -77,8 +99,36 @@ public class WebClientTransportClientFactory implements TransportClientFactory {
|
||||
// Use dedicated Reactor Netty resources independent of the reactive web server
|
||||
// to prevent RejectedExecutionException during graceful shutdown when the
|
||||
// server's event loop terminates before DiscoveryClient deregisters.
|
||||
builder.clientConnector(
|
||||
new ReactorClientHttpConnector(HttpClient.create(this.connectionProvider).runOn(this.loopResources)));
|
||||
HttpClient httpClient = HttpClient.create(this.connectionProvider).runOn(this.loopResources);
|
||||
|
||||
if (this.sslContext.isPresent()) {
|
||||
JdkSslContext sslContext = new JdkSslContext(this.sslContext.get(), true, ClientAuth.NONE);
|
||||
|
||||
httpClient = httpClient.secure(sslContextSpec -> {
|
||||
if (this.hostnameVerifier.isPresent()) {
|
||||
HostnameVerifier verifier = this.hostnameVerifier.get();
|
||||
sslContextSpec.sslContext(sslContext)
|
||||
.handlerConfigurator(sslHandler -> sslHandler.handshakeFuture().addListener(handshake -> {
|
||||
if (handshake.isSuccess()) {
|
||||
SSLEngine engine = sslHandler.engine();
|
||||
if (!verifier.verify(engine.getPeerHost(), engine.getSession())) {
|
||||
Channel channel = (Channel) handshake.getNow();
|
||||
channel.pipeline()
|
||||
.fireExceptionCaught(new SSLPeerUnverifiedException(
|
||||
"Hostname verification failed for " + engine.getPeerHost()));
|
||||
channel.close();
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
else {
|
||||
sslContextSpec.sslContext(sslContext)
|
||||
.handlerConfigurator(HttpClientSecurityUtils.HOSTNAME_VERIFICATION_CONFIGURER);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
builder.clientConnector(new ReactorClientHttpConnector(httpClient));
|
||||
return new WebClientEurekaHttpClient(builder.build());
|
||||
}
|
||||
|
||||
@@ -96,6 +146,8 @@ public class WebClientTransportClientFactory implements TransportClientFactory {
|
||||
ObjectMapper objectMapper = objectMapper();
|
||||
builder.codecs(configurer -> {
|
||||
ClientCodecConfigurer.ClientDefaultCodecs defaults = configurer.defaultCodecs();
|
||||
defaults.jacksonJsonDecoder(new Jackson2JsonDecoder(objectMapper, MediaType.APPLICATION_JSON));
|
||||
defaults.jacksonJsonEncoder(new Jackson2JsonEncoder(objectMapper, MediaType.APPLICATION_JSON));
|
||||
defaults.jackson2JsonEncoder(new Jackson2JsonEncoder(objectMapper, MediaType.APPLICATION_JSON));
|
||||
defaults.jackson2JsonDecoder(new Jackson2JsonDecoder(objectMapper, MediaType.APPLICATION_JSON));
|
||||
|
||||
|
||||
+1
-1
@@ -61,7 +61,7 @@ public class EurekaReactiveDiscoveryClientConfiguration {
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnClass(name = "org.springframework.boot.actuate.health.ReactiveHealthIndicator")
|
||||
@ConditionalOnClass(name = "org.springframework.boot.health.contributor.ReactiveHealthIndicator")
|
||||
@ConditionalOnDiscoveryHealthIndicatorEnabled
|
||||
public ReactiveDiscoveryClientHealthIndicator eurekaReactiveDiscoveryClientHealthIndicator(
|
||||
EurekaReactiveDiscoveryClient client, DiscoveryClientHealthIndicatorProperties properties) {
|
||||
|
||||
+1
-1
@@ -22,7 +22,7 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.boot.web.context.WebServerInitializedEvent;
|
||||
import org.springframework.boot.web.server.context.WebServerInitializedEvent;
|
||||
import org.springframework.cloud.client.discovery.event.InstancePreRegisteredEvent;
|
||||
import org.springframework.cloud.client.discovery.event.InstanceRegisteredEvent;
|
||||
import org.springframework.cloud.client.serviceregistry.AutoServiceRegistration;
|
||||
|
||||
+2
-2
@@ -32,7 +32,7 @@ import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.aop.framework.Advised;
|
||||
import org.springframework.aop.support.AopUtils;
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.cloud.client.DefaultServiceInstance;
|
||||
import org.springframework.cloud.client.ServiceInstance;
|
||||
import org.springframework.cloud.client.serviceregistry.Registration;
|
||||
import org.springframework.cloud.netflix.eureka.CloudEurekaClient;
|
||||
import org.springframework.cloud.netflix.eureka.CloudEurekaInstanceConfig;
|
||||
@@ -102,7 +102,7 @@ public class EurekaRegistration implements Registration {
|
||||
|
||||
@Override
|
||||
public URI getUri() {
|
||||
return DefaultServiceInstance.getUri(this);
|
||||
return ServiceInstance.createUri(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
-6
@@ -12,12 +12,6 @@
|
||||
"description": "Determines whether the EurekaClient instance can be refreshed or not(If disabled none of the Eureka client properties will be refreshable).",
|
||||
"type": "java.lang.Boolean"
|
||||
},
|
||||
{
|
||||
"defaultValue": false,
|
||||
"name": "eureka.client.restclient.enabled",
|
||||
"description": "Enables the use of RestClient for Eureka HTTP Client.",
|
||||
"type": "java.lang.Boolean"
|
||||
},
|
||||
{
|
||||
"defaultValue": false,
|
||||
"name": "eureka.client.webclient.enabled",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
org.springframework.cloud.bootstrap.BootstrapConfiguration=\
|
||||
org.springframework.cloud.netflix.eureka.config.EurekaConfigServerBootstrapConfiguration
|
||||
|
||||
org.springframework.boot.BootstrapRegistryInitializer=\
|
||||
org.springframework.boot.bootstrap.BootstrapRegistryInitializer=\
|
||||
org.springframework.cloud.netflix.eureka.config.EurekaConfigServerBootstrapper
|
||||
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright 2025-present the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.eureka;
|
||||
|
||||
import com.netflix.discovery.EurekaClient;
|
||||
import com.netflix.discovery.shared.Applications;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThatCode;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* @author Mohamed Macow
|
||||
*/
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class EurekaDiscoveryClientTests {
|
||||
|
||||
@Mock
|
||||
private EurekaClient eurekaClient;
|
||||
|
||||
@InjectMocks
|
||||
private EurekaDiscoveryClient client;
|
||||
|
||||
@Test
|
||||
void shouldCompleteProbeWhenClientHealthy() {
|
||||
when(eurekaClient.getApplications()).thenReturn(new Applications());
|
||||
|
||||
assertThatCode(() -> client.probe()).doesNotThrowAnyException();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldThrowProbeWhenClientThrows() {
|
||||
RuntimeException eurekaException = new RuntimeException("exception");
|
||||
when(eurekaClient.getApplications()).thenThrow(eurekaException);
|
||||
|
||||
assertThatExceptionOfType(eurekaException.getClass()).isThrownBy(() -> client.probe())
|
||||
.withMessage(eurekaException.getMessage());
|
||||
}
|
||||
|
||||
}
|
||||
+51
-23
@@ -17,30 +17,32 @@
|
||||
package org.springframework.cloud.netflix.eureka;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import com.netflix.appinfo.InstanceInfo.InstanceStatus;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.boot.actuate.health.AbstractHealthIndicator;
|
||||
import org.springframework.boot.actuate.health.AbstractReactiveHealthIndicator;
|
||||
import org.springframework.boot.actuate.health.CompositeHealthContributor;
|
||||
import org.springframework.boot.actuate.health.Health;
|
||||
import org.springframework.boot.actuate.health.HealthContributor;
|
||||
import org.springframework.boot.actuate.health.HealthIndicator;
|
||||
import org.springframework.boot.actuate.health.NamedContributor;
|
||||
import org.springframework.boot.actuate.health.ReactiveHealthIndicator;
|
||||
import org.springframework.boot.actuate.health.SimpleStatusAggregator;
|
||||
import org.springframework.boot.health.actuate.endpoint.SimpleStatusAggregator;
|
||||
import org.springframework.boot.health.contributor.AbstractHealthIndicator;
|
||||
import org.springframework.boot.health.contributor.AbstractReactiveHealthIndicator;
|
||||
import org.springframework.boot.health.contributor.CompositeHealthContributor;
|
||||
import org.springframework.boot.health.contributor.CompositeReactiveHealthContributor;
|
||||
import org.springframework.boot.health.contributor.Health;
|
||||
import org.springframework.boot.health.contributor.HealthContributor;
|
||||
import org.springframework.boot.health.contributor.HealthContributors;
|
||||
import org.springframework.boot.health.contributor.HealthIndicator;
|
||||
import org.springframework.boot.health.contributor.ReactiveHealthIndicator;
|
||||
import org.springframework.cloud.client.discovery.health.DiscoveryClientHealthIndicator;
|
||||
import org.springframework.cloud.client.discovery.health.DiscoveryCompositeHealthContributor;
|
||||
import org.springframework.cloud.client.discovery.health.DiscoveryHealthIndicator;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@@ -195,6 +197,33 @@ class EurekaHealthCheckHandlerTests {
|
||||
|
||||
}
|
||||
|
||||
public static class NamedUpHealthConfiguration {
|
||||
|
||||
@Bean
|
||||
public HealthIndicator upHealthIndicator() {
|
||||
return () -> Health.up().build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class NamedDownHealthConfiguration {
|
||||
|
||||
@Bean
|
||||
public HealthIndicator downHealthIndicator() {
|
||||
return () -> Health.down().build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class NamedReactiveUpHealthConfiguration {
|
||||
|
||||
@Bean
|
||||
public ReactiveHealthIndicator reactiveUpHealthIndicator() {
|
||||
return () -> Mono.just(Health.up().build());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class FatalHealthConfiguration {
|
||||
|
||||
@Bean
|
||||
@@ -319,22 +348,21 @@ class EurekaHealthCheckHandlerTests {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<NamedContributor<HealthContributor>> iterator() {
|
||||
Iterator<Map.Entry<String, HealthContributor>> iterator = contributorMap.entrySet().iterator();
|
||||
return new Iterator<>() {
|
||||
public Stream<HealthContributors.Entry> stream() {
|
||||
return contributorMap.entrySet()
|
||||
.stream()
|
||||
.map((entry) -> new HealthContributors.Entry(entry.getKey(), entry.getValue()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return iterator.hasNext();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public NamedContributor<HealthContributor> next() {
|
||||
Map.Entry<String, HealthContributor> entry = iterator.next();
|
||||
return NamedContributor.of(entry.getKey(), entry.getValue());
|
||||
}
|
||||
@Configuration
|
||||
static class NamedReactiveDownHealthConfiguration {
|
||||
|
||||
};
|
||||
@Bean
|
||||
CompositeReactiveHealthContributor namedReactiveDownHealthContributor() {
|
||||
return CompositeReactiveHealthContributor.fromMap(Map.of("reactiveDownHealthIndicator",
|
||||
(ReactiveHealthIndicator) () -> Mono.just(Health.down().build())));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+1
-32
@@ -24,7 +24,6 @@ import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.cloud.netflix.eureka.http.RestClientEurekaHttpClient;
|
||||
import org.springframework.cloud.netflix.eureka.http.RestTemplateEurekaHttpClient;
|
||||
import org.springframework.cloud.netflix.eureka.http.WebClientEurekaHttpClient;
|
||||
import org.springframework.cloud.test.ClassPathExclusions;
|
||||
|
||||
@@ -36,27 +35,12 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
*/
|
||||
class EurekaConfigServerBootstrapConfigurationClientTests {
|
||||
|
||||
@Test
|
||||
void properBeansCreatedWhenRestTemplateEnabled() {
|
||||
new ApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(EurekaConfigServerBootstrapConfiguration.class))
|
||||
.withPropertyValues("spring.cloud.config.discovery.enabled=true")
|
||||
.withPropertyValues("eureka.client.enabled=true")
|
||||
.withPropertyValues("eureka.client.restclient.enabled=false")
|
||||
.run(context -> {
|
||||
assertThat(context).hasSingleBean(RestTemplateEurekaHttpClient.class);
|
||||
assertThat(context).doesNotHaveBean(RestClientEurekaHttpClient.class);
|
||||
assertThat(context).doesNotHaveBean(WebClientEurekaHttpClient.class);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void properBeansCreatedWhenRestClientEnabled() {
|
||||
new ApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(EurekaConfigServerBootstrapConfiguration.class))
|
||||
.withPropertyValues("spring.cloud.config.discovery.enabled=true")
|
||||
.withPropertyValues("eureka.client.enabled=true")
|
||||
.withPropertyValues("eureka.client.restclient.enabled=true")
|
||||
.run(context -> {
|
||||
assertThat(context).hasSingleBean(RestClientEurekaHttpClient.class);
|
||||
assertThat(context).doesNotHaveBean(WebClientEurekaHttpClient.class);
|
||||
@@ -80,21 +64,7 @@ class EurekaConfigServerBootstrapConfigurationClientTests {
|
||||
|
||||
@Nested
|
||||
@ClassPathExclusions({ "spring-webflux-*" })
|
||||
static class NoWebFlux {
|
||||
|
||||
@Test
|
||||
void properBeansCreatedWhenRestTemplateEnabled() {
|
||||
new ApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(EurekaConfigServerBootstrapConfiguration.class))
|
||||
.withPropertyValues("spring.cloud.config.discovery.enabled=true")
|
||||
.withPropertyValues("eureka.client.enabled=true")
|
||||
.withPropertyValues("eureka.client.restclient.enabled=false")
|
||||
.run(context -> {
|
||||
assertThat(context).hasSingleBean(RestTemplateEurekaHttpClient.class);
|
||||
assertThat(context).doesNotHaveBean(RestClientEurekaHttpClient.class);
|
||||
assertThat(context).doesNotHaveBean(WebClientEurekaHttpClient.class);
|
||||
});
|
||||
}
|
||||
class NoWebFlux {
|
||||
|
||||
@Test
|
||||
void properBeansCreatedWhenRestClientEnabled() {
|
||||
@@ -102,7 +72,6 @@ class EurekaConfigServerBootstrapConfigurationClientTests {
|
||||
.withConfiguration(AutoConfigurations.of(EurekaConfigServerBootstrapConfiguration.class))
|
||||
.withPropertyValues("spring.cloud.config.discovery.enabled=true")
|
||||
.withPropertyValues("eureka.client.enabled=true")
|
||||
.withPropertyValues("eureka.client.restclient.enabled=true")
|
||||
.run(context -> {
|
||||
assertThat(context).hasSingleBean(RestClientEurekaHttpClient.class);
|
||||
assertThat(context).doesNotHaveBean(WebClientEurekaHttpClient.class);
|
||||
|
||||
+2
-4
@@ -40,10 +40,8 @@ import static org.springframework.boot.test.context.SpringBootTest.WebEnvironmen
|
||||
/**
|
||||
* @author Wonchul Heo
|
||||
*/
|
||||
@SpringBootTest(
|
||||
properties = { "spring.cloud.config.discovery.enabled=true", "eureka.client.enabled=true",
|
||||
"spring.config.use-legacy-processing=true", "eureka.client.restclient.enabled=true" },
|
||||
webEnvironment = RANDOM_PORT)
|
||||
@SpringBootTest(properties = { "spring.cloud.config.discovery.enabled=true", "eureka.client.enabled=true",
|
||||
"spring.config.use-legacy-processing=true" }, webEnvironment = RANDOM_PORT)
|
||||
class EurekaConfigServerBootstrapConfigurationRestClientIntegrationTests {
|
||||
|
||||
@LocalServerPort
|
||||
|
||||
+2
-18
@@ -23,7 +23,6 @@ import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.cloud.config.client.ConfigServerInstanceProvider;
|
||||
import org.springframework.cloud.netflix.eureka.EurekaClientConfigBean;
|
||||
import org.springframework.cloud.netflix.eureka.http.RestClientEurekaHttpClient;
|
||||
import org.springframework.cloud.netflix.eureka.http.RestTemplateEurekaHttpClient;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@@ -33,11 +32,10 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
class EurekaConfigServerBootstrapConfigurationRestClientTests {
|
||||
|
||||
@Test
|
||||
void properBeansCreatedWhenEnabled() {
|
||||
void properBeansCreated() {
|
||||
new ApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(EurekaConfigServerBootstrapConfiguration.class))
|
||||
.withPropertyValues("spring.cloud.config.discovery.enabled=true", "eureka.client.enabled=true",
|
||||
"eureka.client.restclient.enabled=true")
|
||||
.withPropertyValues("spring.cloud.config.discovery.enabled=true", "eureka.client.enabled=true")
|
||||
.run(context -> {
|
||||
assertThat(context).hasSingleBean(EurekaClientConfigBean.class);
|
||||
assertThat(context).hasSingleBean(RestClientEurekaHttpClient.class);
|
||||
@@ -45,18 +43,4 @@ class EurekaConfigServerBootstrapConfigurationRestClientTests {
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void properBeansCreatedWhenEnabledRestClientDisabled() {
|
||||
new ApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(EurekaConfigServerBootstrapConfiguration.class))
|
||||
.withPropertyValues("spring.cloud.config.discovery.enabled=true", "eureka.client.enabled=true",
|
||||
"eureka.client.restclient.enabled=false")
|
||||
.run(context -> {
|
||||
assertThat(context).hasSingleBean(EurekaClientConfigBean.class);
|
||||
assertThat(context).doesNotHaveBean(RestClientEurekaHttpClient.class);
|
||||
assertThat(context).hasSingleBean(RestTemplateEurekaHttpClient.class);
|
||||
assertThat(context).hasSingleBean(ConfigServerInstanceProvider.Function.class);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+2
-2
@@ -39,7 +39,7 @@ import org.springframework.boot.test.system.OutputCaptureExtension;
|
||||
import org.springframework.cloud.config.client.ConfigServerInstanceProvider;
|
||||
import org.springframework.cloud.netflix.eureka.CloudEurekaClient;
|
||||
import org.springframework.cloud.netflix.eureka.EurekaClientConfigBean;
|
||||
import org.springframework.cloud.netflix.eureka.http.RestTemplateEurekaHttpClient;
|
||||
import org.springframework.cloud.netflix.eureka.http.RestClientEurekaHttpClient;
|
||||
import org.springframework.cloud.test.ClassPathExclusions;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
@@ -202,7 +202,7 @@ class EurekaConfigServerBootstrapConfigurationTests {
|
||||
|
||||
private void assertEurekaBeansPresent(AssertableApplicationContext context) {
|
||||
assertThat(context).hasSingleBean(EurekaClientConfigBean.class);
|
||||
assertThat(context).hasSingleBean(RestTemplateEurekaHttpClient.class);
|
||||
assertThat(context).hasSingleBean(RestClientEurekaHttpClient.class);
|
||||
assertThat(context).hasSingleBean(ConfigServerInstanceProvider.Function.class);
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -42,7 +42,7 @@ import static org.springframework.boot.test.context.SpringBootTest.WebEnvironmen
|
||||
*/
|
||||
@SpringBootTest(properties = { "spring.cloud.config.discovery.enabled=true", "eureka.client.enabled=true",
|
||||
"spring.config.use-legacy-processing=true", "eureka.client.webclient.enabled=true",
|
||||
"spring.codec.max-in-memory-size=310000" }, webEnvironment = RANDOM_PORT)
|
||||
"spring.http.codecs.max-in-memory-size=310000" }, webEnvironment = RANDOM_PORT)
|
||||
class EurekaConfigServerBootstrapConfigurationWebClientIntegrationTests {
|
||||
|
||||
@LocalServerPort
|
||||
|
||||
+2
-2
@@ -22,7 +22,7 @@ import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.cloud.config.client.ConfigServerInstanceProvider;
|
||||
import org.springframework.cloud.netflix.eureka.EurekaClientConfigBean;
|
||||
import org.springframework.cloud.netflix.eureka.http.RestTemplateEurekaHttpClient;
|
||||
import org.springframework.cloud.netflix.eureka.http.RestClientEurekaHttpClient;
|
||||
import org.springframework.cloud.netflix.eureka.http.WebClientEurekaHttpClient;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
@@ -54,7 +54,7 @@ class EurekaConfigServerBootstrapConfigurationWebClientTests {
|
||||
.run(context -> {
|
||||
assertThat(context).hasSingleBean(EurekaClientConfigBean.class);
|
||||
assertThat(context).doesNotHaveBean(WebClientEurekaHttpClient.class);
|
||||
assertThat(context).hasSingleBean(RestTemplateEurekaHttpClient.class);
|
||||
assertThat(context).hasSingleBean(RestClientEurekaHttpClient.class);
|
||||
assertThat(context).hasSingleBean(ConfigServerInstanceProvider.Function.class);
|
||||
});
|
||||
}
|
||||
|
||||
+3
-40
@@ -20,7 +20,6 @@ import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
|
||||
import org.springframework.cloud.netflix.eureka.http.RestClientDiscoveryClientOptionalArgs;
|
||||
import org.springframework.cloud.netflix.eureka.http.RestTemplateDiscoveryClientOptionalArgs;
|
||||
import org.springframework.cloud.netflix.eureka.http.WebClientDiscoveryClientOptionalArgs;
|
||||
import org.springframework.cloud.netflix.eureka.sample.EurekaSampleApplication;
|
||||
import org.springframework.cloud.test.ClassPathExclusions;
|
||||
@@ -35,25 +34,12 @@ import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat;
|
||||
class EurekaHttpClientsOptionalArgsConfigurationTests {
|
||||
|
||||
@Test
|
||||
void contextLoadsWithRestTemplateWhenWebClientDisabled() {
|
||||
public void contextLoadsWithRestClientWhenWebClientDisabled() {
|
||||
new WebApplicationContextRunner().withUserConfiguration(EurekaSampleApplication.class)
|
||||
.withPropertyValues("eureka.client.webclient.enabled=false")
|
||||
.withPropertyValues("eureka.client.restclient.enabled=false")
|
||||
.run(context -> {
|
||||
assertThat(context).hasSingleBean(RestTemplateDiscoveryClientOptionalArgs.class);
|
||||
assertThat(context).hasSingleBean(RestClientDiscoveryClientOptionalArgs.class);
|
||||
assertThat(context).doesNotHaveBean(WebClientDiscoveryClientOptionalArgs.class);
|
||||
assertThat(context).doesNotHaveBean(RestClientDiscoveryClientOptionalArgs.class);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void contextLoadsWithRestTemplateWhenRestClientDisabled() {
|
||||
new WebApplicationContextRunner().withUserConfiguration(EurekaSampleApplication.class)
|
||||
.withPropertyValues("eureka.client.restclient.enabled=false")
|
||||
.run(context -> {
|
||||
assertThat(context).hasSingleBean(RestTemplateDiscoveryClientOptionalArgs.class);
|
||||
assertThat(context).doesNotHaveBean(WebClientDiscoveryClientOptionalArgs.class);
|
||||
assertThat(context).doesNotHaveBean(RestClientDiscoveryClientOptionalArgs.class);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -62,31 +48,8 @@ class EurekaHttpClientsOptionalArgsConfigurationTests {
|
||||
new WebApplicationContextRunner().withUserConfiguration(EurekaSampleApplication.class)
|
||||
.withPropertyValues("eureka.client.webclient.enabled=true")
|
||||
.run(context -> {
|
||||
assertThat(context).doesNotHaveBean(RestTemplateDiscoveryClientOptionalArgs.class);
|
||||
assertThat(context).doesNotHaveBean(RestClientDiscoveryClientOptionalArgs.class);
|
||||
assertThat(context).hasSingleBean(WebClientDiscoveryClientOptionalArgs.class);
|
||||
assertThat(context).doesNotHaveBean(RestClientDiscoveryClientOptionalArgs.class);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void contextLoadsWithRestClient() {
|
||||
new WebApplicationContextRunner().withUserConfiguration(EurekaSampleApplication.class)
|
||||
.withPropertyValues("eureka.client.restclient.enabled=true")
|
||||
.run(context -> {
|
||||
assertThat(context).doesNotHaveBean(RestTemplateDiscoveryClientOptionalArgs.class);
|
||||
assertThat(context).doesNotHaveBean(WebClientDiscoveryClientOptionalArgs.class);
|
||||
assertThat(context).hasSingleBean(RestClientDiscoveryClientOptionalArgs.class);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void contextLoadsWithRestTemplateAsDefault() {
|
||||
new WebApplicationContextRunner().withUserConfiguration(EurekaSampleApplication.class)
|
||||
.withPropertyValues("eureka.client.restclient.enabled=false")
|
||||
.run(context -> {
|
||||
assertThat(context).hasSingleBean(RestTemplateDiscoveryClientOptionalArgs.class);
|
||||
assertThat(context).doesNotHaveBean(WebClientDiscoveryClientOptionalArgs.class);
|
||||
assertThat(context).doesNotHaveBean(RestClientDiscoveryClientOptionalArgs.class);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
+4
-5
@@ -21,7 +21,7 @@ import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.cloud.netflix.eureka.http.RestTemplateDiscoveryClientOptionalArgs;
|
||||
import org.springframework.cloud.netflix.eureka.http.RestClientDiscoveryClientOptionalArgs;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@@ -30,12 +30,11 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
*
|
||||
* @author Olga Maciaszek-Sharma
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public class JerseyClientOptionalArgsConfigurationTests {
|
||||
|
||||
@SuppressWarnings("OptionalGetWithoutIsPresent")
|
||||
@Test
|
||||
void shouldCreateRestTemplateDiscoveryClientOptionalArgsWhenJerseyClientDisabled() {
|
||||
void shouldCreateRestClientDiscoveryClientOptionalArgsWhenJerseyClientDisabled() {
|
||||
new ApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(DiscoveryClientOptionalArgsConfiguration.class))
|
||||
.withPropertyValues("eureka.client.jersey.enabled=false")
|
||||
@@ -45,8 +44,8 @@ public class JerseyClientOptionalArgsConfigurationTests {
|
||||
.values()
|
||||
.stream()
|
||||
.findFirst()
|
||||
.get()).isInstanceOf(RestTemplateDiscoveryClientOptionalArgs.class);
|
||||
assertThat(context).hasSingleBean(RestTemplateDiscoveryClientOptionalArgs.class);
|
||||
.get()).isInstanceOf(RestClientDiscoveryClientOptionalArgs.class);
|
||||
assertThat(context).hasSingleBean(RestClientDiscoveryClientOptionalArgs.class);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
+3
-3
@@ -21,9 +21,9 @@ import com.netflix.discovery.EurekaClient;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.actuate.health.Health;
|
||||
import org.springframework.boot.actuate.health.HealthIndicator;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.health.contributor.Health;
|
||||
import org.springframework.boot.health.contributor.HealthIndicator;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
@@ -73,7 +73,7 @@ class EurekaHealthCheckTests {
|
||||
protected static class EurekaHealthCheckApplication {
|
||||
|
||||
@Bean
|
||||
public HealthIndicator healthIndicator() {
|
||||
public HealthIndicator exampleHealthIndicator() {
|
||||
return () -> new Health.Builder().status(System.getProperty("status")).build();
|
||||
}
|
||||
|
||||
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright 2013-present the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.eureka.http;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.cloud.netflix.eureka.TimeoutProperties;
|
||||
import org.springframework.http.client.ClientHttpRequestFactory;
|
||||
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link DefaultEurekaClientHttpRequestFactorySupplier}.
|
||||
*
|
||||
* <p>
|
||||
* These specifically guard against regressing gh-4275: an earlier fix (gh-4258) made this
|
||||
* class a Spring {@code DisposableBean}, which raced with
|
||||
* {@code CloudEurekaClient#shutdown()} during context shutdown and broke
|
||||
* unregister-on-shutdown. That fix was reverted, and this supplier is now intentionally
|
||||
* stateless (gh-4569): it never caches or closes an HTTP client itself. Lifecycle
|
||||
* management of the shared client belongs to the owning
|
||||
* {@link RestClientTransportClientFactory}, which is already scoped to a single Eureka
|
||||
* client - see {@link RestClientTransportClientFactoryShutdownTests}.
|
||||
*/
|
||||
class DefaultEurekaClientHttpRequestFactorySupplierTests {
|
||||
|
||||
private final DefaultEurekaClientHttpRequestFactorySupplier supplier = new DefaultEurekaClientHttpRequestFactorySupplier(
|
||||
new TimeoutProperties(), Collections.emptySet());
|
||||
|
||||
@Test
|
||||
void shouldNotBeADisposableBean() {
|
||||
// Guard against reintroducing gh-4275: this class must not be destroyed via an
|
||||
// independent Spring bean-destroy callback.
|
||||
assertThat(supplier).isNotInstanceOf(DisposableBean.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getShouldReturnANonNullRequestFactory() {
|
||||
ClientHttpRequestFactory requestFactory = supplier.get(null, null);
|
||||
assertThat(requestFactory).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void getShouldBuildAFreshHttpClientOnEveryCall() {
|
||||
// The supplier is stateless - caching and lifecycle management belong to the
|
||||
// caller (RestClientTransportClientFactory), so every call must return an
|
||||
// independent client rather than a shared one.
|
||||
ClientHttpRequestFactory first = supplier.get(null, null);
|
||||
ClientHttpRequestFactory second = supplier.get(null, null);
|
||||
|
||||
Object firstHttpClient = ((HttpComponentsClientHttpRequestFactory) first).getHttpClient();
|
||||
Object secondHttpClient = ((HttpComponentsClientHttpRequestFactory) second).getHttpClient();
|
||||
|
||||
assertThat(firstHttpClient).isNotSameAs(secondHttpClient);
|
||||
}
|
||||
|
||||
}
|
||||
+15
-16
@@ -27,6 +27,7 @@ import com.netflix.discovery.shared.Application;
|
||||
import com.netflix.discovery.shared.Applications;
|
||||
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.http.converter.autoconfigure.ServerHttpMessageConvertersCustomizer;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.Ordered;
|
||||
@@ -34,7 +35,7 @@ import org.springframework.core.annotation.Order;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
|
||||
import org.springframework.security.config.Customizer;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.core.userdetails.User;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
@@ -110,15 +111,6 @@ public class EurekaServerMockApplication {
|
||||
.setNamespace("namespace1")
|
||||
.build();
|
||||
|
||||
/**
|
||||
* Simulates Eureka Server own's serialization.
|
||||
* @return converter
|
||||
*/
|
||||
@Bean
|
||||
public MappingJackson2HttpMessageConverter mappingJacksonHttpMessageConverter() {
|
||||
return EurekaHttpClientUtils.mappingJacksonHttpMessageConverter();
|
||||
}
|
||||
|
||||
@ResponseStatus(HttpStatus.OK)
|
||||
@PostMapping("/apps/{appName}")
|
||||
public void register(@PathVariable String appName, @RequestBody InstanceInfo instanceInfo) {
|
||||
@@ -177,7 +169,7 @@ public class EurekaServerMockApplication {
|
||||
@GetMapping("/apps/{appName}")
|
||||
public Application getApplication(@PathVariable String appName, @RequestHeader HttpHeaders headers) {
|
||||
// Used to verify that RequestConfig customizer has taken effect
|
||||
if (appName.equals("upgrade") && !headers.containsKey("upgrade")) {
|
||||
if (appName.equals("upgrade") && !headers.containsHeader("upgrade")) {
|
||||
throw new RuntimeException("No upgrade header found");
|
||||
}
|
||||
return new Application();
|
||||
@@ -188,6 +180,17 @@ public class EurekaServerMockApplication {
|
||||
return INFO;
|
||||
}
|
||||
|
||||
/*
|
||||
* Use this customizer to make sure we use the Jackson mappings for the Eureka server
|
||||
*/
|
||||
@Bean
|
||||
@Order
|
||||
ServerHttpMessageConvertersCustomizer customServerConvertersCustomizer() {
|
||||
return builder -> {
|
||||
builder.withJsonConverter(EurekaHttpClientUtils.mappingJacksonHttpMessageConverter());
|
||||
};
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@Order(Ordered.HIGHEST_PRECEDENCE)
|
||||
protected static class TestSecurityConfiguration {
|
||||
@@ -204,11 +207,7 @@ public class EurekaServerMockApplication {
|
||||
|
||||
@Bean
|
||||
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
|
||||
// @formatter:off
|
||||
http
|
||||
.securityMatcher("/v2/apps/**")
|
||||
.httpBasic();
|
||||
// @formatter:on
|
||||
http.securityMatcher("/v2/apps/**").httpBasic(Customizer.withDefaults());
|
||||
return http.build();
|
||||
}
|
||||
|
||||
|
||||
+10
-3
@@ -32,7 +32,7 @@ import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
|
||||
import org.springframework.cloud.commons.util.InetUtils;
|
||||
import org.springframework.cloud.netflix.eureka.EurekaInstanceConfigBean;
|
||||
import org.springframework.cloud.netflix.eureka.RestClientTimeoutProperties;
|
||||
import org.springframework.cloud.netflix.eureka.TimeoutProperties;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.web.client.RestClient;
|
||||
|
||||
@@ -46,7 +46,14 @@ import static org.assertj.core.api.AssertionsForClassTypes.assertThatExceptionOf
|
||||
*/
|
||||
@SpringBootTest(classes = EurekaServerMockApplication.class,
|
||||
properties = { "debug=true", "security.basic.enabled=true", "eureka.client.fetch-registry=false",
|
||||
"eureka.client.register-with-eureka=false", "logging.level.org.springframework=INFO" },
|
||||
"eureka.client.register-with-eureka=false", "logging.level.org.springframework=INFO",
|
||||
// spring.http.converters.preferred-json-mapper=jackson2 is only necessary
|
||||
// to make the
|
||||
// mock Eureka Server used in this test to work
|
||||
// TODO we can likely remove this once this Boot issue is fixed post
|
||||
// 2025.1.0-RC1:
|
||||
// https://github.com/spring-projects/spring-boot/issues/47798
|
||||
"spring.http.converters.preferred-json-mapper=jackson2" },
|
||||
webEnvironment = WebEnvironment.RANDOM_PORT)
|
||||
@DirtiesContext
|
||||
class RestClientEurekaHttpClientTests extends AbstractEurekaHttpClientTests {
|
||||
@@ -88,7 +95,7 @@ class RestClientEurekaHttpClientTests extends AbstractEurekaHttpClientTests {
|
||||
private EurekaHttpClient buildEurekaHttpClient(
|
||||
Set<EurekaClientHttpRequestFactorySupplier.RequestConfigCustomizer> customizers) {
|
||||
return new RestClientTransportClientFactory(Optional.empty(), Optional.empty(),
|
||||
new DefaultEurekaClientHttpRequestFactorySupplier(new RestClientTimeoutProperties(), customizers),
|
||||
new DefaultEurekaClientHttpRequestFactorySupplier(new TimeoutProperties(), customizers),
|
||||
RestClient::builder)
|
||||
.newClient(new DefaultEndpoint(serviceUrl));
|
||||
}
|
||||
|
||||
+71
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.eureka.http;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import javax.net.ssl.HostnameVerifier;
|
||||
import javax.net.ssl.SSLContext;
|
||||
|
||||
import com.netflix.discovery.shared.resolver.DefaultEndpoint;
|
||||
import com.netflix.discovery.shared.transport.TransportClientFactory;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.http.client.SimpleClientHttpRequestFactory;
|
||||
import org.springframework.web.client.RestClient;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class RestClientTransportClientFactoriesTests {
|
||||
|
||||
@Test
|
||||
void shouldUseSslContextAndHostnameVerifierProvidedByDiscoveryClient() throws Exception {
|
||||
SSLContext sslContextFromArgs = SSLContext.getDefault();
|
||||
SSLContext sslContextFromDiscoveryClient = SSLContext.getInstance("TLS");
|
||||
sslContextFromDiscoveryClient.init(null, null, null);
|
||||
|
||||
HostnameVerifier hostnameVerifierFromArgs = (hostname, session) -> false;
|
||||
HostnameVerifier hostnameVerifierFromDiscoveryClient = (hostname, session) -> true;
|
||||
|
||||
AtomicReference<SSLContext> capturedSslContext = new AtomicReference<>();
|
||||
AtomicReference<HostnameVerifier> capturedHostnameVerifier = new AtomicReference<>();
|
||||
|
||||
EurekaClientHttpRequestFactorySupplier requestFactorySupplier = (sslContext, hostnameVerifier) -> {
|
||||
capturedSslContext.set(sslContext);
|
||||
capturedHostnameVerifier.set(hostnameVerifier);
|
||||
return new SimpleClientHttpRequestFactory();
|
||||
};
|
||||
|
||||
RestClientDiscoveryClientOptionalArgs args = new RestClientDiscoveryClientOptionalArgs(requestFactorySupplier,
|
||||
RestClient::builder);
|
||||
|
||||
args.setSSLContext(sslContextFromArgs);
|
||||
args.setHostnameVerifier(hostnameVerifierFromArgs);
|
||||
|
||||
RestClientTransportClientFactories factories = new RestClientTransportClientFactories(args);
|
||||
|
||||
TransportClientFactory transportClientFactory = factories.newTransportClientFactory(null, null, null,
|
||||
Optional.of(sslContextFromDiscoveryClient), Optional.of(hostnameVerifierFromDiscoveryClient));
|
||||
|
||||
transportClientFactory.newClient(new DefaultEndpoint("http://localhost"));
|
||||
|
||||
assertThat(capturedSslContext.get()).isSameAs(sslContextFromDiscoveryClient);
|
||||
assertThat(capturedHostnameVerifier.get()).isSameAs(hostnameVerifierFromDiscoveryClient);
|
||||
}
|
||||
|
||||
}
|
||||
+111
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright 2013-present the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.eureka.http;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.cloud.configuration.TlsProperties;
|
||||
import org.springframework.cloud.netflix.eureka.TimeoutProperties;
|
||||
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatCode;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* Tests that {@link RestClientTransportClientFactory} owns and deterministically closes
|
||||
* the shared HTTP client it lazily builds via
|
||||
* {@link EurekaClientHttpRequestFactorySupplier#get}, rather than delegating that
|
||||
* lifecycle to a potentially shared supplier instance (gh-4569).
|
||||
*
|
||||
* <p>
|
||||
* Since each {@code RestClientTransportClientFactory} is already scoped to a single
|
||||
* Eureka client, caching the client here means
|
||||
* {@link RestClientTransportClientFactory#shutdown()} only ever closes a client owned
|
||||
* exclusively by this factory - there is no shared-state hazard between a refreshed
|
||||
* client or a second, independently-created Eureka client, as there would be if the
|
||||
* client were cached in the supplier itself.
|
||||
*/
|
||||
class RestClientTransportClientFactoryShutdownTests {
|
||||
|
||||
private final DefaultEurekaClientHttpRequestFactorySupplier supplier = new DefaultEurekaClientHttpRequestFactorySupplier(
|
||||
new TimeoutProperties(), Collections.emptySet());
|
||||
|
||||
private final RestClientTransportClientFactory factory = new RestClientTransportClientFactory(new TlsProperties(),
|
||||
supplier);
|
||||
|
||||
@Test
|
||||
void shutdownBeforeAnyNewClientCallShouldNotThrow() {
|
||||
// shutdown() before newClient() (e.g. context shut down before any request was
|
||||
// ever made) must not throw.
|
||||
assertThatCode(factory::shutdown).doesNotThrowAnyException();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shutdownShouldBeIdempotent() {
|
||||
factory.newClient(endpoint());
|
||||
factory.shutdown();
|
||||
// Idempotent - shutdown paths may call shutdown() more than once.
|
||||
assertThatCode(factory::shutdown).doesNotThrowAnyException();
|
||||
}
|
||||
|
||||
@Test
|
||||
void repeatedNewClientCallsShouldReuseTheSameCachedRequestFactory() {
|
||||
// newClient() delegates to the same cached request factory on every call, rather
|
||||
// than asking the supplier for a fresh one each time.
|
||||
factory.newClient(endpoint());
|
||||
Object firstHttpClient = cachedHttpClient(factory);
|
||||
|
||||
factory.newClient(endpoint());
|
||||
Object secondHttpClient = cachedHttpClient(factory);
|
||||
|
||||
assertThat(firstHttpClient).isSameAs(secondHttpClient);
|
||||
}
|
||||
|
||||
private static com.netflix.discovery.shared.resolver.EurekaEndpoint endpoint() {
|
||||
com.netflix.discovery.shared.resolver.EurekaEndpoint endpoint = mock(
|
||||
com.netflix.discovery.shared.resolver.EurekaEndpoint.class);
|
||||
when(endpoint.getServiceUrl()).thenReturn("http://localhost:8761/eureka/");
|
||||
return endpoint;
|
||||
}
|
||||
|
||||
private static Object cachedHttpClient(RestClientTransportClientFactory factory) {
|
||||
Object requestFactory = org.springframework.test.util.ReflectionTestUtils.getField(factory,
|
||||
"cachedRequestFactory");
|
||||
return ((HttpComponentsClientHttpRequestFactory) requestFactory).getHttpClient();
|
||||
}
|
||||
|
||||
@Test
|
||||
void newClientAfterShutdownShouldCreateANewCachedRequestFactory() {
|
||||
factory.newClient(endpoint());
|
||||
Object httpClientBeforeShutdown = cachedHttpClient(factory);
|
||||
|
||||
factory.shutdown();
|
||||
|
||||
factory.newClient(endpoint());
|
||||
Object httpClientAfterShutdown = cachedHttpClient(factory);
|
||||
|
||||
// shutdown() clears the cached request factory, so a subsequent newClient()
|
||||
// call must lazily build a fresh one rather than reusing the client that was
|
||||
// just closed.
|
||||
assertThat(httpClientAfterShutdown).isNotSameAs(httpClientBeforeShutdown);
|
||||
}
|
||||
|
||||
}
|
||||
+2
-3
@@ -25,7 +25,7 @@ import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.cloud.netflix.eureka.RestClientTimeoutProperties;
|
||||
import org.springframework.cloud.netflix.eureka.TimeoutProperties;
|
||||
import org.springframework.web.client.RestClient;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
@@ -43,8 +43,7 @@ class RestClientTransportClientFactoryTests {
|
||||
@BeforeEach
|
||||
void setup() {
|
||||
transportClientFactory = new RestClientTransportClientFactory(Optional.empty(), Optional.empty(),
|
||||
new DefaultEurekaClientHttpRequestFactorySupplier(new RestClientTimeoutProperties(),
|
||||
Collections.emptySet()),
|
||||
new DefaultEurekaClientHttpRequestFactorySupplier(new TimeoutProperties(), Collections.emptySet()),
|
||||
RestClient::builder);
|
||||
}
|
||||
|
||||
|
||||
-85
@@ -1,85 +0,0 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.eureka.http;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.netflix.appinfo.providers.EurekaConfigBasedInstanceInfoProvider;
|
||||
import com.netflix.discovery.shared.resolver.DefaultEndpoint;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
|
||||
import org.springframework.cloud.commons.util.InetUtils;
|
||||
import org.springframework.cloud.netflix.eureka.EurekaInstanceConfigBean;
|
||||
import org.springframework.http.client.ClientHttpRequestInterceptor;
|
||||
import org.springframework.http.client.support.BasicAuthenticationInterceptor;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* @author Daniel Lavoie
|
||||
*/
|
||||
@SpringBootTest(classes = EurekaServerMockApplication.class,
|
||||
properties = { "debug=true", "security.basic.enabled=true", "eureka.client.fetch-registry=false",
|
||||
"eureka.client.register-with-eureka=false", "logging.level.org.springframework=INFO" },
|
||||
webEnvironment = WebEnvironment.RANDOM_PORT)
|
||||
@DirtiesContext
|
||||
class RestTemplateEurekaHttpClientTests extends AbstractEurekaHttpClientTests {
|
||||
|
||||
@Autowired
|
||||
private InetUtils inetUtils;
|
||||
|
||||
@Value("http://${security.user.name}:${security.user.password}@localhost:${local.server.port}/eureka")
|
||||
private String serviceUrl;
|
||||
|
||||
@BeforeEach
|
||||
void setup() {
|
||||
eurekaHttpClient = new RestTemplateTransportClientFactory().newClient(new DefaultEndpoint(serviceUrl));
|
||||
|
||||
EurekaInstanceConfigBean config = new EurekaInstanceConfigBean(inetUtils);
|
||||
|
||||
String appname = "customapp";
|
||||
config.setIpAddress("127.0.0.1");
|
||||
config.setHostname("localhost");
|
||||
config.setAppname(appname);
|
||||
config.setVirtualHostName(appname);
|
||||
config.setSecureVirtualHostName(appname);
|
||||
config.setNonSecurePort(4444);
|
||||
config.setSecurePort(8443);
|
||||
config.setInstanceId("127.0.0.1:customapp:4444");
|
||||
|
||||
info = new EurekaConfigBasedInstanceInfoProvider(config).get();
|
||||
}
|
||||
|
||||
@Test
|
||||
void basicAuth() {
|
||||
assertThat(eurekaHttpClient).isInstanceOf(RestTemplateEurekaHttpClient.class);
|
||||
RestTemplateEurekaHttpClient restTemplateEurekaHttpClient = (RestTemplateEurekaHttpClient) eurekaHttpClient;
|
||||
RestTemplate restTemplate = restTemplateEurekaHttpClient.getRestTemplate();
|
||||
List<ClientHttpRequestInterceptor> interceptors = restTemplate.getInterceptors();
|
||||
boolean hasBasicAuth = interceptors.stream()
|
||||
.anyMatch(interceptor -> interceptor instanceof BasicAuthenticationInterceptor);
|
||||
assertThat(hasBasicAuth).as("Basic Auth not configured").isTrue();
|
||||
}
|
||||
|
||||
}
|
||||
-94
@@ -1,94 +0,0 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.eureka.http;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import com.netflix.discovery.shared.resolver.DefaultEndpoint;
|
||||
import com.netflix.discovery.shared.transport.EurekaHttpClient;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.http.client.ClientHttpRequestFactorySettings;
|
||||
import org.springframework.boot.http.client.ClientHttpRequestFactorySettings.Redirects;
|
||||
import org.springframework.boot.web.client.RestTemplateBuilder;
|
||||
import org.springframework.http.client.ClientHttpRequestFactory;
|
||||
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
|
||||
import org.springframework.http.client.InterceptingClientHttpRequestFactory;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* @author Daniel Lavoie
|
||||
* @author Wonchul Heo
|
||||
*/
|
||||
class RestTemplateTransportClientFactoryTests {
|
||||
|
||||
private RestTemplateTransportClientFactory transportClientFactory;
|
||||
|
||||
@BeforeEach
|
||||
void setup() {
|
||||
transportClientFactory = new RestTemplateTransportClientFactory();
|
||||
}
|
||||
|
||||
@Test
|
||||
void withoutUserInfo() {
|
||||
EurekaHttpClient eurekaHttpClient = transportClientFactory
|
||||
.newClient(new DefaultEndpoint("http://localhost:8761"));
|
||||
assertThat(eurekaHttpClient).isInstanceOf(RestTemplateEurekaHttpClient.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void invalidUserInfo() {
|
||||
EurekaHttpClient eurekaHttpClient = transportClientFactory
|
||||
.newClient(new DefaultEndpoint("http://test@localhost:8761"));
|
||||
assertThat(eurekaHttpClient).isInstanceOf(RestTemplateEurekaHttpClient.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void userInfo() {
|
||||
EurekaHttpClient eurekaHttpClient = transportClientFactory
|
||||
.newClient(new DefaultEndpoint("http://test:test@localhost:8761"));
|
||||
assertThat(eurekaHttpClient).isInstanceOf(RestTemplateEurekaHttpClient.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRequestFactorySetWithRestTemplateBuilderSupplier() {
|
||||
// Gateway Server WebMVC sets Redirects.DONT_FOLLOW, gh-4423
|
||||
RestTemplateBuilder builder = new RestTemplateBuilder()
|
||||
.requestFactorySettings(new ClientHttpRequestFactorySettings(Redirects.DONT_FOLLOW, null, null, null));
|
||||
transportClientFactory = new RestTemplateTransportClientFactory(Optional.empty(), Optional.empty(),
|
||||
new DefaultEurekaClientHttpRequestFactorySupplier(), () -> builder);
|
||||
EurekaHttpClient eurekaHttpClient = transportClientFactory
|
||||
.newClient(new DefaultEndpoint("http://localhost:8761"));
|
||||
RestTemplateEurekaHttpClient restTemplateEurekaHttpClient = (RestTemplateEurekaHttpClient) eurekaHttpClient;
|
||||
RestTemplate restTemplate = restTemplateEurekaHttpClient.getRestTemplate();
|
||||
ClientHttpRequestFactory requestFactory = restTemplate.getRequestFactory();
|
||||
if (requestFactory instanceof InterceptingClientHttpRequestFactory interceptingClientHttpRequestFactory) {
|
||||
requestFactory = interceptingClientHttpRequestFactory.getDelegate();
|
||||
}
|
||||
assertThat(requestFactory).isInstanceOf(HttpComponentsClientHttpRequestFactory.class);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void shutdown() {
|
||||
transportClientFactory.shutdown();
|
||||
}
|
||||
|
||||
}
|
||||
+132
@@ -16,9 +16,21 @@
|
||||
|
||||
package org.springframework.cloud.netflix.eureka.http;
|
||||
|
||||
import java.security.SecureRandom;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.time.Duration;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import javax.net.ssl.HostnameVerifier;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.SSLPeerUnverifiedException;
|
||||
import javax.net.ssl.TrustManager;
|
||||
import javax.net.ssl.X509TrustManager;
|
||||
|
||||
import com.netflix.discovery.shared.resolver.DefaultEndpoint;
|
||||
import io.netty.handler.ssl.SslContextBuilder;
|
||||
import io.netty.handler.ssl.util.SelfSignedCertificate;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -28,6 +40,8 @@ import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoSettings;
|
||||
import org.mockito.quality.Strictness;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.netty.DisposableServer;
|
||||
import reactor.netty.http.server.HttpServer;
|
||||
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
@@ -37,6 +51,7 @@ import org.springframework.web.reactive.function.client.ExchangeFunction;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
@@ -101,6 +116,123 @@ class WebClientTransportClientFactoryTest {
|
||||
transportClientFatory.newClient(new DefaultEndpoint("http://test:test@localhost:8761"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testHostnameVerificationFailure() throws Exception {
|
||||
SelfSignedCertificate certificate = new SelfSignedCertificate("localhost");
|
||||
io.netty.handler.ssl.SslContext serverSslContext = SslContextBuilder
|
||||
.forServer(certificate.certificate(), certificate.privateKey())
|
||||
.build();
|
||||
|
||||
AtomicBoolean hostnameVerified = new AtomicBoolean();
|
||||
|
||||
DisposableServer server = HttpServer.create()
|
||||
.port(0)
|
||||
.secure(sslContextSpec -> sslContextSpec.sslContext(serverSslContext))
|
||||
.handle((request, response) -> response.send())
|
||||
.bindNow();
|
||||
|
||||
try {
|
||||
SSLContext clientSslContext = SSLContext.getInstance("TLS");
|
||||
TrustManager[] trustManagers = { new X509TrustManager() {
|
||||
|
||||
@Override
|
||||
public X509Certificate[] getAcceptedIssuers() {
|
||||
return new X509Certificate[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkClientTrusted(X509Certificate[] chain, String authType) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkServerTrusted(X509Certificate[] chain, String authType) {
|
||||
}
|
||||
|
||||
} };
|
||||
clientSslContext.init(null, trustManagers, new SecureRandom());
|
||||
|
||||
HostnameVerifier hostnameVerifier = (hostname, session) -> {
|
||||
hostnameVerified.set(true);
|
||||
return false;
|
||||
};
|
||||
|
||||
WebClientTransportClientFactory factory = new WebClientTransportClientFactory(WebClient::builder,
|
||||
Optional.of(clientSslContext), Optional.of(hostnameVerifier));
|
||||
|
||||
try {
|
||||
WebClientEurekaHttpClient client = (WebClientEurekaHttpClient) factory
|
||||
.newClient(new DefaultEndpoint("https://localhost:" + server.port()));
|
||||
|
||||
assertThatThrownBy(() -> client.getWebClient()
|
||||
.get()
|
||||
.retrieve()
|
||||
.bodyToMono(Void.class)
|
||||
.block(Duration.ofSeconds(10))).hasRootCauseInstanceOf(SSLPeerUnverifiedException.class);
|
||||
|
||||
assertThat(hostnameVerified).isTrue();
|
||||
}
|
||||
finally {
|
||||
factory.shutdown();
|
||||
}
|
||||
}
|
||||
finally {
|
||||
server.disposeNow();
|
||||
certificate.delete();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testHostnameVerificationWithDefaultVerifier() throws Exception {
|
||||
SelfSignedCertificate certificate = new SelfSignedCertificate("localhost");
|
||||
io.netty.handler.ssl.SslContext serverSslContext = SslContextBuilder
|
||||
.forServer(certificate.certificate(), certificate.privateKey())
|
||||
.build();
|
||||
|
||||
DisposableServer server = HttpServer.create()
|
||||
.port(0)
|
||||
.secure(sslContextSpec -> sslContextSpec.sslContext(serverSslContext))
|
||||
.handle((request, response) -> response.send())
|
||||
.bindNow();
|
||||
|
||||
try {
|
||||
SSLContext clientSslContext = SSLContext.getInstance("TLS");
|
||||
TrustManager[] trustManagers = { new X509TrustManager() {
|
||||
|
||||
@Override
|
||||
public X509Certificate[] getAcceptedIssuers() {
|
||||
return new X509Certificate[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkClientTrusted(X509Certificate[] chain, String authType) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkServerTrusted(X509Certificate[] chain, String authType) {
|
||||
}
|
||||
|
||||
} };
|
||||
clientSslContext.init(null, trustManagers, new SecureRandom());
|
||||
|
||||
WebClientTransportClientFactory factory = new WebClientTransportClientFactory(WebClient::builder,
|
||||
Optional.of(clientSslContext), Optional.empty());
|
||||
|
||||
try {
|
||||
WebClientEurekaHttpClient client = (WebClientEurekaHttpClient) factory
|
||||
.newClient(new DefaultEndpoint("https://localhost:" + server.port()));
|
||||
|
||||
client.getWebClient().get().retrieve().bodyToMono(Void.class).block(Duration.ofSeconds(10));
|
||||
}
|
||||
finally {
|
||||
factory.shutdown();
|
||||
}
|
||||
}
|
||||
finally {
|
||||
server.disposeNow();
|
||||
certificate.delete();
|
||||
}
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void shutdown() {
|
||||
transportClientFatory.shutdown();
|
||||
|
||||
+2
-2
@@ -81,8 +81,8 @@ class EurekaReactiveDiscoveryClientConfigurationTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void worksWithoutActuator() {
|
||||
contextRunner.withClassLoader(new FilteredClassLoader("org.springframework.boot.actuate")).run(context -> {
|
||||
void worksWithoutHealth() {
|
||||
contextRunner.withClassLoader(new FilteredClassLoader("org.springframework.boot.health")).run(context -> {
|
||||
assertThat(context).hasSingleBean(ReactiveDiscoveryClient.class);
|
||||
assertThat(context).doesNotHaveBean(ReactiveDiscoveryClientHealthIndicator.class);
|
||||
});
|
||||
|
||||
+18
@@ -39,6 +39,7 @@ import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* @author Tim Ysewyn
|
||||
* @author Mohamed Macow
|
||||
*/
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class EurekaReactiveDiscoveryClientTests {
|
||||
@@ -109,4 +110,21 @@ class EurekaReactiveDiscoveryClientTests {
|
||||
StepVerifier.create(instances).expectNextCount(1).expectComplete().verify();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldCompleteReactiveProbeWhenClientHealthy() {
|
||||
when(eurekaClient.getApplications()).thenReturn(new Applications());
|
||||
|
||||
StepVerifier.create(client.reactiveProbe()).verifyComplete();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldErrorReactiveProbeWhenClientThrows() {
|
||||
RuntimeException eurekaException = new RuntimeException("exception");
|
||||
when(eurekaClient.getApplications()).thenThrow(eurekaException);
|
||||
|
||||
StepVerifier.create(client.reactiveProbe())
|
||||
.verifyErrorSatisfies(
|
||||
ex -> assertThat(ex).isInstanceOf(RuntimeException.class).hasMessage(eurekaException.getMessage()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -5,13 +5,14 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-netflix</artifactId>
|
||||
<version>4.3.2</version>
|
||||
<version>5.1.0-SNAPSHOT</version>
|
||||
<relativePath>..</relativePath> <!-- lookup parent from repository -->
|
||||
</parent>
|
||||
<artifactId>spring-cloud-netflix-eureka-server</artifactId>
|
||||
<name>Spring Cloud Netflix Eureka Server</name>
|
||||
<url>https://projects.spring.io/spring-cloud/</url>
|
||||
<properties>
|
||||
<jersey.version>4.0.2</jersey.version>
|
||||
<wro4j.version>1.10.1</wro4j.version>
|
||||
<wiremock.version>2.27.2</wiremock.version>
|
||||
</properties>
|
||||
@@ -57,18 +58,22 @@
|
||||
<dependency>
|
||||
<groupId>org.glassfish.jersey.containers</groupId>
|
||||
<artifactId>jersey-container-servlet</artifactId>
|
||||
<version>${jersey.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.glassfish.jersey.core</groupId>
|
||||
<artifactId>jersey-server</artifactId>
|
||||
<version>${jersey.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.glassfish.jersey.core</groupId>
|
||||
<artifactId>jersey-client</artifactId>
|
||||
<version>${jersey.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.glassfish.jersey.inject</groupId>
|
||||
<artifactId>jersey-hk2</artifactId>
|
||||
<version>${jersey.version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.glassfish.hk2.external</groupId>
|
||||
@@ -76,6 +81,16 @@
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-resttestclient</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-restclient</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.glassfish.hk2</groupId>
|
||||
<artifactId>spring-bridge</artifactId>
|
||||
|
||||
+1
-1
@@ -79,8 +79,8 @@ import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.autoconfigure.web.ServerProperties;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.boot.web.server.autoconfigure.ServerProperties;
|
||||
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
||||
import org.springframework.cloud.client.actuator.HasFeatures;
|
||||
import org.springframework.cloud.context.environment.EnvironmentChangeEvent;
|
||||
|
||||
+2
-2
@@ -20,14 +20,14 @@ import com.netflix.eureka.registry.PeerAwareInstanceRegistry;
|
||||
import io.micrometer.core.instrument.MeterRegistry;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.boot.actuate.autoconfigure.metrics.CompositeMeterRegistryAutoConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.metrics.MetricsAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration;
|
||||
import org.springframework.boot.micrometer.metrics.autoconfigure.CompositeMeterRegistryAutoConfiguration;
|
||||
import org.springframework.boot.micrometer.metrics.autoconfigure.MetricsAutoConfiguration;
|
||||
import org.springframework.cloud.netflix.eureka.server.EurekaServerAutoConfiguration;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.core.task.TaskExecutor;
|
||||
|
||||
+1
-1
@@ -23,9 +23,9 @@ import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.resttestclient.TestRestTemplate;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
|
||||
import org.springframework.boot.test.web.client.TestRestTemplate;
|
||||
import org.springframework.boot.test.web.server.LocalServerPort;
|
||||
import org.springframework.cloud.netflix.eureka.server.ApplicationContextTests.Application;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
+1
-1
@@ -21,9 +21,9 @@ import java.util.Map;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.resttestclient.TestRestTemplate;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
|
||||
import org.springframework.boot.test.web.client.TestRestTemplate;
|
||||
import org.springframework.cloud.netflix.eureka.server.ApplicationContextTests.Application;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
|
||||
+1
-1
@@ -21,9 +21,9 @@ import java.util.Map;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.resttestclient.TestRestTemplate;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
|
||||
import org.springframework.boot.test.web.client.TestRestTemplate;
|
||||
import org.springframework.cloud.netflix.eureka.server.ApplicationContextTests.Application;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
|
||||
+1
-1
@@ -23,8 +23,8 @@ import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.resttestclient.TestRestTemplate;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.web.client.TestRestTemplate;
|
||||
import org.springframework.boot.test.web.server.LocalServerPort;
|
||||
import org.springframework.cloud.netflix.eureka.server.ApplicationServletPathTests.Application;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
+1
-1
@@ -28,8 +28,8 @@ import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.resttestclient.TestRestTemplate;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.web.client.TestRestTemplate;
|
||||
import org.springframework.boot.test.web.server.LocalServerPort;
|
||||
import org.springframework.cloud.netflix.eureka.server.ApplicationTests.Application;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
+1
-1
@@ -21,8 +21,8 @@ import java.util.Map;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.resttestclient.TestRestTemplate;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.web.client.TestRestTemplate;
|
||||
import org.springframework.boot.test.web.server.LocalServerPort;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.HttpStatus;
|
||||
|
||||
+2
-3
@@ -32,10 +32,9 @@ import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
|
||||
import org.springframework.boot.resttestclient.TestRestTemplate;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.util.TestPropertyValues;
|
||||
import org.springframework.boot.test.web.client.TestRestTemplate;
|
||||
import org.springframework.cloud.context.environment.EnvironmentChangeEvent;
|
||||
import org.springframework.cloud.netflix.eureka.EurekaClientConfigBean;
|
||||
import org.springframework.cloud.netflix.eureka.server.EurekaServerAutoConfiguration.RefreshablePeerEurekaNodes;
|
||||
@@ -247,7 +246,7 @@ class RefreshablePeerEurekaNodesTests {
|
||||
|
||||
@EnableEurekaServer
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableAutoConfiguration(exclude = { SecurityAutoConfiguration.class })
|
||||
@EnableAutoConfiguration
|
||||
protected static class Application {
|
||||
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-netflix</artifactId>
|
||||
<version>4.3.2</version>
|
||||
<version>5.1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
|
||||
<name>Spring Cloud Starter Netflix Eureka Client</name>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-netflix</artifactId>
|
||||
<version>4.3.2</version>
|
||||
<version>5.1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
|
||||
<name>Spring Cloud Starter Netflix Eureka Server</name>
|
||||
|
||||
Reference in New Issue
Block a user