Polish
This commit is contained in:
@@ -100,8 +100,9 @@ public class JvmMetricsAutoConfiguration {
|
||||
@ConditionalOnMissingBean(type = VIRTUAL_THREAD_METRICS_CLASS)
|
||||
@ImportRuntimeHints(VirtualThreadMetricsRuntimeHintsRegistrar.class)
|
||||
MeterBinder virtualThreadMetrics() throws ClassNotFoundException {
|
||||
Class<?> clazz = ClassUtils.forName(VIRTUAL_THREAD_METRICS_CLASS, getClass().getClassLoader());
|
||||
return (MeterBinder) BeanUtils.instantiateClass(clazz);
|
||||
Class<?> virtualThreadMetricsClass = ClassUtils.forName(VIRTUAL_THREAD_METRICS_CLASS,
|
||||
getClass().getClassLoader());
|
||||
return (MeterBinder) BeanUtils.instantiateClass(virtualThreadMetricsClass);
|
||||
}
|
||||
|
||||
static final class VirtualThreadMetricsRuntimeHintsRegistrar implements RuntimeHintsRegistrar {
|
||||
|
||||
@@ -18,8 +18,6 @@ package org.springframework.boot.autoconfigure.data.redis;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.boot.autoconfigure.data.redis.RedisConnectionConfiguration.ConnectionInfo;
|
||||
|
||||
/**
|
||||
* Adapts {@link RedisProperties} to {@link RedisConnectionDetails}.
|
||||
*
|
||||
@@ -28,6 +26,7 @@ import org.springframework.boot.autoconfigure.data.redis.RedisConnectionConfigur
|
||||
* @author Phillip Webb
|
||||
* @author Scott Frederick
|
||||
* @author Yanming Zhou
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
class PropertiesRedisConnectionDetails implements RedisConnectionDetails {
|
||||
|
||||
@@ -39,76 +38,45 @@ class PropertiesRedisConnectionDetails implements RedisConnectionDetails {
|
||||
|
||||
@Override
|
||||
public String getUsername() {
|
||||
if (this.properties.getUrl() != null) {
|
||||
ConnectionInfo connectionInfo = ConnectionInfo.of(this.properties.getUrl());
|
||||
return connectionInfo.getUsername();
|
||||
}
|
||||
return this.properties.getUsername();
|
||||
RedisUrl redisUrl = getRedisUrl();
|
||||
return (redisUrl != null) ? redisUrl.credentials().username() : this.properties.getUsername();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPassword() {
|
||||
if (this.properties.getUrl() != null) {
|
||||
ConnectionInfo connectionInfo = ConnectionInfo.of(this.properties.getUrl());
|
||||
return connectionInfo.getPassword();
|
||||
}
|
||||
return this.properties.getPassword();
|
||||
RedisUrl redisUrl = getRedisUrl();
|
||||
return (redisUrl != null) ? redisUrl.credentials().password() : this.properties.getPassword();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Standalone getStandalone() {
|
||||
if (this.properties.getUrl() != null) {
|
||||
ConnectionInfo connectionInfo = ConnectionInfo.of(this.properties.getUrl());
|
||||
return Standalone.of(connectionInfo.getUri().getHost(), connectionInfo.getUri().getPort(),
|
||||
connectionInfo.getDatabase());
|
||||
}
|
||||
return Standalone.of(this.properties.getHost(), this.properties.getPort(), this.properties.getDatabase());
|
||||
RedisUrl redisUrl = getRedisUrl();
|
||||
return (redisUrl != null)
|
||||
? Standalone.of(redisUrl.uri().getHost(), redisUrl.uri().getPort(), redisUrl.database())
|
||||
: Standalone.of(this.properties.getHost(), this.properties.getPort(), this.properties.getDatabase());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Sentinel getSentinel() {
|
||||
org.springframework.boot.autoconfigure.data.redis.RedisProperties.Sentinel sentinel = this.properties
|
||||
.getSentinel();
|
||||
if (sentinel == null) {
|
||||
return null;
|
||||
}
|
||||
return new Sentinel() {
|
||||
|
||||
@Override
|
||||
public int getDatabase() {
|
||||
return getStandalone().getDatabase();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMaster() {
|
||||
return sentinel.getMaster();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Node> getNodes() {
|
||||
return sentinel.getNodes().stream().map(PropertiesRedisConnectionDetails.this::asNode).toList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUsername() {
|
||||
return sentinel.getUsername();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPassword() {
|
||||
return sentinel.getPassword();
|
||||
}
|
||||
|
||||
};
|
||||
RedisProperties.Sentinel sentinel = this.properties.getSentinel();
|
||||
return (sentinel != null) ? new PropertiesSentinel(getStandalone().getDatabase(), sentinel) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cluster getCluster() {
|
||||
RedisProperties.Cluster cluster = this.properties.getCluster();
|
||||
List<Node> nodes = (cluster != null) ? cluster.getNodes().stream().map(this::asNode).toList() : null;
|
||||
List<Node> nodes = (cluster != null) ? asNodes(cluster.getNodes()) : null;
|
||||
return (nodes != null) ? () -> nodes : null;
|
||||
}
|
||||
|
||||
private RedisUrl getRedisUrl() {
|
||||
return RedisUrl.of(this.properties.getUrl());
|
||||
}
|
||||
|
||||
private List<Node> asNodes(List<String> nodes) {
|
||||
return nodes.stream().map(this::asNode).toList();
|
||||
}
|
||||
|
||||
private Node asNode(String node) {
|
||||
int portSeparatorIndex = node.lastIndexOf(':');
|
||||
String host = node.substring(0, portSeparatorIndex);
|
||||
@@ -116,4 +84,45 @@ class PropertiesRedisConnectionDetails implements RedisConnectionDetails {
|
||||
return new Node(host, port);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link Sentinel} implementation backed by properties.
|
||||
*/
|
||||
private class PropertiesSentinel implements Sentinel {
|
||||
|
||||
private final int database;
|
||||
|
||||
private final RedisProperties.Sentinel properties;
|
||||
|
||||
PropertiesSentinel(int database, RedisProperties.Sentinel properties) {
|
||||
this.database = database;
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDatabase() {
|
||||
return this.database;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMaster() {
|
||||
return this.properties.getMaster();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Node> getNodes() {
|
||||
return asNodes(this.properties.getNodes());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUsername() {
|
||||
return this.properties.getUsername();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPassword() {
|
||||
return this.properties.getPassword();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -16,8 +16,6 @@
|
||||
|
||||
package org.springframework.boot.autoconfigure.data.redis;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@@ -33,7 +31,6 @@ import org.springframework.data.redis.connection.RedisPassword;
|
||||
import org.springframework.data.redis.connection.RedisSentinelConfiguration;
|
||||
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Base Redis connection configuration.
|
||||
@@ -152,14 +149,18 @@ abstract class RedisConnectionConfiguration {
|
||||
return this.properties;
|
||||
}
|
||||
|
||||
protected SslBundles getSslBundles() {
|
||||
protected final SslBundles getSslBundles() {
|
||||
return this.sslBundles;
|
||||
}
|
||||
|
||||
protected boolean isSslEnabled() {
|
||||
protected final boolean isSslEnabled() {
|
||||
return getProperties().getSsl().isEnabled();
|
||||
}
|
||||
|
||||
protected final boolean urlUsesSsl() {
|
||||
return RedisUrl.of(this.properties.getUrl()).useSsl();
|
||||
}
|
||||
|
||||
protected boolean isPoolEnabled(Pool pool) {
|
||||
Boolean enabled = pool.getEnabled();
|
||||
return (enabled != null) ? enabled : COMMONS_POOL2_AVAILABLE;
|
||||
@@ -173,89 +174,8 @@ abstract class RedisConnectionConfiguration {
|
||||
return nodes;
|
||||
}
|
||||
|
||||
protected final boolean urlUsesSsl() {
|
||||
return ConnectionInfo.of(this.properties.getUrl()).isUseSsl();
|
||||
}
|
||||
|
||||
protected final RedisConnectionDetails getConnectionDetails() {
|
||||
return this.connectionDetails;
|
||||
}
|
||||
|
||||
static final class ConnectionInfo {
|
||||
|
||||
private final URI uri;
|
||||
|
||||
private final boolean useSsl;
|
||||
|
||||
private final String username;
|
||||
|
||||
private final String password;
|
||||
|
||||
private final int database;
|
||||
|
||||
private ConnectionInfo(URI uri, boolean useSsl, String username, String password, int database) {
|
||||
this.uri = uri;
|
||||
this.useSsl = useSsl;
|
||||
this.username = username;
|
||||
this.password = password;
|
||||
this.database = database;
|
||||
}
|
||||
|
||||
URI getUri() {
|
||||
return this.uri;
|
||||
}
|
||||
|
||||
boolean isUseSsl() {
|
||||
return this.useSsl;
|
||||
}
|
||||
|
||||
String getUsername() {
|
||||
return this.username;
|
||||
}
|
||||
|
||||
String getPassword() {
|
||||
return this.password;
|
||||
}
|
||||
|
||||
int getDatabase() {
|
||||
return this.database;
|
||||
}
|
||||
|
||||
static ConnectionInfo of(String url) {
|
||||
try {
|
||||
URI uri = new URI(url);
|
||||
String scheme = uri.getScheme();
|
||||
if (!"redis".equals(scheme) && !"rediss".equals(scheme)) {
|
||||
throw new RedisUrlSyntaxException(url);
|
||||
}
|
||||
boolean useSsl = ("rediss".equals(scheme));
|
||||
String username = null;
|
||||
String password = null;
|
||||
if (uri.getUserInfo() != null) {
|
||||
String candidate = uri.getUserInfo();
|
||||
int index = candidate.indexOf(':');
|
||||
if (index >= 0) {
|
||||
username = candidate.substring(0, index);
|
||||
password = candidate.substring(index + 1);
|
||||
}
|
||||
else {
|
||||
password = candidate;
|
||||
}
|
||||
}
|
||||
int database = 0;
|
||||
if (StringUtils.hasText(uri.getPath())) {
|
||||
String[] pathSplit = uri.getPath().split("/", 2);
|
||||
if (pathSplit.length > 1 && !pathSplit[1].isEmpty()) {
|
||||
database = Integer.parseInt(pathSplit[1]);
|
||||
}
|
||||
}
|
||||
return new ConnectionInfo(uri, useSsl, username, password, database);
|
||||
}
|
||||
catch (URISyntaxException ex) {
|
||||
throw new RedisUrlSyntaxException(url, ex);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright 2012-2025 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.boot.autoconfigure.data.redis;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* A parsed URL used to connect to Redis.
|
||||
*
|
||||
* @param uri the source URI
|
||||
* @param useSsl if SSL is used to connect
|
||||
* @param credentials the connection credentials
|
||||
* @param database the database index
|
||||
* @author Mark Paluch
|
||||
* @author Stephane Nicoll
|
||||
* @author Alen Turkovic
|
||||
* @author Scott Frederick
|
||||
* @author Eddú Meléndez
|
||||
* @author Moritz Halbritter
|
||||
* @author Andy Wilkinson
|
||||
* @author Phillip Webb
|
||||
* @author Yanming Zhou
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
record RedisUrl(URI uri, boolean useSsl, Credentials credentials, int database) {
|
||||
|
||||
static RedisUrl of(String url) {
|
||||
return (url != null) ? of(toUri(url)) : null;
|
||||
}
|
||||
|
||||
private static RedisUrl of(URI uri) {
|
||||
boolean useSsl = ("rediss".equals(uri.getScheme()));
|
||||
Credentials credentials = Credentials.fromUserInfo(uri.getUserInfo());
|
||||
int database = getDatabase(uri);
|
||||
return new RedisUrl(uri, useSsl, credentials, database);
|
||||
}
|
||||
|
||||
private static int getDatabase(URI uri) {
|
||||
String path = uri.getPath();
|
||||
String[] split = (!StringUtils.hasText(path)) ? new String[0] : path.split("/", 2);
|
||||
return (split.length > 1 && !split[1].isEmpty()) ? Integer.parseInt(split[1]) : 0;
|
||||
}
|
||||
|
||||
private static URI toUri(String url) {
|
||||
try {
|
||||
URI uri = new URI(url);
|
||||
String scheme = uri.getScheme();
|
||||
if (!"redis".equals(scheme) && !"rediss".equals(scheme)) {
|
||||
throw new RedisUrlSyntaxException(url);
|
||||
}
|
||||
return uri;
|
||||
}
|
||||
catch (URISyntaxException ex) {
|
||||
throw new RedisUrlSyntaxException(url, ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Redis connection credentials.
|
||||
*
|
||||
* @param username the username or {@code null}
|
||||
* @param password the password
|
||||
*/
|
||||
record Credentials(String username, String password) {
|
||||
|
||||
private static final Credentials NONE = new Credentials(null, null);
|
||||
|
||||
private static Credentials fromUserInfo(String userInfo) {
|
||||
if (userInfo == null) {
|
||||
return NONE;
|
||||
}
|
||||
int index = userInfo.indexOf(':');
|
||||
if (index != -1) {
|
||||
return new Credentials(userInfo.substring(0, index), userInfo.substring(index + 1));
|
||||
}
|
||||
return new Credentials(null, userInfo);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -22,13 +22,13 @@ import java.io.InputStream;
|
||||
import javax.sql.DataSource;
|
||||
import javax.xml.XMLConstants;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import javax.xml.parsers.SAXParser;
|
||||
import javax.xml.parsers.SAXParserFactory;
|
||||
import javax.xml.transform.Source;
|
||||
import javax.xml.transform.sax.SAXSource;
|
||||
|
||||
import jakarta.xml.bind.JAXBContext;
|
||||
import jakarta.xml.bind.JAXBException;
|
||||
import jakarta.xml.bind.Unmarshaller;
|
||||
import org.jooq.ConnectionProvider;
|
||||
import org.jooq.DSLContext;
|
||||
import org.jooq.ExecuteListenerProvider;
|
||||
@@ -40,6 +40,8 @@ import org.jooq.impl.DefaultDSLContext;
|
||||
import org.jooq.impl.DefaultExecuteListenerProvider;
|
||||
import org.xml.sax.InputSource;
|
||||
import org.xml.sax.SAXException;
|
||||
import org.xml.sax.SAXNotRecognizedException;
|
||||
import org.xml.sax.SAXNotSupportedException;
|
||||
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
@@ -138,27 +140,35 @@ public class JooqAutoConfiguration {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load {@link Settings} with <a href=
|
||||
* "https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html#jaxb-unmarshaller">
|
||||
* XML External Entity Prevention</a>.
|
||||
*/
|
||||
private static final class JaxbSettingsLoader {
|
||||
|
||||
private Settings load(InputStream inputStream) {
|
||||
try {
|
||||
// See
|
||||
// https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html#jaxb-unmarshaller
|
||||
SAXParserFactory spf = SAXParserFactory.newInstance();
|
||||
spf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
|
||||
spf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
|
||||
spf.setNamespaceAware(true);
|
||||
spf.setXIncludeAware(false);
|
||||
Source xmlSource = new SAXSource(spf.newSAXParser().getXMLReader(), new InputSource(inputStream));
|
||||
JAXBContext jc = JAXBContext.newInstance(Settings.class);
|
||||
Unmarshaller um = jc.createUnmarshaller();
|
||||
return um.unmarshal(xmlSource, Settings.class).getValue();
|
||||
SAXParser parser = createParserFactory().newSAXParser();
|
||||
Source source = new SAXSource(parser.getXMLReader(), new InputSource(inputStream));
|
||||
JAXBContext context = JAXBContext.newInstance(Settings.class);
|
||||
return context.createUnmarshaller().unmarshal(source, Settings.class).getValue();
|
||||
}
|
||||
catch (ParserConfigurationException | JAXBException | SAXException ex) {
|
||||
throw new IllegalStateException("Failed to unmarshal settings", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private SAXParserFactory createParserFactory()
|
||||
throws ParserConfigurationException, SAXNotRecognizedException, SAXNotSupportedException {
|
||||
SAXParserFactory factory = SAXParserFactory.newInstance();
|
||||
factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
|
||||
factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
|
||||
factory.setNamespaceAware(true);
|
||||
factory.setXIncludeAware(false);
|
||||
return factory;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user