Start splitting up spring-boot-autoconfigure
This commit is contained in:
committed by
Phillip Webb
parent
349f296d26
commit
710b1d80eb
@@ -1,90 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2024 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.cassandra;
|
||||
|
||||
import com.datastax.oss.driver.api.core.CqlSession;
|
||||
import com.datastax.oss.driver.api.core.config.DriverConfigLoader;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.testcontainers.cassandra.CassandraContainer;
|
||||
import org.testcontainers.junit.jupiter.Container;
|
||||
import org.testcontainers.junit.jupiter.Testcontainers;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.boot.testsupport.container.TestImage;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.BDDMockito.then;
|
||||
import static org.mockito.Mockito.spy;
|
||||
|
||||
/**
|
||||
* Integration tests for {@link CassandraAutoConfiguration}.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
@Testcontainers(disabledWithoutDocker = true)
|
||||
class CassandraAutoConfigurationIntegrationTests {
|
||||
|
||||
@Container
|
||||
static final CassandraContainer cassandra = TestImage.container(CassandraContainer.class);
|
||||
|
||||
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(CassandraAutoConfiguration.class))
|
||||
.withPropertyValues(
|
||||
"spring.cassandra.contact-points:" + cassandra.getHost() + ":" + cassandra.getFirstMappedPort(),
|
||||
"spring.cassandra.local-datacenter=datacenter1", "spring.cassandra.connection.connect-timeout=60s",
|
||||
"spring.cassandra.connection.init-query-timeout=60s", "spring.cassandra.request.timeout=60s");
|
||||
|
||||
@Test
|
||||
void whenTheContextIsClosedThenTheDriverConfigLoaderIsClosed() {
|
||||
this.contextRunner.withUserConfiguration(DriverConfigLoaderSpyConfiguration.class).run((context) -> {
|
||||
assertThat(((BeanDefinitionRegistry) context.getSourceApplicationContext())
|
||||
.getBeanDefinition("cassandraDriverConfigLoader")
|
||||
.getDestroyMethodName()).isEmpty();
|
||||
// Initialize lazy bean
|
||||
context.getBean(CqlSession.class);
|
||||
DriverConfigLoader driverConfigLoader = context.getBean(DriverConfigLoader.class);
|
||||
context.close();
|
||||
then(driverConfigLoader).should().close();
|
||||
});
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class DriverConfigLoaderSpyConfiguration {
|
||||
|
||||
@Bean
|
||||
static BeanPostProcessor driverConfigLoaderSpy() {
|
||||
return new BeanPostProcessor() {
|
||||
|
||||
@Override
|
||||
public Object postProcessAfterInitialization(Object bean, String beanName) {
|
||||
if (bean instanceof DriverConfigLoader) {
|
||||
return spy(bean);
|
||||
}
|
||||
return bean;
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,131 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2024 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.cassandra;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import com.datastax.oss.driver.api.core.ConsistencyLevel;
|
||||
import com.datastax.oss.driver.api.core.CqlSession;
|
||||
import com.datastax.oss.driver.api.core.CqlSessionBuilder;
|
||||
import com.datastax.oss.driver.api.core.cql.SimpleStatement;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.rnorth.ducttape.TimeoutException;
|
||||
import org.rnorth.ducttape.unreliables.Unreliables;
|
||||
import org.testcontainers.cassandra.CassandraContainer;
|
||||
import org.testcontainers.containers.ContainerLaunchException;
|
||||
import org.testcontainers.containers.wait.strategy.AbstractWaitStrategy;
|
||||
import org.testcontainers.images.builder.Transferable;
|
||||
import org.testcontainers.junit.jupiter.Container;
|
||||
import org.testcontainers.junit.jupiter.Testcontainers;
|
||||
import org.testcontainers.utility.DockerImageName;
|
||||
|
||||
import org.springframework.beans.factory.BeanCreationException;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.boot.testsupport.container.TestImage;
|
||||
import org.springframework.util.StreamUtils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
|
||||
/**
|
||||
* Tests for {@link CassandraAutoConfiguration} that only uses password authentication.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
@Testcontainers(disabledWithoutDocker = true)
|
||||
class CassandraAutoConfigurationWithPasswordAuthenticationIntegrationTests {
|
||||
|
||||
@Container
|
||||
static final CassandraContainer cassandra = TestImage.container(PasswordAuthenticatorCassandraContainer.class)
|
||||
.withStartupAttempts(5)
|
||||
.waitingFor(new CassandraWaitStrategy());
|
||||
|
||||
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(CassandraAutoConfiguration.class))
|
||||
.withPropertyValues(
|
||||
"spring.cassandra.contact-points:" + cassandra.getHost() + ":" + cassandra.getFirstMappedPort(),
|
||||
"spring.cassandra.local-datacenter=datacenter1", "spring.cassandra.connection.connect-timeout=60s",
|
||||
"spring.cassandra.connection.init-query-timeout=60s", "spring.cassandra.request.timeout=60s");
|
||||
|
||||
@Test
|
||||
void authenticationWithValidUsernameAndPassword() {
|
||||
this.contextRunner
|
||||
.withPropertyValues("spring.cassandra.username=cassandra", "spring.cassandra.password=cassandra")
|
||||
.run((context) -> {
|
||||
SimpleStatement select = SimpleStatement.newInstance("SELECT release_version FROM system.local")
|
||||
.setConsistencyLevel(ConsistencyLevel.LOCAL_ONE);
|
||||
assertThat(context.getBean(CqlSession.class).execute(select).one()).isNotNull();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void authenticationWithInvalidCredentials() {
|
||||
this.contextRunner
|
||||
.withPropertyValues("spring.cassandra.username=not-a-user", "spring.cassandra.password=invalid-password")
|
||||
.run((context) -> assertThatExceptionOfType(BeanCreationException.class)
|
||||
.isThrownBy(() -> context.getBean(CqlSession.class))
|
||||
.withMessageContaining("Authentication error"));
|
||||
}
|
||||
|
||||
static final class PasswordAuthenticatorCassandraContainer extends CassandraContainer {
|
||||
|
||||
PasswordAuthenticatorCassandraContainer(DockerImageName dockerImageName) {
|
||||
super(dockerImageName);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void containerIsCreated(String containerId) {
|
||||
String config = copyFileFromContainer("/etc/cassandra/cassandra.yaml",
|
||||
(stream) -> StreamUtils.copyToString(stream, StandardCharsets.UTF_8));
|
||||
String updatedConfig = config.replace("authenticator: AllowAllAuthenticator",
|
||||
"authenticator: PasswordAuthenticator");
|
||||
copyFileToContainer(Transferable.of(updatedConfig.getBytes(StandardCharsets.UTF_8)),
|
||||
"/etc/cassandra/cassandra.yaml");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static final class CassandraWaitStrategy extends AbstractWaitStrategy {
|
||||
|
||||
@Override
|
||||
protected void waitUntilReady() {
|
||||
try {
|
||||
Unreliables.retryUntilSuccess((int) this.startupTimeout.getSeconds(), TimeUnit.SECONDS, () -> {
|
||||
getRateLimiter().doWhenReady(() -> cqlSessionBuilder().build());
|
||||
return true;
|
||||
});
|
||||
}
|
||||
catch (TimeoutException ex) {
|
||||
throw new ContainerLaunchException(
|
||||
"Timed out waiting for Cassandra to be accessible for query execution");
|
||||
}
|
||||
}
|
||||
|
||||
private CqlSessionBuilder cqlSessionBuilder() {
|
||||
return CqlSession.builder()
|
||||
.addContactPoint(new InetSocketAddress(this.waitStrategyTarget.getHost(),
|
||||
this.waitStrategyTarget.getFirstMappedPort()))
|
||||
.withLocalDatacenter("datacenter1")
|
||||
.withAuthCredentials("cassandra", "cassandra");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,90 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2024 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.couchbase;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
import com.couchbase.client.core.diagnostics.ClusterState;
|
||||
import com.couchbase.client.core.diagnostics.DiagnosticsResult;
|
||||
import com.couchbase.client.java.Bucket;
|
||||
import com.couchbase.client.java.Cluster;
|
||||
import com.couchbase.client.java.Collection;
|
||||
import com.couchbase.client.java.env.ClusterEnvironment;
|
||||
import com.couchbase.client.java.json.JsonObject;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.testcontainers.couchbase.BucketDefinition;
|
||||
import org.testcontainers.couchbase.CouchbaseContainer;
|
||||
import org.testcontainers.couchbase.CouchbaseService;
|
||||
import org.testcontainers.junit.jupiter.Container;
|
||||
import org.testcontainers.junit.jupiter.Testcontainers;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.boot.testsupport.container.TestImage;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Integration tests for {@link CouchbaseAutoConfiguration}.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @author Brian Clozel
|
||||
*/
|
||||
@Testcontainers(disabledWithoutDocker = true)
|
||||
class CouchbaseAutoConfigurationIntegrationTests {
|
||||
|
||||
private static final String BUCKET_NAME = "cbbucket";
|
||||
|
||||
@Container
|
||||
static final CouchbaseContainer couchbase = TestImage.container(CouchbaseContainer.class)
|
||||
.withEnabledServices(CouchbaseService.KV)
|
||||
.withCredentials("spring", "password")
|
||||
.withBucket(new BucketDefinition(BUCKET_NAME).withPrimaryIndex(false));
|
||||
|
||||
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(CouchbaseAutoConfiguration.class))
|
||||
.withPropertyValues("spring.couchbase.connection-string: " + couchbase.getConnectionString(),
|
||||
"spring.couchbase.username:spring", "spring.couchbase.password:password",
|
||||
"spring.couchbase.bucket.name:" + BUCKET_NAME, "spring.couchbase.env.timeouts.connect=2m",
|
||||
"spring.couchbase.env.timeouts.key-value=1m");
|
||||
|
||||
@Test
|
||||
void defaultConfiguration() {
|
||||
this.contextRunner.run((context) -> {
|
||||
assertThat(context).hasSingleBean(Cluster.class).hasSingleBean(ClusterEnvironment.class);
|
||||
Cluster cluster = context.getBean(Cluster.class);
|
||||
Bucket bucket = cluster.bucket(BUCKET_NAME);
|
||||
bucket.waitUntilReady(Duration.ofMinutes(5));
|
||||
DiagnosticsResult diagnostics = cluster.diagnostics();
|
||||
assertThat(diagnostics.state()).isEqualTo(ClusterState.ONLINE);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenCouchbaseIsUsingCustomObjectMapperThenJsonCanBeRoundTripped() {
|
||||
this.contextRunner.withBean(ObjectMapper.class, ObjectMapper::new).run((context) -> {
|
||||
Cluster cluster = context.getBean(Cluster.class);
|
||||
Bucket bucket = cluster.bucket(BUCKET_NAME);
|
||||
bucket.waitUntilReady(Duration.ofMinutes(5));
|
||||
Collection collection = bucket.defaultCollection();
|
||||
collection.insert("test-document", JsonObject.create().put("a", "alpha"));
|
||||
assertThat(collection.get("test-document").contentAsObject().get("a")).isEqualTo("alpha");
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,90 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2024 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.cassandra;
|
||||
|
||||
import com.datastax.oss.driver.api.core.CqlSession;
|
||||
import com.datastax.oss.driver.api.core.CqlSessionBuilder;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.testcontainers.cassandra.CassandraContainer;
|
||||
import org.testcontainers.junit.jupiter.Container;
|
||||
import org.testcontainers.junit.jupiter.Testcontainers;
|
||||
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurationPackages;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.data.cassandra.city.City;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.boot.testsupport.container.TestImage;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.cassandra.config.SchemaAction;
|
||||
import org.springframework.data.cassandra.config.SessionFactoryFactoryBean;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link CassandraDataAutoConfiguration} that require a Cassandra instance.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
@Testcontainers(disabledWithoutDocker = true)
|
||||
class CassandraDataAutoConfigurationIntegrationTests {
|
||||
|
||||
@Container
|
||||
static final CassandraContainer cassandra = TestImage.container(CassandraContainer.class);
|
||||
|
||||
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
||||
.withConfiguration(
|
||||
AutoConfigurations.of(CassandraAutoConfiguration.class, CassandraDataAutoConfiguration.class))
|
||||
.withPropertyValues(
|
||||
"spring.cassandra.contact-points:" + cassandra.getHost() + ":" + cassandra.getFirstMappedPort(),
|
||||
"spring.cassandra.local-datacenter=datacenter1", "spring.cassandra.connection.connect-timeout=60s",
|
||||
"spring.cassandra.connection.init-query-timeout=60s", "spring.cassandra.request.timeout=60s")
|
||||
.withInitializer((context) -> AutoConfigurationPackages.register((BeanDefinitionRegistry) context,
|
||||
City.class.getPackage().getName()));
|
||||
|
||||
@Test
|
||||
void hasDefaultSchemaActionSet() {
|
||||
this.contextRunner.run((context) -> assertThat(context.getBean(SessionFactoryFactoryBean.class))
|
||||
.hasFieldOrPropertyWithValue("schemaAction", SchemaAction.NONE));
|
||||
}
|
||||
|
||||
@Test
|
||||
void hasRecreateSchemaActionSet() {
|
||||
this.contextRunner.withUserConfiguration(KeyspaceTestConfiguration.class)
|
||||
.withPropertyValues("spring.cassandra.schemaAction=recreate_drop_unused")
|
||||
.run((context) -> assertThat(context.getBean(SessionFactoryFactoryBean.class))
|
||||
.hasFieldOrPropertyWithValue("schemaAction", SchemaAction.RECREATE_DROP_UNUSED));
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class KeyspaceTestConfiguration {
|
||||
|
||||
@Bean
|
||||
CqlSession cqlSession(CqlSessionBuilder cqlSessionBuilder) {
|
||||
try (CqlSession session = cqlSessionBuilder.build()) {
|
||||
session.execute("CREATE KEYSPACE IF NOT EXISTS boot_test"
|
||||
+ " WITH REPLICATION = { 'class' : 'SimpleStrategy', 'replication_factor' : 1 };");
|
||||
}
|
||||
return cqlSessionBuilder.withKeyspace("boot_test").build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,113 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2024 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.elasticsearch;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.testcontainers.elasticsearch.ElasticsearchContainer;
|
||||
import org.testcontainers.junit.jupiter.Container;
|
||||
import org.testcontainers.junit.jupiter.Testcontainers;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.autoconfigure.TestAutoConfigurationPackage;
|
||||
import org.springframework.boot.autoconfigure.data.alt.elasticsearch.CityElasticsearchDbRepository;
|
||||
import org.springframework.boot.autoconfigure.data.elasticsearch.city.City;
|
||||
import org.springframework.boot.autoconfigure.data.elasticsearch.city.CityRepository;
|
||||
import org.springframework.boot.autoconfigure.data.empty.EmptyDataPackage;
|
||||
import org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchClientAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchRestClientAutoConfiguration;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.boot.testsupport.container.TestImage;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.elasticsearch.client.elc.ElasticsearchTemplate;
|
||||
import org.springframework.data.elasticsearch.config.EnableElasticsearchAuditing;
|
||||
import org.springframework.data.elasticsearch.repository.config.EnableElasticsearchRepositories;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link ElasticsearchRepositoriesAutoConfiguration}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @author Andy Wilkinson
|
||||
* @author Brian Clozel
|
||||
* @author Scott Frederick
|
||||
*/
|
||||
@Testcontainers(disabledWithoutDocker = true)
|
||||
class ElasticsearchRepositoriesAutoConfigurationTests {
|
||||
|
||||
@Container
|
||||
static final ElasticsearchContainer elasticsearch = TestImage.container(ElasticsearchContainer.class);
|
||||
|
||||
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(ElasticsearchRestClientAutoConfiguration.class,
|
||||
ElasticsearchClientAutoConfiguration.class, ElasticsearchRepositoriesAutoConfiguration.class,
|
||||
ElasticsearchDataAutoConfiguration.class))
|
||||
.withPropertyValues("spring.elasticsearch.uris=" + elasticsearch.getHttpHostAddress());
|
||||
|
||||
@Test
|
||||
void testDefaultRepositoryConfiguration() {
|
||||
this.contextRunner.withUserConfiguration(TestConfiguration.class)
|
||||
.run((context) -> assertThat(context).hasSingleBean(CityRepository.class)
|
||||
.hasSingleBean(ElasticsearchTemplate.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testNoRepositoryConfiguration() {
|
||||
this.contextRunner.withUserConfiguration(EmptyConfiguration.class)
|
||||
.run((context) -> assertThat(context).hasSingleBean(ElasticsearchTemplate.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void doesNotTriggerDefaultRepositoryDetectionIfCustomized() {
|
||||
this.contextRunner.withUserConfiguration(CustomizedConfiguration.class)
|
||||
.run((context) -> assertThat(context).hasSingleBean(CityElasticsearchDbRepository.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testAuditingConfiguration() {
|
||||
this.contextRunner.withUserConfiguration(AuditingConfiguration.class)
|
||||
.run((context) -> assertThat(context).hasSingleBean(ElasticsearchTemplate.class));
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@TestAutoConfigurationPackage(City.class)
|
||||
static class TestConfiguration {
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@TestAutoConfigurationPackage(EmptyDataPackage.class)
|
||||
static class EmptyConfiguration {
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@TestAutoConfigurationPackage(ElasticsearchRepositoriesAutoConfigurationTests.class)
|
||||
@EnableElasticsearchRepositories(basePackageClasses = CityElasticsearchDbRepository.class)
|
||||
static class CustomizedConfiguration {
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@TestAutoConfigurationPackage(ElasticsearchRepositoriesAutoConfigurationTests.class)
|
||||
@EnableElasticsearchRepositories
|
||||
@EnableElasticsearchAuditing
|
||||
static class AuditingConfiguration {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,127 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2024 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.elasticsearch;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.testcontainers.elasticsearch.ElasticsearchContainer;
|
||||
import org.testcontainers.junit.jupiter.Container;
|
||||
import org.testcontainers.junit.jupiter.Testcontainers;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.autoconfigure.TestAutoConfigurationPackage;
|
||||
import org.springframework.boot.autoconfigure.data.alt.elasticsearch.CityReactiveElasticsearchDbRepository;
|
||||
import org.springframework.boot.autoconfigure.data.elasticsearch.city.City;
|
||||
import org.springframework.boot.autoconfigure.data.elasticsearch.city.ReactiveCityRepository;
|
||||
import org.springframework.boot.autoconfigure.data.empty.EmptyDataPackage;
|
||||
import org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchClientAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchRestClientAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.elasticsearch.ReactiveElasticsearchClientAutoConfiguration;
|
||||
import org.springframework.boot.test.context.FilteredClassLoader;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.boot.testsupport.container.TestImage;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.elasticsearch.client.elc.ReactiveElasticsearchTemplate;
|
||||
import org.springframework.data.elasticsearch.config.EnableElasticsearchAuditing;
|
||||
import org.springframework.data.elasticsearch.repository.config.EnableReactiveElasticsearchRepositories;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link ReactiveElasticsearchRepositoriesAutoConfiguration}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @author Andy Wilkinson
|
||||
* @author Brian Clozel
|
||||
* @author Scott Frederick
|
||||
*/
|
||||
@Testcontainers(disabledWithoutDocker = true)
|
||||
class ReactiveElasticsearchRepositoriesAutoConfigurationTests {
|
||||
|
||||
@Container
|
||||
static final ElasticsearchContainer elasticsearch = TestImage.container(ElasticsearchContainer.class);
|
||||
|
||||
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(ElasticsearchClientAutoConfiguration.class,
|
||||
ElasticsearchRestClientAutoConfiguration.class,
|
||||
ReactiveElasticsearchRepositoriesAutoConfiguration.class, ElasticsearchDataAutoConfiguration.class,
|
||||
ReactiveElasticsearchClientAutoConfiguration.class))
|
||||
.withPropertyValues(
|
||||
"spring.elasticsearch.uris=" + elasticsearch.getHost() + ":" + elasticsearch.getFirstMappedPort(),
|
||||
"spring.elasticsearch.socket-timeout=30s");
|
||||
|
||||
@Test
|
||||
void backsOffWithoutReactor() {
|
||||
this.contextRunner.withUserConfiguration(TestConfiguration.class)
|
||||
.withClassLoader(new FilteredClassLoader(Mono.class))
|
||||
.run((context) -> assertThat(context)
|
||||
.doesNotHaveBean(ReactiveElasticsearchRepositoriesAutoConfiguration.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDefaultRepositoryConfiguration() {
|
||||
this.contextRunner.withUserConfiguration(TestConfiguration.class)
|
||||
.run((context) -> assertThat(context).hasSingleBean(ReactiveCityRepository.class)
|
||||
.hasSingleBean(ReactiveElasticsearchTemplate.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testNoRepositoryConfiguration() {
|
||||
this.contextRunner.withUserConfiguration(EmptyConfiguration.class)
|
||||
.run((context) -> assertThat(context).hasSingleBean(ReactiveElasticsearchTemplate.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void doesNotTriggerDefaultRepositoryDetectionIfCustomized() {
|
||||
this.contextRunner.withUserConfiguration(CustomizedConfiguration.class)
|
||||
.run((context) -> assertThat(context).hasSingleBean(CityReactiveElasticsearchDbRepository.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testAuditingConfiguration() {
|
||||
this.contextRunner.withUserConfiguration(AuditingConfiguration.class)
|
||||
.run((context) -> assertThat(context).hasSingleBean(ReactiveElasticsearchTemplate.class));
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@TestAutoConfigurationPackage(City.class)
|
||||
static class TestConfiguration {
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@TestAutoConfigurationPackage(EmptyDataPackage.class)
|
||||
static class EmptyConfiguration {
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@TestAutoConfigurationPackage(ReactiveElasticsearchRepositoriesAutoConfigurationTests.class)
|
||||
@EnableReactiveElasticsearchRepositories(basePackageClasses = CityReactiveElasticsearchDbRepository.class)
|
||||
static class CustomizedConfiguration {
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@TestAutoConfigurationPackage(ElasticsearchRepositoriesAutoConfigurationTests.class)
|
||||
@EnableReactiveElasticsearchRepositories
|
||||
@EnableElasticsearchAuditing
|
||||
static class AuditingConfiguration {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2024 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.neo4j;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.testcontainers.containers.Neo4jContainer;
|
||||
import org.testcontainers.junit.jupiter.Container;
|
||||
import org.testcontainers.junit.jupiter.Testcontainers;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.data.neo4j.country.CountryRepository;
|
||||
import org.springframework.boot.autoconfigure.neo4j.Neo4jAutoConfiguration;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.testsupport.container.TestImage;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.neo4j.repository.config.EnableNeo4jRepositories;
|
||||
import org.springframework.test.context.DynamicPropertyRegistry;
|
||||
import org.springframework.test.context.DynamicPropertySource;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Test to ensure that the properties get read and applied during the auto-configuration.
|
||||
*
|
||||
* @author Michael J. Simons
|
||||
*/
|
||||
@SpringBootTest
|
||||
@Testcontainers(disabledWithoutDocker = true)
|
||||
class Neo4jRepositoriesAutoConfigurationIntegrationTests {
|
||||
|
||||
@Container
|
||||
static final Neo4jContainer<?> neo4j = TestImage.container(Neo4jContainer.class);
|
||||
|
||||
@DynamicPropertySource
|
||||
static void neo4jProperties(DynamicPropertyRegistry registry) {
|
||||
registry.add("spring.neo4j.uri", neo4j::getBoltUrl);
|
||||
registry.add("spring.neo4j.authentication.username", () -> "neo4j");
|
||||
registry.add("spring.neo4j.authentication.password", neo4j::getAdminPassword);
|
||||
}
|
||||
|
||||
@Autowired
|
||||
private CountryRepository countryRepository;
|
||||
|
||||
@Test
|
||||
void ensureRepositoryIsReady() {
|
||||
assertThat(this.countryRepository.count()).isZero();
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableNeo4jRepositories(basePackageClasses = CountryRepository.class)
|
||||
@ImportAutoConfiguration({ Neo4jAutoConfiguration.class, Neo4jDataAutoConfiguration.class,
|
||||
Neo4jRepositoriesAutoConfiguration.class })
|
||||
static class TestConfiguration {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,108 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2024 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 com.redis.testcontainers.RedisContainer;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.testcontainers.junit.jupiter.Container;
|
||||
import org.testcontainers.junit.jupiter.Testcontainers;
|
||||
|
||||
import org.springframework.boot.autoconfigure.TestAutoConfigurationPackage;
|
||||
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.data.alt.redis.CityRedisRepository;
|
||||
import org.springframework.boot.autoconfigure.data.empty.EmptyDataPackage;
|
||||
import org.springframework.boot.autoconfigure.data.redis.city.City;
|
||||
import org.springframework.boot.autoconfigure.data.redis.city.CityRepository;
|
||||
import org.springframework.boot.test.util.TestPropertyValues;
|
||||
import org.springframework.boot.testsupport.container.TestImage;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.redis.repository.configuration.EnableRedisRepositories;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link RedisRepositoriesAutoConfiguration}.
|
||||
*
|
||||
* @author Eddú Meléndez
|
||||
*/
|
||||
@Testcontainers(disabledWithoutDocker = true)
|
||||
class RedisRepositoriesAutoConfigurationTests {
|
||||
|
||||
@Container
|
||||
public static RedisContainer redis = TestImage.container(RedisContainer.class);
|
||||
|
||||
private final AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
TestPropertyValues
|
||||
.of("spring.data.redis.host=" + redis.getHost(), "spring.data.redis.port=" + redis.getFirstMappedPort())
|
||||
.applyTo(this.context.getEnvironment());
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void close() {
|
||||
this.context.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDefaultRepositoryConfiguration() {
|
||||
this.context.register(TestConfiguration.class, RedisAutoConfiguration.class,
|
||||
RedisRepositoriesAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class);
|
||||
this.context.refresh();
|
||||
assertThat(this.context.getBean(CityRepository.class)).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testNoRepositoryConfiguration() {
|
||||
this.context.register(EmptyConfiguration.class, RedisAutoConfiguration.class,
|
||||
RedisRepositoriesAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class);
|
||||
this.context.refresh();
|
||||
assertThat(this.context.getBean("redisTemplate")).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void doesNotTriggerDefaultRepositoryDetectionIfCustomized() {
|
||||
this.context.register(CustomizedConfiguration.class, RedisAutoConfiguration.class,
|
||||
RedisRepositoriesAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class);
|
||||
this.context.refresh();
|
||||
assertThat(this.context.getBean(CityRedisRepository.class)).isNotNull();
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@TestAutoConfigurationPackage(City.class)
|
||||
static class TestConfiguration {
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@TestAutoConfigurationPackage(EmptyDataPackage.class)
|
||||
static class EmptyConfiguration {
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@TestAutoConfigurationPackage(RedisRepositoriesAutoConfigurationTests.class)
|
||||
@EnableRedisRepositories(basePackageClasses = CityRedisRepository.class)
|
||||
static class CustomizedConfiguration {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2024 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.elasticsearch;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import co.elastic.clients.elasticsearch.ElasticsearchClient;
|
||||
import co.elastic.clients.elasticsearch.core.GetResponse;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.testcontainers.elasticsearch.ElasticsearchContainer;
|
||||
import org.testcontainers.junit.jupiter.Container;
|
||||
import org.testcontainers.junit.jupiter.Testcontainers;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.boot.testsupport.container.TestImage;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Integration tests for {@link ElasticsearchClientAutoConfiguration}.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
@Testcontainers(disabledWithoutDocker = true)
|
||||
class ElasticsearchClientAutoConfigurationIntegrationTests {
|
||||
|
||||
@Container
|
||||
static final ElasticsearchContainer elasticsearch = TestImage.container(ElasticsearchContainer.class);
|
||||
|
||||
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(JacksonAutoConfiguration.class,
|
||||
ElasticsearchRestClientAutoConfiguration.class, ElasticsearchClientAutoConfiguration.class));
|
||||
|
||||
@Test
|
||||
void reactiveClientCanQueryElasticsearchNode() {
|
||||
this.contextRunner
|
||||
.withPropertyValues("spring.elasticsearch.uris=" + elasticsearch.getHttpHostAddress(),
|
||||
"spring.elasticsearch.connection-timeout=120s", "spring.elasticsearch.socket-timeout=120s")
|
||||
.run((context) -> {
|
||||
ElasticsearchClient client = context.getBean(ElasticsearchClient.class);
|
||||
client.index((b) -> b.index("foo").id("1").document(Map.of("a", "alpha", "b", "bravo")));
|
||||
GetResponse<Object> response = client.get((b) -> b.index("foo").id("1"), Object.class);
|
||||
assertThat(response).isNotNull();
|
||||
assertThat(response.found()).isTrue();
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2024 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.elasticsearch;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.elasticsearch.client.Request;
|
||||
import org.elasticsearch.client.Response;
|
||||
import org.elasticsearch.client.RestClient;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.testcontainers.elasticsearch.ElasticsearchContainer;
|
||||
import org.testcontainers.junit.jupiter.Container;
|
||||
import org.testcontainers.junit.jupiter.Testcontainers;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.boot.testsupport.container.TestImage;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Integration tests for {@link ElasticsearchRestClientAutoConfiguration}.
|
||||
*
|
||||
* @author Brian Clozel
|
||||
* @author Vedran Pavic
|
||||
* @author Evgeniy Cheban
|
||||
* @author Filip Hrisafov
|
||||
*/
|
||||
@Testcontainers(disabledWithoutDocker = true)
|
||||
class ElasticsearchRestClientAutoConfigurationIntegrationTests {
|
||||
|
||||
@Container
|
||||
static final ElasticsearchContainer elasticsearch = TestImage.container(ElasticsearchContainer.class);
|
||||
|
||||
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(ElasticsearchRestClientAutoConfiguration.class));
|
||||
|
||||
@Test
|
||||
void restClientCanQueryElasticsearchNode() {
|
||||
this.contextRunner
|
||||
.withPropertyValues("spring.elasticsearch.uris=" + elasticsearch.getHttpHostAddress(),
|
||||
"spring.elasticsearch.connection-timeout=120s", "spring.elasticsearch.socket-timeout=120s")
|
||||
.run((context) -> {
|
||||
RestClient client = context.getBean(RestClient.class);
|
||||
Request index = new Request("PUT", "/test/_doc/2");
|
||||
index.setJsonEntity("{" + " \"a\": \"alpha\"," + " \"b\": \"bravo\"" + "}");
|
||||
client.performRequest(index);
|
||||
Request getRequest = new Request("GET", "/test/_doc/2");
|
||||
Response response = client.performRequest(getRequest);
|
||||
try (InputStream input = response.getEntity().getContent()) {
|
||||
JsonNode result = new ObjectMapper().readTree(input);
|
||||
assertThat(result.path("found").asBoolean()).isTrue();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2024 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.elasticsearch;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import co.elastic.clients.elasticsearch.core.GetResponse;
|
||||
import co.elastic.clients.elasticsearch.core.IndexResponse;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.testcontainers.elasticsearch.ElasticsearchContainer;
|
||||
import org.testcontainers.junit.jupiter.Container;
|
||||
import org.testcontainers.junit.jupiter.Testcontainers;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.boot.testsupport.container.TestImage;
|
||||
import org.springframework.data.elasticsearch.client.elc.ReactiveElasticsearchClient;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Integration tests for {@link ReactiveElasticsearchClientAutoConfiguration}.
|
||||
*
|
||||
* @author Brian Clozel
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
@Testcontainers(disabledWithoutDocker = true)
|
||||
class ReactiveElasticsearchClientAutoConfigurationIntegrationTests {
|
||||
|
||||
@Container
|
||||
static final ElasticsearchContainer elasticsearch = TestImage.container(ElasticsearchContainer.class);
|
||||
|
||||
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(JacksonAutoConfiguration.class,
|
||||
ElasticsearchRestClientAutoConfiguration.class, ReactiveElasticsearchClientAutoConfiguration.class));
|
||||
|
||||
@Test
|
||||
void reactiveClientCanQueryElasticsearchNode() {
|
||||
this.contextRunner
|
||||
.withPropertyValues("spring.elasticsearch.uris=" + elasticsearch.getHttpHostAddress(),
|
||||
"spring.elasticsearch.connection-timeout=120s", "spring.elasticsearch.socket-timeout=120s")
|
||||
.run((context) -> {
|
||||
ReactiveElasticsearchClient client = context.getBean(ReactiveElasticsearchClient.class);
|
||||
Mono<IndexResponse> index = client
|
||||
.index((b) -> b.index("foo").id("1").document(Map.of("a", "alpha", "b", "bravo")));
|
||||
index.block();
|
||||
Mono<GetResponse<Object>> get = client.get((b) -> b.index("foo").id("1"), Object.class);
|
||||
GetResponse<Object> response = get.block();
|
||||
assertThat(response).isNotNull();
|
||||
assertThat(response.found()).isTrue();
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,219 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2024 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.mail;
|
||||
|
||||
import java.net.SocketTimeoutException;
|
||||
import java.security.cert.CertPathBuilderException;
|
||||
import java.time.Duration;
|
||||
import java.util.Arrays;
|
||||
|
||||
import javax.net.ssl.SSLException;
|
||||
|
||||
import jakarta.mail.Folder;
|
||||
import jakarta.mail.Message;
|
||||
import jakarta.mail.MessagingException;
|
||||
import jakarta.mail.Session;
|
||||
import jakarta.mail.Store;
|
||||
import org.awaitility.Awaitility;
|
||||
import org.junit.jupiter.api.Nested;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.testcontainers.junit.jupiter.Container;
|
||||
import org.testcontainers.junit.jupiter.Testcontainers;
|
||||
import org.testcontainers.utility.MountableFile;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.autoconfigure.ssl.SslAutoConfiguration;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.boot.testsupport.container.MailpitContainer;
|
||||
import org.springframework.boot.testsupport.container.TestImage;
|
||||
import org.springframework.mail.SimpleMailMessage;
|
||||
import org.springframework.mail.javamail.JavaMailSenderImpl;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatException;
|
||||
|
||||
/**
|
||||
* Integration tests for {@link MailSenderAutoConfiguration}.
|
||||
*
|
||||
* @author Rui Figueira
|
||||
*/
|
||||
@Testcontainers(disabledWithoutDocker = true)
|
||||
class MailSenderAutoConfigurationIntegrationTests {
|
||||
|
||||
private SimpleMailMessage createMessage(String subject) {
|
||||
SimpleMailMessage msg = new SimpleMailMessage();
|
||||
msg.setFrom("from@example.com");
|
||||
msg.setTo("to@example.com");
|
||||
msg.setSubject(subject);
|
||||
msg.setText("Subject: " + subject);
|
||||
return msg;
|
||||
}
|
||||
|
||||
private String getSubject(Message message) {
|
||||
try {
|
||||
return message.getSubject();
|
||||
}
|
||||
catch (MessagingException ex) {
|
||||
throw new RuntimeException("Failed to get message subject", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private void assertMessagesContainSubject(Session session, String subject) throws MessagingException {
|
||||
try (Store store = session.getStore("pop3")) {
|
||||
String host = session.getProperty("mail.pop3.host");
|
||||
int port = Integer.parseInt(session.getProperty("mail.pop3.port"));
|
||||
store.connect(host, port, "user", "pass");
|
||||
try (Folder folder = store.getFolder("inbox")) {
|
||||
folder.open(Folder.READ_ONLY);
|
||||
Awaitility.await()
|
||||
.atMost(Duration.ofSeconds(5))
|
||||
.ignoreExceptions()
|
||||
.untilAsserted(() -> assertThat(Arrays.stream(folder.getMessages()).map(this::getSubject))
|
||||
.contains(subject));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
class ImplicitTlsTests {
|
||||
|
||||
@Container
|
||||
private static final MailpitContainer mailpit = TestImage.container(MailpitContainer.class)
|
||||
.withSmtpRequireTls(true)
|
||||
.withSmtpTlsCert(MountableFile
|
||||
.forClasspathResource("/org/springframework/boot/autoconfigure/mail/ssl/test-server.crt"))
|
||||
.withSmtpTlsKey(MountableFile
|
||||
.forClasspathResource("/org/springframework/boot/autoconfigure/mail/ssl/test-server.key"))
|
||||
.withPop3Auth("user:pass");
|
||||
|
||||
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(MailSenderAutoConfiguration.class, SslAutoConfiguration.class));
|
||||
|
||||
@Test
|
||||
void sendEmailWithSslEnabledAndCert() {
|
||||
this.contextRunner.withPropertyValues("spring.mail.host:" + mailpit.getHost(),
|
||||
"spring.mail.port:" + mailpit.getSmtpPort(), "spring.mail.ssl.enabled:true",
|
||||
"spring.mail.ssl.bundle:test-bundle",
|
||||
"spring.ssl.bundle.pem.test-bundle.truststore.certificate=classpath:org/springframework/boot/autoconfigure/mail/ssl/test-ca.crt",
|
||||
"spring.ssl.bundle.pem.test-bundle.keystore.certificate=classpath:org/springframework/boot/autoconfigure/mail/ssl/test-client.crt",
|
||||
"spring.ssl.bundle.pem.test-bundle.keystore.private-key=classpath:org/springframework/boot/autoconfigure/mail/ssl/test-client.key",
|
||||
"spring.mail.properties.mail.pop3.host:" + mailpit.getHost(),
|
||||
"spring.mail.properties.mail.pop3.port:" + mailpit.getPop3Port())
|
||||
.run((context) -> {
|
||||
JavaMailSenderImpl mailSender = context.getBean(JavaMailSenderImpl.class);
|
||||
mailSender.send(createMessage("Hello World!"));
|
||||
assertMessagesContainSubject(mailSender.getSession(), "Hello World!");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void sendEmailWithSslEnabledWithoutCert() {
|
||||
this.contextRunner
|
||||
.withPropertyValues("spring.mail.host:" + mailpit.getHost(),
|
||||
"spring.mail.port:" + mailpit.getSmtpPort(), "spring.mail.ssl.enabled:true")
|
||||
.run((context) -> {
|
||||
JavaMailSenderImpl mailSender = context.getBean(JavaMailSenderImpl.class);
|
||||
assertThatException().isThrownBy(() -> mailSender.send(createMessage("Should fail")))
|
||||
.withRootCauseInstanceOf(CertPathBuilderException.class);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void sendEmailWithoutSslWithCert() {
|
||||
this.contextRunner.withPropertyValues("spring.mail.host:" + mailpit.getHost(),
|
||||
"spring.mail.port:" + mailpit.getSmtpPort(), "spring.mail.properties.mail.smtp.timeout:1000",
|
||||
"spring.mail.ssl.bundle:test-bundle",
|
||||
"spring.ssl.bundle.pem.test-bundle.truststore.certificate=classpath:org/springframework/boot/autoconfigure/mail/ssl/test-ca.crt",
|
||||
"spring.ssl.bundle.pem.test-bundle.keystore.certificate=classpath:org/springframework/boot/autoconfigure/mail/ssl/test-client.crt",
|
||||
"spring.ssl.bundle.pem.test-bundle.keystore.private-key=classpath:org/springframework/boot/autoconfigure/mail/ssl/test-client.key")
|
||||
.run((context) -> {
|
||||
JavaMailSenderImpl mailSender = context.getBean(JavaMailSenderImpl.class);
|
||||
assertThatException().isThrownBy(() -> mailSender.send(createMessage("Should fail")))
|
||||
.withRootCauseInstanceOf(SocketTimeoutException.class);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Nested
|
||||
class StarttlsTests {
|
||||
|
||||
@Container
|
||||
private static final MailpitContainer mailpit = TestImage.container(MailpitContainer.class)
|
||||
.withSmtpRequireStarttls(true)
|
||||
.withSmtpTlsCert(MountableFile
|
||||
.forClasspathResource("/org/springframework/boot/autoconfigure/mail/ssl/test-server.crt"))
|
||||
.withSmtpTlsKey(MountableFile
|
||||
.forClasspathResource("/org/springframework/boot/autoconfigure/mail/ssl/test-server.key"))
|
||||
.withPop3Auth("user:pass");
|
||||
|
||||
final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(MailSenderAutoConfiguration.class, SslAutoConfiguration.class));
|
||||
|
||||
@Test
|
||||
void sendEmailWithStarttlsAndCertAndSslDisabled() {
|
||||
this.contextRunner.withPropertyValues("spring.mail.host:" + mailpit.getHost(),
|
||||
"spring.mail.port:" + mailpit.getSmtpPort(),
|
||||
"spring.mail.properties.mail.smtp.starttls.enable:true",
|
||||
"spring.mail.properties.mail.smtp.starttls.required:true", "spring.mail.ssl.bundle:test-bundle",
|
||||
"spring.ssl.bundle.pem.test-bundle.truststore.certificate=classpath:org/springframework/boot/autoconfigure/mail/ssl/test-ca.crt",
|
||||
"spring.ssl.bundle.pem.test-bundle.keystore.certificate=classpath:org/springframework/boot/autoconfigure/mail/ssl/test-client.crt",
|
||||
"spring.ssl.bundle.pem.test-bundle.keystore.private-key=classpath:org/springframework/boot/autoconfigure/mail/ssl/test-client.key",
|
||||
"spring.mail.properties.mail.pop3.host:" + mailpit.getHost(),
|
||||
"spring.mail.properties.mail.pop3.port:" + mailpit.getPop3Port())
|
||||
.run((context) -> {
|
||||
JavaMailSenderImpl mailSender = context.getBean(JavaMailSenderImpl.class);
|
||||
mailSender.send(createMessage("Sent with STARTTLS"));
|
||||
assertMessagesContainSubject(mailSender.getSession(), "Sent with STARTTLS");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void sendEmailWithStarttlsAndCertAndSslEnabled() {
|
||||
this.contextRunner.withPropertyValues("spring.mail.host:" + mailpit.getHost(),
|
||||
"spring.mail.port:" + mailpit.getSmtpPort(), "spring.mail.ssl.enabled:true",
|
||||
"spring.mail.properties.mail.smtp.starttls.enable:true",
|
||||
"spring.mail.properties.mail.smtp.starttls.required:true", "spring.mail.ssl.bundle:test-bundle",
|
||||
"spring.ssl.bundle.pem.test-bundle.truststore.certificate=classpath:org/springframework/boot/autoconfigure/mail/ssl/test-ca.crt",
|
||||
"spring.ssl.bundle.pem.test-bundle.keystore.certificate=classpath:org/springframework/boot/autoconfigure/mail/ssl/test-client.crt",
|
||||
"spring.ssl.bundle.pem.test-bundle.keystore.private-key=classpath:org/springframework/boot/autoconfigure/mail/ssl/test-client.key",
|
||||
"spring.mail.properties.mail.pop3.host:" + mailpit.getHost(),
|
||||
"spring.mail.properties.mail.pop3.port:" + mailpit.getPop3Port())
|
||||
.run((context) -> {
|
||||
JavaMailSenderImpl mailSender = context.getBean(JavaMailSenderImpl.class);
|
||||
assertThatException().isThrownBy(() -> mailSender.send(createMessage("Should fail")))
|
||||
.withRootCauseInstanceOf(SSLException.class);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void sendEmailWithStarttlsWithoutCert() {
|
||||
this.contextRunner
|
||||
.withPropertyValues("spring.mail.host:" + mailpit.getHost(),
|
||||
"spring.mail.port:" + mailpit.getSmtpPort(),
|
||||
"spring.mail.properties.mail.smtp.starttls.enable:true",
|
||||
"spring.mail.properties.mail.smtp.starttls.required:true")
|
||||
.run((context) -> {
|
||||
JavaMailSenderImpl mailSender = context.getBean(JavaMailSenderImpl.class);
|
||||
assertThatException().isThrownBy(() -> mailSender.send(createMessage("Should fail")))
|
||||
.withRootCauseInstanceOf(CertPathBuilderException.class);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,180 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2024 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.neo4j;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import org.junit.jupiter.api.Nested;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.neo4j.driver.AuthToken;
|
||||
import org.neo4j.driver.AuthTokenManager;
|
||||
import org.neo4j.driver.AuthTokenManagers;
|
||||
import org.neo4j.driver.AuthTokens;
|
||||
import org.neo4j.driver.Driver;
|
||||
import org.neo4j.driver.Result;
|
||||
import org.neo4j.driver.Session;
|
||||
import org.neo4j.driver.Transaction;
|
||||
import org.testcontainers.containers.Neo4jContainer;
|
||||
import org.testcontainers.junit.jupiter.Container;
|
||||
import org.testcontainers.junit.jupiter.Testcontainers;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.testsupport.container.TestImage;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.test.context.DynamicPropertyRegistry;
|
||||
import org.springframework.test.context.DynamicPropertySource;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Integration tests for {@link Neo4jAutoConfiguration}.
|
||||
*
|
||||
* @author Michael J. Simons
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
@Testcontainers(disabledWithoutDocker = true)
|
||||
class Neo4jAutoConfigurationIntegrationTests {
|
||||
|
||||
@Container
|
||||
private static final Neo4jContainer<?> neo4j = TestImage.container(Neo4jContainer.class);
|
||||
|
||||
@SpringBootTest
|
||||
@Nested
|
||||
class DriverWithDefaultAuthToken {
|
||||
|
||||
@DynamicPropertySource
|
||||
static void neo4jProperties(DynamicPropertyRegistry registry) {
|
||||
registry.add("spring.neo4j.uri", neo4j::getBoltUrl);
|
||||
registry.add("spring.neo4j.authentication.username", () -> "neo4j");
|
||||
registry.add("spring.neo4j.authentication.password", neo4j::getAdminPassword);
|
||||
}
|
||||
|
||||
@Autowired
|
||||
private Driver driver;
|
||||
|
||||
@Test
|
||||
void driverCanHandleRequest() {
|
||||
try (Session session = this.driver.session(); Transaction tx = session.beginTransaction()) {
|
||||
Result statementResult = tx.run("MATCH (n:Thing) RETURN n LIMIT 1");
|
||||
assertThat(statementResult.hasNext()).isFalse();
|
||||
tx.commit();
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ImportAutoConfiguration(Neo4jAutoConfiguration.class)
|
||||
static class TestConfiguration {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@SpringBootTest
|
||||
@Nested
|
||||
class DriverWithDynamicAuthToken {
|
||||
|
||||
@DynamicPropertySource
|
||||
static void neo4jProperties(DynamicPropertyRegistry registry) {
|
||||
registry.add("spring.neo4j.uri", neo4j::getBoltUrl);
|
||||
registry.add("spring.neo4j.authentication.username", () -> "wrong");
|
||||
registry.add("spring.neo4j.authentication.password", () -> "alsowrong");
|
||||
}
|
||||
|
||||
@Autowired
|
||||
private Driver driver;
|
||||
|
||||
@Test
|
||||
void driverCanHandleRequest() {
|
||||
try (Session session = this.driver.session(); Transaction tx = session.beginTransaction()) {
|
||||
Result statementResult = tx.run("MATCH (n:Thing) RETURN n LIMIT 1");
|
||||
assertThat(statementResult.hasNext()).isFalse();
|
||||
tx.commit();
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ImportAutoConfiguration(Neo4jAutoConfiguration.class)
|
||||
static class TestConfiguration {
|
||||
|
||||
@Bean
|
||||
AuthTokenManager authTokenManager() {
|
||||
return AuthTokenManagers.bearer(() -> AuthTokens.basic("neo4j", neo4j.getAdminPassword())
|
||||
.expiringAt(System.currentTimeMillis() + 5_000));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@SpringBootTest
|
||||
@Nested
|
||||
class DriverWithCustomConnectionDetailsIgnoresAuthTokenManager {
|
||||
|
||||
@DynamicPropertySource
|
||||
static void neo4jProperties(DynamicPropertyRegistry registry) {
|
||||
registry.add("spring.neo4j.uri", neo4j::getBoltUrl);
|
||||
registry.add("spring.neo4j.authentication.username", () -> "wrong");
|
||||
registry.add("spring.neo4j.authentication.password", () -> "alsowrong");
|
||||
}
|
||||
|
||||
@Autowired
|
||||
private Driver driver;
|
||||
|
||||
@Test
|
||||
void driverCanHandleRequest() {
|
||||
try (Session session = this.driver.session(); Transaction tx = session.beginTransaction()) {
|
||||
Result statementResult = tx.run("MATCH (n:Thing) RETURN n LIMIT 1");
|
||||
assertThat(statementResult.hasNext()).isFalse();
|
||||
tx.commit();
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ImportAutoConfiguration(Neo4jAutoConfiguration.class)
|
||||
static class TestConfiguration {
|
||||
|
||||
@Bean
|
||||
AuthTokenManager authTokenManager() {
|
||||
return AuthTokenManagers.bearer(() -> AuthTokens.basic("wrongagain", "stillwrong")
|
||||
.expiringAt(System.currentTimeMillis() + 5_000));
|
||||
}
|
||||
|
||||
@Bean
|
||||
Neo4jConnectionDetails connectionDetails() {
|
||||
return new Neo4jConnectionDetails() {
|
||||
|
||||
@Override
|
||||
public URI getUri() {
|
||||
return URI.create(neo4j.getBoltUrl());
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthToken getAuthToken() {
|
||||
return AuthTokens.basic("neo4j", neo4j.getAdminPassword());
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,114 +0,0 @@
|
||||
/*
|
||||
* 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.pulsar;
|
||||
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.testcontainers.containers.PulsarContainer;
|
||||
import org.testcontainers.junit.jupiter.Container;
|
||||
import org.testcontainers.junit.jupiter.Testcontainers;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.web.server.servlet.tomcat.TomcatServletWebServerAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration;
|
||||
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.testsupport.container.TestImage;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.pulsar.annotation.PulsarListener;
|
||||
import org.springframework.pulsar.core.PulsarTemplate;
|
||||
import org.springframework.test.context.DynamicPropertyRegistry;
|
||||
import org.springframework.test.context.DynamicPropertySource;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Integration tests for {@link PulsarAutoConfiguration}.
|
||||
*
|
||||
* @author Chris Bono
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
|
||||
@Testcontainers(disabledWithoutDocker = true)
|
||||
class PulsarAutoConfigurationIntegrationTests {
|
||||
|
||||
@Container
|
||||
static final PulsarContainer pulsar = TestImage.container(PulsarContainer.class);
|
||||
|
||||
private static final CountDownLatch listenLatch = new CountDownLatch(1);
|
||||
|
||||
private static final String TOPIC = "pacit-hello-topic";
|
||||
|
||||
@DynamicPropertySource
|
||||
static void pulsarProperties(DynamicPropertyRegistry registry) {
|
||||
registry.add("spring.pulsar.client.service-url", pulsar::getPulsarBrokerUrl);
|
||||
registry.add("spring.pulsar.admin.service-url", pulsar::getHttpServiceUrl);
|
||||
}
|
||||
|
||||
@Test
|
||||
void appStartsWithAutoConfiguredSpringPulsarComponents(
|
||||
@Autowired(required = false) PulsarTemplate<String> pulsarTemplate) {
|
||||
assertThat(pulsarTemplate).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void templateCanBeAccessedDuringWebRequest(@Autowired TestRestTemplate restTemplate) throws InterruptedException {
|
||||
assertThat(restTemplate.getForObject("/hello", String.class)).startsWith("Hello World -> ");
|
||||
assertThat(listenLatch.await(5, TimeUnit.SECONDS)).isTrue();
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ImportAutoConfiguration({ DispatcherServletAutoConfiguration.class, TomcatServletWebServerAutoConfiguration.class,
|
||||
WebMvcAutoConfiguration.class, HttpMessageConvertersAutoConfiguration.class, JacksonAutoConfiguration.class,
|
||||
PulsarAutoConfiguration.class, PulsarReactiveAutoConfiguration.class })
|
||||
@Import(TestWebController.class)
|
||||
static class TestConfiguration {
|
||||
|
||||
@PulsarListener(subscriptionName = TOPIC + "-sub", topics = TOPIC)
|
||||
void listen(String ignored) {
|
||||
listenLatch.countDown();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@RestController
|
||||
static class TestWebController {
|
||||
|
||||
private final PulsarTemplate<String> pulsarTemplate;
|
||||
|
||||
TestWebController(PulsarTemplate<String> pulsarTemplate) {
|
||||
this.pulsarTemplate = pulsarTemplate;
|
||||
}
|
||||
|
||||
@GetMapping("/hello")
|
||||
String sayHello() {
|
||||
return "Hello World -> " + this.pulsarTemplate.send(TOPIC, "hello");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,137 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2024 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.session;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.testcontainers.containers.MongoDBContainer;
|
||||
import org.testcontainers.junit.jupiter.Container;
|
||||
import org.testcontainers.junit.jupiter.Testcontainers;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.data.mongo.MongoReactiveDataAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.mongo.MongoReactiveAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.web.reactive.WebSessionIdResolverAutoConfiguration;
|
||||
import org.springframework.boot.test.context.FilteredClassLoader;
|
||||
import org.springframework.boot.test.context.assertj.AssertableReactiveWebApplicationContext;
|
||||
import org.springframework.boot.test.context.runner.ContextConsumer;
|
||||
import org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;
|
||||
import org.springframework.boot.testsupport.container.TestImage;
|
||||
import org.springframework.http.ResponseCookie;
|
||||
import org.springframework.session.MapSession;
|
||||
import org.springframework.session.data.mongo.ReactiveMongoSessionRepository;
|
||||
import org.springframework.session.data.redis.ReactiveRedisSessionRepository;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Mongo-specific tests for {@link SessionAutoConfiguration}.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
* @author Weix Sun
|
||||
*/
|
||||
@Testcontainers(disabledWithoutDocker = true)
|
||||
class ReactiveSessionAutoConfigurationMongoTests extends AbstractSessionAutoConfigurationTests {
|
||||
|
||||
@Container
|
||||
static final MongoDBContainer mongoDb = TestImage.container(MongoDBContainer.class);
|
||||
|
||||
private final ReactiveWebApplicationContextRunner contextRunner = new ReactiveWebApplicationContextRunner()
|
||||
.withClassLoader(new FilteredClassLoader(ReactiveRedisSessionRepository.class))
|
||||
.withConfiguration(AutoConfigurations.of(SessionAutoConfiguration.class, MongoAutoConfiguration.class,
|
||||
MongoDataAutoConfiguration.class, MongoReactiveAutoConfiguration.class,
|
||||
MongoReactiveDataAutoConfiguration.class));
|
||||
|
||||
@Test
|
||||
void defaultConfig() {
|
||||
this.contextRunner.withPropertyValues("spring.data.mongodb.uri=" + mongoDb.getReplicaSetUrl())
|
||||
.run(validateSpringSessionUsesMongo("sessions"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void defaultConfigWithCustomTimeout() {
|
||||
this.contextRunner
|
||||
.withPropertyValues("spring.session.timeout=1m", "spring.data.mongodb.uri=" + mongoDb.getReplicaSetUrl())
|
||||
.run((context) -> {
|
||||
ReactiveMongoSessionRepository repository = validateSessionRepository(context,
|
||||
ReactiveMongoSessionRepository.class);
|
||||
assertThat(repository).hasFieldOrPropertyWithValue("defaultMaxInactiveInterval", Duration.ofMinutes(1));
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void defaultConfigWithCustomSessionTimeout() {
|
||||
this.contextRunner
|
||||
.withPropertyValues("server.reactive.session.timeout=1m",
|
||||
"spring.data.mongodb.uri=" + mongoDb.getReplicaSetUrl())
|
||||
.run((context) -> {
|
||||
ReactiveMongoSessionRepository repository = validateSessionRepository(context,
|
||||
ReactiveMongoSessionRepository.class);
|
||||
assertThat(repository).hasFieldOrPropertyWithValue("defaultMaxInactiveInterval", Duration.ofMinutes(1));
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void mongoSessionStoreWithCustomizations() {
|
||||
this.contextRunner
|
||||
.withPropertyValues("spring.session.mongodb.collection-name=foo",
|
||||
"spring.data.mongodb.uri=" + mongoDb.getReplicaSetUrl())
|
||||
.run(validateSpringSessionUsesMongo("foo"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void sessionCookieConfigurationIsAppliedToAutoConfiguredWebSessionIdResolver() {
|
||||
AutoConfigurations autoConfigurations = AutoConfigurations.of(SessionAutoConfiguration.class,
|
||||
MongoAutoConfiguration.class, MongoDataAutoConfiguration.class, MongoReactiveAutoConfiguration.class,
|
||||
MongoReactiveDataAutoConfiguration.class, WebSessionIdResolverAutoConfiguration.class);
|
||||
new ReactiveWebApplicationContextRunner().withConfiguration(autoConfigurations)
|
||||
.withUserConfiguration(Config.class)
|
||||
.withClassLoader(new FilteredClassLoader(ReactiveRedisSessionRepository.class))
|
||||
.withPropertyValues("server.reactive.session.cookie.name:JSESSIONID",
|
||||
"server.reactive.session.cookie.domain:.example.com",
|
||||
"server.reactive.session.cookie.path:/example", "server.reactive.session.cookie.max-age:60",
|
||||
"server.reactive.session.cookie.http-only:false", "server.reactive.session.cookie.secure:false",
|
||||
"server.reactive.session.cookie.same-site:strict",
|
||||
"spring.data.mongodb.uri=" + mongoDb.getReplicaSetUrl())
|
||||
.run(assertExchangeWithSession((exchange) -> {
|
||||
List<ResponseCookie> cookies = exchange.getResponse().getCookies().get("JSESSIONID");
|
||||
assertThat(cookies).isNotEmpty();
|
||||
assertThat(cookies).allMatch((cookie) -> cookie.getDomain().equals(".example.com"));
|
||||
assertThat(cookies).allMatch((cookie) -> cookie.getPath().equals("/example"));
|
||||
assertThat(cookies).allMatch((cookie) -> cookie.getMaxAge().equals(Duration.ofSeconds(60)));
|
||||
assertThat(cookies).allMatch((cookie) -> !cookie.isHttpOnly());
|
||||
assertThat(cookies).allMatch((cookie) -> !cookie.isSecure());
|
||||
assertThat(cookies).allMatch((cookie) -> cookie.getSameSite().equals("Strict"));
|
||||
}));
|
||||
}
|
||||
|
||||
private ContextConsumer<AssertableReactiveWebApplicationContext> validateSpringSessionUsesMongo(
|
||||
String collectionName) {
|
||||
return (context) -> {
|
||||
ReactiveMongoSessionRepository repository = validateSessionRepository(context,
|
||||
ReactiveMongoSessionRepository.class);
|
||||
assertThat(repository.getCollectionName()).isEqualTo(collectionName);
|
||||
assertThat(repository).hasFieldOrPropertyWithValue("defaultMaxInactiveInterval",
|
||||
MapSession.DEFAULT_MAX_INACTIVE_INTERVAL);
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,230 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2024 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.session;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.redis.testcontainers.RedisContainer;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.testcontainers.junit.jupiter.Container;
|
||||
import org.testcontainers.junit.jupiter.Testcontainers;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.data.redis.RedisReactiveAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.web.ServerProperties;
|
||||
import org.springframework.boot.autoconfigure.web.reactive.WebSessionIdResolverAutoConfiguration;
|
||||
import org.springframework.boot.test.context.FilteredClassLoader;
|
||||
import org.springframework.boot.test.context.assertj.AssertableReactiveWebApplicationContext;
|
||||
import org.springframework.boot.test.context.runner.ContextConsumer;
|
||||
import org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;
|
||||
import org.springframework.boot.testsupport.container.TestImage;
|
||||
import org.springframework.data.redis.connection.ReactiveRedisConnection;
|
||||
import org.springframework.data.redis.connection.ReactiveRedisConnectionFactory;
|
||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||
import org.springframework.http.ResponseCookie;
|
||||
import org.springframework.session.MapSession;
|
||||
import org.springframework.session.SaveMode;
|
||||
import org.springframework.session.data.mongo.ReactiveMongoSessionRepository;
|
||||
import org.springframework.session.data.redis.ReactiveRedisIndexedSessionRepository;
|
||||
import org.springframework.session.data.redis.ReactiveRedisSessionRepository;
|
||||
import org.springframework.session.data.redis.config.ConfigureReactiveRedisAction;
|
||||
import org.springframework.session.data.redis.config.annotation.ConfigureNotifyKeyspaceEventsReactiveAction;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.entry;
|
||||
|
||||
/**
|
||||
* Reactive Redis-specific tests for {@link SessionAutoConfiguration}.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @author Andy Wilkinson
|
||||
* @author Vedran Pavic
|
||||
* @author Weix Sun
|
||||
*/
|
||||
@Testcontainers(disabledWithoutDocker = true)
|
||||
class ReactiveSessionAutoConfigurationRedisTests extends AbstractSessionAutoConfigurationTests {
|
||||
|
||||
@Container
|
||||
public static RedisContainer redis = TestImage.container(RedisContainer.class);
|
||||
|
||||
protected final ReactiveWebApplicationContextRunner contextRunner = new ReactiveWebApplicationContextRunner()
|
||||
.withClassLoader(new FilteredClassLoader(ReactiveMongoSessionRepository.class))
|
||||
.withConfiguration(
|
||||
AutoConfigurations.of(SessionAutoConfiguration.class, WebSessionIdResolverAutoConfiguration.class,
|
||||
RedisAutoConfiguration.class, RedisReactiveAutoConfiguration.class));
|
||||
|
||||
@Test
|
||||
void defaultConfig() {
|
||||
this.contextRunner.run(validateSpringSessionUsesRedis("spring:session:", SaveMode.ON_SET_ATTRIBUTE));
|
||||
}
|
||||
|
||||
@Test
|
||||
void redisTakesPrecedenceMultipleImplementations() {
|
||||
ReactiveWebApplicationContextRunner contextRunner = new ReactiveWebApplicationContextRunner().withConfiguration(
|
||||
AutoConfigurations.of(SessionAutoConfiguration.class, WebSessionIdResolverAutoConfiguration.class,
|
||||
RedisAutoConfiguration.class, RedisReactiveAutoConfiguration.class));
|
||||
contextRunner.run(validateSpringSessionUsesRedis("spring:session:", SaveMode.ON_SET_ATTRIBUTE));
|
||||
}
|
||||
|
||||
@Test
|
||||
void defaultConfigWithCustomTimeout() {
|
||||
this.contextRunner.withPropertyValues("spring.session.timeout=1m").run((context) -> {
|
||||
ReactiveRedisSessionRepository repository = validateSessionRepository(context,
|
||||
ReactiveRedisSessionRepository.class);
|
||||
assertThat(repository).hasFieldOrPropertyWithValue("defaultMaxInactiveInterval", Duration.ofMinutes(1));
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void defaultConfigWithCustomWebFluxTimeout() {
|
||||
this.contextRunner.withPropertyValues("server.reactive.session.timeout=1m").run((context) -> {
|
||||
ReactiveRedisSessionRepository repository = validateSessionRepository(context,
|
||||
ReactiveRedisSessionRepository.class);
|
||||
assertThat(repository).hasFieldOrPropertyWithValue("defaultMaxInactiveInterval", Duration.ofMinutes(1));
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void redisSessionStoreWithCustomizations() {
|
||||
this.contextRunner
|
||||
.withPropertyValues("spring.session.redis.namespace=foo", "spring.session.redis.save-mode=on-get-attribute")
|
||||
.run(validateSpringSessionUsesRedis("foo:", SaveMode.ON_GET_ATTRIBUTE));
|
||||
}
|
||||
|
||||
@Test
|
||||
void sessionCookieConfigurationIsAppliedToAutoConfiguredWebSessionIdResolver() {
|
||||
this.contextRunner.withUserConfiguration(Config.class)
|
||||
.withPropertyValues("spring.data.redis.host=" + redis.getHost(),
|
||||
"spring.data.redis.port=" + redis.getFirstMappedPort(),
|
||||
"server.reactive.session.cookie.name:JSESSIONID",
|
||||
"server.reactive.session.cookie.domain:.example.com",
|
||||
"server.reactive.session.cookie.path:/example", "server.reactive.session.cookie.max-age:60",
|
||||
"server.reactive.session.cookie.http-only:false", "server.reactive.session.cookie.secure:false",
|
||||
"server.reactive.session.cookie.same-site:strict")
|
||||
.run(assertExchangeWithSession((exchange) -> {
|
||||
List<ResponseCookie> cookies = exchange.getResponse().getCookies().get("JSESSIONID");
|
||||
assertThat(cookies).isNotEmpty();
|
||||
assertThat(cookies).allMatch((cookie) -> cookie.getDomain().equals(".example.com"));
|
||||
assertThat(cookies).allMatch((cookie) -> cookie.getPath().equals("/example"));
|
||||
assertThat(cookies).allMatch((cookie) -> cookie.getMaxAge().equals(Duration.ofSeconds(60)));
|
||||
assertThat(cookies).allMatch((cookie) -> !cookie.isHttpOnly());
|
||||
assertThat(cookies).allMatch((cookie) -> !cookie.isSecure());
|
||||
assertThat(cookies).allMatch((cookie) -> cookie.getSameSite().equals("Strict"));
|
||||
}));
|
||||
}
|
||||
|
||||
@Test
|
||||
void indexedRedisSessionDefaultConfig() {
|
||||
this.contextRunner
|
||||
.withPropertyValues("spring.session.redis.repository-type=indexed",
|
||||
"spring.data.redis.host=" + redis.getHost(), "spring.data.redis.port=" + redis.getFirstMappedPort())
|
||||
.withConfiguration(AutoConfigurations.of(RedisAutoConfiguration.class))
|
||||
.run(validateSpringSessionUsesIndexedRedis("spring:session:", SaveMode.ON_SET_ATTRIBUTE));
|
||||
}
|
||||
|
||||
@Test
|
||||
void indexedRedisSessionStoreWithCustomizations() {
|
||||
this.contextRunner.withConfiguration(AutoConfigurations.of(RedisAutoConfiguration.class))
|
||||
.withPropertyValues("spring.session.redis.repository-type=indexed", "spring.session.redis.namespace=foo",
|
||||
"spring.session.redis.save-mode=on-get-attribute", "spring.data.redis.host=" + redis.getHost(),
|
||||
"spring.data.redis.port=" + redis.getFirstMappedPort())
|
||||
.run(validateSpringSessionUsesIndexedRedis("foo:", SaveMode.ON_GET_ATTRIBUTE));
|
||||
}
|
||||
|
||||
@Test
|
||||
void indexedRedisSessionWithConfigureActionNone() {
|
||||
this.contextRunner.withConfiguration(AutoConfigurations.of(RedisAutoConfiguration.class))
|
||||
.withPropertyValues("spring.session.redis.repository-type=indexed",
|
||||
"spring.session.redis.configure-action=none", "spring.data.redis.host=" + redis.getHost(),
|
||||
"spring.data.redis.port=" + redis.getFirstMappedPort())
|
||||
.run(validateStrategy(ConfigureReactiveRedisAction.NO_OP.getClass()));
|
||||
}
|
||||
|
||||
@Test
|
||||
void indexedRedisSessionWithDefaultConfigureActionNone() {
|
||||
this.contextRunner.withConfiguration(AutoConfigurations.of(RedisAutoConfiguration.class))
|
||||
.withPropertyValues("spring.session.redis.repository-type=indexed",
|
||||
"spring.data.redis.host=" + redis.getHost(), "spring.data.redis.port=" + redis.getFirstMappedPort())
|
||||
.run(validateStrategy(ConfigureNotifyKeyspaceEventsReactiveAction.class,
|
||||
entry("notify-keyspace-events", "gxE")));
|
||||
}
|
||||
|
||||
@Test
|
||||
void indexedRedisSessionWithCustomConfigureReactiveRedisActionBean() {
|
||||
this.contextRunner.withConfiguration(AutoConfigurations.of(RedisAutoConfiguration.class))
|
||||
.withUserConfiguration(MaxEntriesReactiveRedisAction.class)
|
||||
.withPropertyValues("spring.session.redis.repository-type=indexed",
|
||||
"spring.data.redis.host=" + redis.getHost(), "spring.data.redis.port=" + redis.getFirstMappedPort())
|
||||
.run(validateStrategy(MaxEntriesReactiveRedisAction.class, entry("set-max-intset-entries", "1024")));
|
||||
|
||||
}
|
||||
|
||||
private ContextConsumer<AssertableReactiveWebApplicationContext> validateSpringSessionUsesRedis(String namespace,
|
||||
SaveMode saveMode) {
|
||||
return (context) -> {
|
||||
ReactiveRedisSessionRepository repository = validateSessionRepository(context,
|
||||
ReactiveRedisSessionRepository.class);
|
||||
assertThat(repository).hasFieldOrPropertyWithValue("defaultMaxInactiveInterval",
|
||||
MapSession.DEFAULT_MAX_INACTIVE_INTERVAL);
|
||||
assertThat(repository).hasFieldOrPropertyWithValue("namespace", namespace);
|
||||
assertThat(repository).hasFieldOrPropertyWithValue("saveMode", saveMode);
|
||||
};
|
||||
}
|
||||
|
||||
private ContextConsumer<AssertableReactiveWebApplicationContext> validateSpringSessionUsesIndexedRedis(
|
||||
String keyNamespace, SaveMode saveMode) {
|
||||
return (context) -> {
|
||||
ReactiveRedisIndexedSessionRepository repository = validateSessionRepository(context,
|
||||
ReactiveRedisIndexedSessionRepository.class);
|
||||
assertThat(repository).hasFieldOrPropertyWithValue("defaultMaxInactiveInterval",
|
||||
new ServerProperties().getReactive().getSession().getTimeout());
|
||||
assertThat(repository).hasFieldOrPropertyWithValue("namespace", keyNamespace);
|
||||
assertThat(repository).hasFieldOrPropertyWithValue("saveMode", saveMode);
|
||||
};
|
||||
}
|
||||
|
||||
private ContextConsumer<AssertableReactiveWebApplicationContext> validateStrategy(
|
||||
Class<? extends ConfigureReactiveRedisAction> expectedConfigureReactiveRedisActionType,
|
||||
Map.Entry<?, ?>... expectedConfig) {
|
||||
return (context) -> {
|
||||
assertThat(context).hasSingleBean(ConfigureReactiveRedisAction.class);
|
||||
assertThat(context).hasSingleBean(RedisConnectionFactory.class);
|
||||
assertThat(context.getBean(ConfigureReactiveRedisAction.class))
|
||||
.isInstanceOf(expectedConfigureReactiveRedisActionType);
|
||||
ReactiveRedisConnection connection = context.getBean(ReactiveRedisConnectionFactory.class)
|
||||
.getReactiveConnection();
|
||||
if (expectedConfig.length > 0) {
|
||||
assertThat(connection.serverCommands().getConfig("*").block(Duration.ofSeconds(30)))
|
||||
.contains(expectedConfig);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static class MaxEntriesReactiveRedisAction implements ConfigureReactiveRedisAction {
|
||||
|
||||
@Override
|
||||
public Mono<Void> configure(ReactiveRedisConnection connection) {
|
||||
return Mono.when(connection.serverCommands().setConfig("set-max-intset-entries", "1024"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,112 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2024 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.session;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.testcontainers.containers.MongoDBContainer;
|
||||
import org.testcontainers.junit.jupiter.Container;
|
||||
import org.testcontainers.junit.jupiter.Testcontainers;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.web.ServerProperties;
|
||||
import org.springframework.boot.test.context.FilteredClassLoader;
|
||||
import org.springframework.boot.test.context.assertj.AssertableWebApplicationContext;
|
||||
import org.springframework.boot.test.context.runner.ContextConsumer;
|
||||
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
|
||||
import org.springframework.boot.testsupport.container.TestImage;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.session.config.SessionRepositoryCustomizer;
|
||||
import org.springframework.session.data.mongo.MongoIndexedSessionRepository;
|
||||
import org.springframework.session.data.redis.RedisIndexedSessionRepository;
|
||||
import org.springframework.session.hazelcast.HazelcastIndexedSessionRepository;
|
||||
import org.springframework.session.jdbc.JdbcIndexedSessionRepository;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Mongo-specific tests for {@link SessionAutoConfiguration}.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
@Testcontainers(disabledWithoutDocker = true)
|
||||
class SessionAutoConfigurationMongoTests extends AbstractSessionAutoConfigurationTests {
|
||||
|
||||
@Container
|
||||
static final MongoDBContainer mongoDb = TestImage.container(MongoDBContainer.class);
|
||||
|
||||
private final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()
|
||||
.withClassLoader(new FilteredClassLoader(HazelcastIndexedSessionRepository.class,
|
||||
JdbcIndexedSessionRepository.class, RedisIndexedSessionRepository.class))
|
||||
.withConfiguration(AutoConfigurations.of(MongoAutoConfiguration.class, MongoDataAutoConfiguration.class,
|
||||
SessionAutoConfiguration.class))
|
||||
.withPropertyValues("spring.data.mongodb.uri=" + mongoDb.getReplicaSetUrl());
|
||||
|
||||
@Test
|
||||
void defaultConfig() {
|
||||
this.contextRunner.run(validateSpringSessionUsesMongo("sessions"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void defaultConfigWithCustomTimeout() {
|
||||
this.contextRunner.withPropertyValues("spring.session.timeout=1m")
|
||||
.run(validateSpringSessionUsesMongo("sessions", Duration.ofMinutes(1)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void mongoSessionStoreWithCustomizations() {
|
||||
this.contextRunner.withPropertyValues("spring.session.mongodb.collection-name=foo")
|
||||
.run(validateSpringSessionUsesMongo("foo"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenTheUserDefinesTheirOwnSessionRepositoryCustomizerThenDefaultConfigurationIsOverwritten() {
|
||||
this.contextRunner.withUserConfiguration(CustomizerConfiguration.class)
|
||||
.withPropertyValues("spring.session.mongodb.collection-name=foo")
|
||||
.run(validateSpringSessionUsesMongo("customized"));
|
||||
}
|
||||
|
||||
private ContextConsumer<AssertableWebApplicationContext> validateSpringSessionUsesMongo(String collectionName) {
|
||||
return validateSpringSessionUsesMongo(collectionName,
|
||||
new ServerProperties().getServlet().getSession().getTimeout());
|
||||
}
|
||||
|
||||
private ContextConsumer<AssertableWebApplicationContext> validateSpringSessionUsesMongo(String collectionName,
|
||||
Duration timeout) {
|
||||
return (context) -> {
|
||||
MongoIndexedSessionRepository repository = validateSessionRepository(context,
|
||||
MongoIndexedSessionRepository.class);
|
||||
assertThat(repository).hasFieldOrPropertyWithValue("collectionName", collectionName);
|
||||
assertThat(repository).hasFieldOrPropertyWithValue("defaultMaxInactiveInterval", timeout);
|
||||
};
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class CustomizerConfiguration {
|
||||
|
||||
@Bean
|
||||
SessionRepositoryCustomizer<MongoIndexedSessionRepository> sessionRepositoryCustomizer() {
|
||||
return (repository) -> repository.setCollectionName("customized");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,265 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2024 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.session;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.Map;
|
||||
|
||||
import com.redis.testcontainers.RedisContainer;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.testcontainers.junit.jupiter.Container;
|
||||
import org.testcontainers.junit.jupiter.Testcontainers;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.web.ServerProperties;
|
||||
import org.springframework.boot.context.properties.source.InvalidConfigurationPropertyValueException;
|
||||
import org.springframework.boot.test.context.FilteredClassLoader;
|
||||
import org.springframework.boot.test.context.assertj.AssertableWebApplicationContext;
|
||||
import org.springframework.boot.test.context.runner.ContextConsumer;
|
||||
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
|
||||
import org.springframework.boot.testsupport.container.TestImage;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.redis.connection.RedisConnection;
|
||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||
import org.springframework.session.FlushMode;
|
||||
import org.springframework.session.SaveMode;
|
||||
import org.springframework.session.config.SessionRepositoryCustomizer;
|
||||
import org.springframework.session.data.mongo.MongoIndexedSessionRepository;
|
||||
import org.springframework.session.data.redis.RedisIndexedSessionRepository;
|
||||
import org.springframework.session.data.redis.RedisSessionRepository;
|
||||
import org.springframework.session.data.redis.config.ConfigureNotifyKeyspaceEventsAction;
|
||||
import org.springframework.session.data.redis.config.ConfigureRedisAction;
|
||||
import org.springframework.session.hazelcast.HazelcastIndexedSessionRepository;
|
||||
import org.springframework.session.jdbc.JdbcIndexedSessionRepository;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.entry;
|
||||
|
||||
/**
|
||||
* Redis specific tests for {@link SessionAutoConfiguration}.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @author Vedran Pavic
|
||||
*/
|
||||
@Testcontainers(disabledWithoutDocker = true)
|
||||
class SessionAutoConfigurationRedisTests extends AbstractSessionAutoConfigurationTests {
|
||||
|
||||
@Container
|
||||
public static RedisContainer redis = TestImage.container(RedisContainer.class);
|
||||
|
||||
protected final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()
|
||||
.withClassLoader(new FilteredClassLoader(HazelcastIndexedSessionRepository.class,
|
||||
JdbcIndexedSessionRepository.class, MongoIndexedSessionRepository.class))
|
||||
.withConfiguration(AutoConfigurations.of(SessionAutoConfiguration.class));
|
||||
|
||||
@Test
|
||||
void defaultConfig() {
|
||||
this.contextRunner
|
||||
.withPropertyValues("spring.data.redis.host=" + redis.getHost(),
|
||||
"spring.data.redis.port=" + redis.getFirstMappedPort())
|
||||
.withConfiguration(AutoConfigurations.of(RedisAutoConfiguration.class))
|
||||
.run(validateSpringSessionUsesDefaultRedis("spring:session:", FlushMode.ON_SAVE,
|
||||
SaveMode.ON_SET_ATTRIBUTE));
|
||||
}
|
||||
|
||||
@Test
|
||||
void invalidConfigurationPropertyValueWhenDefaultConfigIsUsedWithCustomCronCleanup() {
|
||||
this.contextRunner.withPropertyValues("spring.data.redis.host=" + redis.getHost(),
|
||||
"spring.data.redis.port=" + redis.getFirstMappedPort(), "spring.session.redis.cleanup-cron=0 0 * * * *")
|
||||
.withConfiguration(AutoConfigurations.of(RedisAutoConfiguration.class))
|
||||
.run((context) -> {
|
||||
assertThat(context).hasFailed();
|
||||
assertThat(context.getStartupFailure())
|
||||
.hasRootCauseExactlyInstanceOf(InvalidConfigurationPropertyValueException.class);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void redisTakesPrecedenceMultipleImplementations() {
|
||||
this.contextRunner.withConfiguration(AutoConfigurations.of(RedisAutoConfiguration.class))
|
||||
.withPropertyValues("spring.data.redis.host=" + redis.getHost(),
|
||||
"spring.data.redis.port=" + redis.getFirstMappedPort())
|
||||
.run(validateSpringSessionUsesDefaultRedis("spring:session:", FlushMode.ON_SAVE,
|
||||
SaveMode.ON_SET_ATTRIBUTE));
|
||||
}
|
||||
|
||||
@Test
|
||||
void defaultConfigWithCustomTimeout() {
|
||||
this.contextRunner
|
||||
.withPropertyValues("spring.data.redis.host=" + redis.getHost(),
|
||||
"spring.data.redis.port=" + redis.getFirstMappedPort(), "spring.session.timeout=1m")
|
||||
.withConfiguration(AutoConfigurations.of(RedisAutoConfiguration.class))
|
||||
.run((context) -> {
|
||||
RedisSessionRepository repository = validateSessionRepository(context, RedisSessionRepository.class);
|
||||
assertThat(repository).hasFieldOrPropertyWithValue("defaultMaxInactiveInterval", Duration.ofMinutes(1));
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void defaultRedisSessionStoreWithCustomizations() {
|
||||
this.contextRunner.withConfiguration(AutoConfigurations.of(RedisAutoConfiguration.class))
|
||||
.withPropertyValues("spring.session.redis.namespace=foo", "spring.session.redis.flush-mode=immediate",
|
||||
"spring.session.redis.save-mode=on-get-attribute", "spring.data.redis.host=" + redis.getHost(),
|
||||
"spring.data.redis.port=" + redis.getFirstMappedPort())
|
||||
.run(validateSpringSessionUsesDefaultRedis("foo:", FlushMode.IMMEDIATE, SaveMode.ON_GET_ATTRIBUTE));
|
||||
}
|
||||
|
||||
@Test
|
||||
void indexedRedisSessionDefaultConfig() {
|
||||
this.contextRunner
|
||||
.withPropertyValues("spring.session.redis.repository-type=indexed",
|
||||
"spring.data.redis.host=" + redis.getHost(), "spring.data.redis.port=" + redis.getFirstMappedPort())
|
||||
.withConfiguration(AutoConfigurations.of(RedisAutoConfiguration.class))
|
||||
.run(validateSpringSessionUsesIndexedRedis("spring:session:", FlushMode.ON_SAVE, SaveMode.ON_SET_ATTRIBUTE,
|
||||
"0 * * * * *"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void indexedRedisSessionStoreWithCustomizations() {
|
||||
this.contextRunner.withConfiguration(AutoConfigurations.of(RedisAutoConfiguration.class))
|
||||
.withPropertyValues("spring.session.redis.repository-type=indexed", "spring.session.redis.namespace=foo",
|
||||
"spring.session.redis.flush-mode=immediate", "spring.session.redis.save-mode=on-get-attribute",
|
||||
"spring.session.redis.cleanup-cron=0 0 12 * * *", "spring.data.redis.host=" + redis.getHost(),
|
||||
"spring.data.redis.port=" + redis.getFirstMappedPort())
|
||||
.run(validateSpringSessionUsesIndexedRedis("foo:", FlushMode.IMMEDIATE, SaveMode.ON_GET_ATTRIBUTE,
|
||||
"0 0 12 * * *"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void indexedRedisSessionWithConfigureActionNone() {
|
||||
this.contextRunner.withConfiguration(AutoConfigurations.of(RedisAutoConfiguration.class))
|
||||
.withPropertyValues("spring.session.redis.repository-type=indexed",
|
||||
"spring.session.redis.configure-action=none", "spring.data.redis.host=" + redis.getHost(),
|
||||
"spring.data.redis.port=" + redis.getFirstMappedPort())
|
||||
.run(validateStrategy(ConfigureRedisAction.NO_OP.getClass()));
|
||||
}
|
||||
|
||||
@Test
|
||||
void indexedRedisSessionWithDefaultConfigureActionNone() {
|
||||
this.contextRunner.withConfiguration(AutoConfigurations.of(RedisAutoConfiguration.class))
|
||||
.withPropertyValues("spring.session.redis.repository-type=indexed",
|
||||
"spring.data.redis.host=" + redis.getHost(), "spring.data.redis.port=" + redis.getFirstMappedPort())
|
||||
.run(validateStrategy(ConfigureNotifyKeyspaceEventsAction.class, entry("notify-keyspace-events", "gxE")));
|
||||
}
|
||||
|
||||
@Test
|
||||
void indexedRedisSessionWithCustomConfigureRedisActionBean() {
|
||||
this.contextRunner.withConfiguration(AutoConfigurations.of(RedisAutoConfiguration.class))
|
||||
.withUserConfiguration(MaxEntriesRedisAction.class)
|
||||
.withPropertyValues("spring.session.redis.repository-type=indexed",
|
||||
"spring.data.redis.host=" + redis.getHost(), "spring.data.redis.port=" + redis.getFirstMappedPort())
|
||||
.run(validateStrategy(MaxEntriesRedisAction.class, entry("set-max-intset-entries", "1024")));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenTheUserDefinesTheirOwnSessionRepositoryCustomizerThenDefaultConfigurationIsOverwritten() {
|
||||
this.contextRunner.withConfiguration(AutoConfigurations.of(RedisAutoConfiguration.class))
|
||||
.withUserConfiguration(CustomizerConfiguration.class)
|
||||
.withPropertyValues("spring.session.redis.flush-mode=immediate",
|
||||
"spring.data.redis.host=" + redis.getHost(), "spring.data.redis.port=" + redis.getFirstMappedPort())
|
||||
.run((context) -> {
|
||||
RedisSessionRepository repository = validateSessionRepository(context, RedisSessionRepository.class);
|
||||
assertThat(repository).hasFieldOrPropertyWithValue("flushMode", FlushMode.ON_SAVE);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenIndexedAndTheUserDefinesTheirOwnSessionRepositoryCustomizerThenDefaultConfigurationIsOverwritten() {
|
||||
this.contextRunner.withConfiguration(AutoConfigurations.of(RedisAutoConfiguration.class))
|
||||
.withUserConfiguration(IndexedCustomizerConfiguration.class)
|
||||
.withPropertyValues("spring.session.redis.repository-type=indexed",
|
||||
"spring.session.redis.flush-mode=immediate", "spring.data.redis.host=" + redis.getHost(),
|
||||
"spring.data.redis.port=" + redis.getFirstMappedPort())
|
||||
.run((context) -> {
|
||||
RedisIndexedSessionRepository repository = validateSessionRepository(context,
|
||||
RedisIndexedSessionRepository.class);
|
||||
assertThat(repository).hasFieldOrPropertyWithValue("flushMode", FlushMode.ON_SAVE);
|
||||
});
|
||||
}
|
||||
|
||||
private ContextConsumer<AssertableWebApplicationContext> validateSpringSessionUsesDefaultRedis(String keyNamespace,
|
||||
FlushMode flushMode, SaveMode saveMode) {
|
||||
return (context) -> {
|
||||
RedisSessionRepository repository = validateSessionRepository(context, RedisSessionRepository.class);
|
||||
assertThat(repository).hasFieldOrPropertyWithValue("defaultMaxInactiveInterval",
|
||||
new ServerProperties().getServlet().getSession().getTimeout());
|
||||
assertThat(repository).hasFieldOrPropertyWithValue("keyNamespace", keyNamespace);
|
||||
assertThat(repository).hasFieldOrPropertyWithValue("flushMode", flushMode);
|
||||
assertThat(repository).hasFieldOrPropertyWithValue("saveMode", saveMode);
|
||||
};
|
||||
}
|
||||
|
||||
private ContextConsumer<AssertableWebApplicationContext> validateSpringSessionUsesIndexedRedis(String keyNamespace,
|
||||
FlushMode flushMode, SaveMode saveMode, String cleanupCron) {
|
||||
return (context) -> {
|
||||
RedisIndexedSessionRepository repository = validateSessionRepository(context,
|
||||
RedisIndexedSessionRepository.class);
|
||||
assertThat(repository).hasFieldOrPropertyWithValue("defaultMaxInactiveInterval",
|
||||
new ServerProperties().getServlet().getSession().getTimeout());
|
||||
assertThat(repository).hasFieldOrPropertyWithValue("namespace", keyNamespace);
|
||||
assertThat(repository).hasFieldOrPropertyWithValue("flushMode", flushMode);
|
||||
assertThat(repository).hasFieldOrPropertyWithValue("saveMode", saveMode);
|
||||
assertThat(repository).hasFieldOrPropertyWithValue("cleanupCron", cleanupCron);
|
||||
};
|
||||
}
|
||||
|
||||
private ContextConsumer<AssertableWebApplicationContext> validateStrategy(
|
||||
Class<? extends ConfigureRedisAction> expectedConfigureRedisActionType, Map.Entry<?, ?>... expectedConfig) {
|
||||
return (context) -> {
|
||||
assertThat(context).hasSingleBean(ConfigureRedisAction.class);
|
||||
assertThat(context).hasSingleBean(RedisConnectionFactory.class);
|
||||
assertThat(context.getBean(ConfigureRedisAction.class)).isInstanceOf(expectedConfigureRedisActionType);
|
||||
RedisConnection connection = context.getBean(RedisConnectionFactory.class).getConnection();
|
||||
if (expectedConfig.length > 0) {
|
||||
assertThat(connection.serverCommands().getConfig("*")).contains(expectedConfig);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static class MaxEntriesRedisAction implements ConfigureRedisAction {
|
||||
|
||||
@Override
|
||||
public void configure(RedisConnection connection) {
|
||||
connection.serverCommands().setConfig("set-max-intset-entries", "1024");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class CustomizerConfiguration {
|
||||
|
||||
@Bean
|
||||
SessionRepositoryCustomizer<RedisSessionRepository> sessionRepositoryCustomizer() {
|
||||
return (repository) -> repository.setFlushMode(FlushMode.ON_SAVE);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class IndexedCustomizerConfiguration {
|
||||
|
||||
@Bean
|
||||
SessionRepositoryCustomizer<RedisIndexedSessionRepository> sessionRepositoryCustomizer() {
|
||||
return (repository) -> repository.setFlushMode(FlushMode.ON_SAVE);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIFhjCCA26gAwIBAgIUfIkk29IT9OpbgfjL8oRIPSLjUcAwDQYJKoZIhvcNAQEL
|
||||
BQAwOzEZMBcGA1UECgwQU3ByaW5nIEJvb3QgVGVzdDEeMBwGA1UEAwwVQ2VydGlm
|
||||
aWNhdGUgQXV0aG9yaXR5MB4XDTI0MDUwMTE2NTMyNVoXDTM0MDQyOTE2NTMyNVow
|
||||
OzEZMBcGA1UECgwQU3ByaW5nIEJvb3QgVGVzdDEeMBwGA1UEAwwVQ2VydGlmaWNh
|
||||
dGUgQXV0aG9yaXR5MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAusN2
|
||||
KzQQUUxZSiI3ZZuZohFwq2KXSUNPdJ6rgD3/YKNTDSZXKZPO53kYPP0DXf0sm3CH
|
||||
cyWSWVabyimZYuPWena1MElSL4ZpJ9WwkZoOQ3bPFK1utz6kMOwrgAUcky8H/rIK
|
||||
j2JEBhkSHUIGr57NjUEwG1ygaSerM8RzWw1PtMq+C8LOu3v94qzE3NDg1QRpyvV9
|
||||
OmsLsjISd0ZmAJNi9vmiEH923KnPyiqnQmWKpYicdgQmX1GXylS22jZqAwaOkYGj
|
||||
X8UdeyvrohkZkM0hn9uaSufQGEW4yKACn3PkjJtzi8drBIyjIi9YcAzBxZB9oVKq
|
||||
XZMlltgO2fDMmIJi0Ngt0Ci7fCoEMqSocKyDKML6YLr9UWtx4bfsrk+rVO9Q/D/v
|
||||
8RKgstv7dCf2KWRX3ZJEC0IBHS5gLNq0qqqVcGx3LcSyhdiKJOtSwAnNkHMh+jSQ
|
||||
xLSlBjcSqTPiGTRK/Rddl+xnU/mBgk7ZBGNrUFaD5McMFjddS7Ih82aHnpQ1gekW
|
||||
nUGv+Tm/G68h2BvZ5U2q+RfeOCgRW9i/AYW2jgT7IFnfjyUXgBQveauMAchomqFE
|
||||
VLe95ZgViF6vmH34EKo3w9L5TQiwk/r53YlM7TSOTyDqx66t4zGYDsVMicpKmzi4
|
||||
2Rp8EpErARRyREUIKSvWs9O9+uT3+7arNLgHe5ECAwEAAaOBgTB/MB0GA1UdDgQW
|
||||
BBRVMLDVqPECWaH6GruL9E52VcTrPjAfBgNVHSMEGDAWgBRVMLDVqPECWaH6GruL
|
||||
9E52VcTrPjAPBgNVHRMBAf8EBTADAQH/MCwGA1UdEQQlMCOCC2V4YW1wbGUuY29t
|
||||
gglsb2NhbGhvc3SCCTEyNy4wLjAuMTANBgkqhkiG9w0BAQsFAAOCAgEAeSpjCL3j
|
||||
2GIFBNKr/5amLOYa0kZ6r1dJs+K6xvMsUvsBJ/QQsV5nYDMIoV/NYUd8SyYV4lEj
|
||||
7LHX5ZbmJrvPk30LGEBG/5Vy2MIATrQrQ14S4nXtEdSnBvTQwPOOaHc+2dTp3YpM
|
||||
f4ffELKWyispTifx1eqdiUJhURKeQBh+3W7zpyaiN4vJaqEDKGgFQtHA/OyZL2hZ
|
||||
BpxHB0zpb2iDHV8MeyfOT7HQWUk6p13vdYm6EnyJT8fzWvE+TqYNbqFmB+CLRSXy
|
||||
R3p1yaeTd4LnVknJ0UBKqEyul3ziHZDhKhBpwdglYOQz4eWjSFhikX9XZ8NaI38Q
|
||||
QqLZVn0DsH2ztkjrQrUVgK2xn4aUuqoLDk4Hu6h5baUn+f2GLuzx+EXc/i3ikYvw
|
||||
Y3JyufOgw6nGGFG+/QXEj85XtLPhN7Wm42z2e/BGzi0MLl65sfpEDXvFTA72Yzws
|
||||
OYaeg/HxeYwUHQgs2fKl/LgV4chntSCvTqfNl6OnQafD/ISJNpx3xWR3HwF+ypFG
|
||||
UaLE+e1soqEJbzL31U/6pypHLsj8Y8r9hJbZXo2ibnhjFV6fypUAP0rbIzaoWcrJ
|
||||
T0Sbliz+KQTMzCcubiAi4bI/kZ5FJ4kkaHqUpIWzlx1h2WVJ65ASFDjBWb8eVmB6
|
||||
Dyno/RVFR/rUL5091gjGRXhLsi1oUHKdEzU=
|
||||
-----END CERTIFICATE-----
|
||||
@@ -1,52 +0,0 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIIJQwIBADANBgkqhkiG9w0BAQEFAASCCS0wggkpAgEAAoICAQC6w3YrNBBRTFlK
|
||||
Ijdlm5miEXCrYpdJQ090nquAPf9go1MNJlcpk87neRg8/QNd/SybcIdzJZJZVpvK
|
||||
KZli49Z6drUwSVIvhmkn1bCRmg5Dds8UrW63PqQw7CuABRyTLwf+sgqPYkQGGRId
|
||||
Qgavns2NQTAbXKBpJ6szxHNbDU+0yr4Lws67e/3irMTc0ODVBGnK9X06awuyMhJ3
|
||||
RmYAk2L2+aIQf3bcqc/KKqdCZYqliJx2BCZfUZfKVLbaNmoDBo6RgaNfxR17K+ui
|
||||
GRmQzSGf25pK59AYRbjIoAKfc+SMm3OLx2sEjKMiL1hwDMHFkH2hUqpdkyWW2A7Z
|
||||
8MyYgmLQ2C3QKLt8KgQypKhwrIMowvpguv1Ra3Hht+yuT6tU71D8P+/xEqCy2/t0
|
||||
J/YpZFfdkkQLQgEdLmAs2rSqqpVwbHctxLKF2Iok61LACc2QcyH6NJDEtKUGNxKp
|
||||
M+IZNEr9F12X7GdT+YGCTtkEY2tQVoPkxwwWN11LsiHzZoeelDWB6RadQa/5Ob8b
|
||||
ryHYG9nlTar5F944KBFb2L8BhbaOBPsgWd+PJReAFC95q4wByGiaoURUt73lmBWI
|
||||
Xq+YffgQqjfD0vlNCLCT+vndiUztNI5PIOrHrq3jMZgOxUyJykqbOLjZGnwSkSsB
|
||||
FHJERQgpK9az07365Pf7tqs0uAd7kQIDAQABAoICAAthB10ggfICHdqXdRqavWST
|
||||
fXLjweXz1O59EGPy4xFnQhMmB99/ovaVeTWWENN0LniWBZqtalpJHZrWqALPcOzr
|
||||
OKTlgr1kihmkOmrUoRPZNErFOl6t0WEtsoTNSu1oyyrofB46VXytoF3p/PBMU6fM
|
||||
lfrEzP07LoIr8P9WM0oHpEahKulfZ5uc/S2bCGfSKgP0qxmZFhBYXqmnv2U/laMI
|
||||
mKg6q+pL6l4d9SzldOobBbVnEVNzbDUmrjFjaVgf2SXiaSrXnrE3ftbUgqtA5FCS
|
||||
F7eCojooXVbT8PT4Ia+zdPnKP6n6S6I0kkXZcSDxacYffEPRSFQFe/opYr3UC+Mk
|
||||
1/UmOnoI8X8+N9SPcVD9cbVQUzBuuXfTy+LMx9mg3QxFebRSRre22xSOSlM7MF9B
|
||||
6MPeNgwCk3Z0NTr+IedGfyA+d6+iHTMGnv0hF4b4UkcXbC3HdeR3K4hf+msGD2oG
|
||||
7JF423T/d7t+g883y4CZm7p096apR8cCLIe2HKSwcYbKhft7LkAdm8kpnqkr5ER1
|
||||
anI7RDmucrx3HgrXeuCz9Uai6EMU6jNU1MAEBVeu4jz1rlO4e9zS2Ak68AwIz0zI
|
||||
tl5el3paHjlRYY6YTslM5qjGerJt19IyHvZxXXIzF7JdF7w1nSK9bjvninALJl49
|
||||
YZAPRIbyQ8P6DLqiDNBFAoIBAQDvQoow86vNg6zHdb8eBC10l2Y6M5DAKTWPE8RJ
|
||||
n0td1TLwEHzKvkR25v6yGKABbBO1+7ABACCqA8rkcB7M5jugak/kR9vuDrFPAsqf
|
||||
lgckf1Up7ekDheTH8X1VSDiRZPv07UElO0M3aFeMVR/xi9Wae8C3WZo9dT2wKnM0
|
||||
d0Acr4Kt4SYm1Dw7kuh+Y1L/vvWuryPm1btxhfKO6JN5v2W8DTrqVkxuxYEM1VnR
|
||||
69LfauLVico2q8EGXmQTth/Iok5wj1qI6kmrlgQR+eSY1qgNk1qzwjJVsbSmAOL8
|
||||
6Y9Ksct53bEN6DIdYRE/SrEVCz/FY1Pry2DNTjdiwImaSOZ3AoIBAQDH1KRkqsET
|
||||
YUnPJxp9pHWlynicEVE/Y7FFhhtpUKzhY1nZ+NsNy91FrZiyx5Os7pSxhLNID8g5
|
||||
xKCOfYd7qdvZCg/5bMXhtagQ3gwa/wyuyamc29dKkCpHDz/GkoEkgVe6eYu1GNdR
|
||||
iNpY5ye5T9fBE1s3odbDcnRVeHAP7vqz5z17JKrlqZVhbLYlR4qGHmAogq7vWlyd
|
||||
IR5qLoXMgyqq5OHl1GaaiqfViBpJeoEWYze0cARUWOcrJRblJYS03WHMuLDG5RZd
|
||||
5nmf2xwEcMgW5AX7+GB8CdXRVZy6OZcGn7TU9+xnBJA2LbzxJlHBXjWEd8Uma2Al
|
||||
+ohlDbGrd8g3AoIBAHsWzGlqstREDbt/xBb5Jzl4OktvA+UYTkmRbcZCgU+Aw3fl
|
||||
w426XRaeuCF/sbGJnIpfNakOG7/bu6HSXMYlHD/m8bsLjQXn4Sg4021OjdYk+/da
|
||||
Qiph09VZU5VwVknWnhjfhkhVOLtknsW/dXOa8QVM7VRmcId1rYrYC/TN9NnNIXm6
|
||||
/xmyzloHtjxvdN/Fqjd4OwwioRBCTQtgc56K7RfV5p1wUFocmcu0Z0UsAYyXPKOH
|
||||
A9Ukf2V7YhkR9UAO4DPgTD9r6QKxZt6opQZMSKDTUjJwkdysU7ejdSOQNPvEhF3p
|
||||
w5DYCBA9Q9Y/4uJkqyYtd5szQlXdC3lufFw3bPkCggEBAKPA3GpmB0xjWEG6UJoP
|
||||
UB1pWwbBpivk/Rr097eI1fLpIHNf29plalE0HcK7i4eWByGllekCjdjRCaVattCe
|
||||
9DraZRbHjS0WWMBhxdfFk9YUCbsx6C4BD7QlieSmn8+TcpmsCtF/psr4870Qx9uy
|
||||
0yI0Q3bGV6DYRP7ZcDOOacFNSHOGK8mB+5jXpjfMdXbMo43u8X3RNb3JqwvmTdy2
|
||||
zBs47ukQ8nfIEhsIqkn2apw2+CoT9WhNZjpT7XwgD6zLEd7apnqGtpqCSL63pjD5
|
||||
Xu5rM4A1HJPo11/w4Ts2AE38SAqRlBcjhS3wszmGZk6obgC8yUFfkm3s7SKqYyMZ
|
||||
SGcCggEBAO0IDB/h1meZ2y+6bSsCVaDSxdRl0JF0CDUYVTANQsJ+q7u7CpF9xOo8
|
||||
YNrSy8eM0K6RMY/3WbTm+4z9tOldxEV2dn+29oVeMKkgpJYo0k2Au3wTMI2xMyyl
|
||||
HZ+ZttsqSZsj2CPx83LMaPwKdzVjwA7alVx4P+AkQKn7jGJgidj5xyw0G3gnzdfT
|
||||
nGzuitQFlcrcPyrVHAAmRhIw+B5CsvMFlM8PAvojN7burGswjWGeZjkgqoLvKlgq
|
||||
jRMGzLTzF9Pay7P/D/pWQwPVGiseJq+QVIA+iILpy9Zb9T6DnBFaPFGOKAduzVU9
|
||||
lTLiho2DATppaxNUQKh/5k70hzbipDg=
|
||||
-----END PRIVATE KEY-----
|
||||
@@ -1,26 +0,0 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEWjCCAkKgAwIBAgIURBZvq442tp+/K9TZII5Vy/LzVx0wDQYJKoZIhvcNAQEL
|
||||
BQAwOzEZMBcGA1UECgwQU3ByaW5nIEJvb3QgVGVzdDEeMBwGA1UEAwwVQ2VydGlm
|
||||
aWNhdGUgQXV0aG9yaXR5MB4XDTI0MDUwMTE2NTMyNVoXDTM0MDQyOTE2NTMyNVow
|
||||
LzEZMBcGA1UECgwQU3ByaW5nIEJvb3QgVGVzdDESMBAGA1UEAwwJbG9jYWxob3N0
|
||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvGb7tu0odSuOjeY1lHlh
|
||||
sRR4PayAvlryjfrrp49hjoVTiL3d/Jo6Po5HlqwJcYuclm0EWQR5Vur/zYJpfUE7
|
||||
b8+E9Qwe50+YzfQ2tVFEdq/VfqemrYRGee+pMelOCI90enOKCxfpo6EHbz+WnUP0
|
||||
mnD8OAF9QpolSdWAMOGJoPdWX65KQvyMXvQbj9VIHmsx7NCaIOYxjHXB/dI2FmXV
|
||||
+m4VT6mb8he9dXmgK/ozMq6XIPOAXe0n3dlfMTSEddeNeVwnBpr/n5e0cpwGFhdf
|
||||
NNu5CI4ecipBhXljJi/4/47M/6hd69HwE05C4zyH4ZDZ2JTfaSKOLV+jYdBUqJP5
|
||||
dwIDAQABo2IwYDALBgNVHQ8EBAMCBaAwEQYJYIZIAYb4QgEBBAQDAgeAMB0GA1Ud
|
||||
DgQWBBRWiWOo9cm2IF/ZlhWLVjifLzYa/DAfBgNVHSMEGDAWgBRVMLDVqPECWaH6
|
||||
GruL9E52VcTrPjANBgkqhkiG9w0BAQsFAAOCAgEAA5Wphtu2nBhY+QNOBOwXq4zF
|
||||
N5qt2IYTLfR7xqpKhhXx9VkIjdPWpcsGuCuMmfPVNvQWE6iK0/jMMqToTj4H6K7e
|
||||
MN74j0GwwcknT1P42tUzEpg8LKR8VMdhWhyqdniCDNWWuaz1iVSoF0S2i4jFSzH5
|
||||
1q3KMKMZ4niK5aJI0fAGa4fCjyuun1Mfg/qGBGwLnqDkIXjeAopZf4Jb64TtzjAs
|
||||
j9NT6mYbe3E0tw3fHT9ihYdbZDZgSjeCsuq9OiRMVb0DWWmRoLmmOrlN8IJlHV/3
|
||||
WyI/ta4Cw5EZ0oaOg0lIyOxXyvElth1xIvh+kdqZSBsU0gNBri6ZIzYbbTh2KTTO
|
||||
BJHQt9L5naWG27pDrIxBicWXS/MIYonktm3YgCLfuW3kWcVk8bIlNhfcoAYBBgfM
|
||||
IEYSYEq+bH2IQ+YoWQz3AxjJ8gEuuSUP6R6mYY65FfpjkKgcpGBvw4EIAmqKDtPS
|
||||
hlLY/F0XVj9KZzrMyH4/vonu+DAb/P7Zmt2fyk/dQO6bAc3ltRmJbJm4VJ2v/T8I
|
||||
LVu2FtcUYgtLNtkWUPfdb3GSUUgkKlUpWSty31TKSUszJjW1oRykQhEko6o5U3S8
|
||||
ptQzXdApsb1lGOqewkubE25tIu2RLiNkKcjFOjJ/lu0vP9k76wWwRVnFLFvfo4lW
|
||||
pgywiOifs5JbcCt0ZQ0=
|
||||
-----END CERTIFICATE-----
|
||||
@@ -1,28 +0,0 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC8Zvu27Sh1K46N
|
||||
5jWUeWGxFHg9rIC+WvKN+uunj2GOhVOIvd38mjo+jkeWrAlxi5yWbQRZBHlW6v/N
|
||||
gml9QTtvz4T1DB7nT5jN9Da1UUR2r9V+p6athEZ576kx6U4Ij3R6c4oLF+mjoQdv
|
||||
P5adQ/SacPw4AX1CmiVJ1YAw4Ymg91ZfrkpC/Ixe9BuP1UgeazHs0Jog5jGMdcH9
|
||||
0jYWZdX6bhVPqZvyF711eaAr+jMyrpcg84Bd7Sfd2V8xNIR11415XCcGmv+fl7Ry
|
||||
nAYWF18027kIjh5yKkGFeWMmL/j/jsz/qF3r0fATTkLjPIfhkNnYlN9pIo4tX6Nh
|
||||
0FSok/l3AgMBAAECggEABXnBe3MwXAMQENzNypOiXK4VE3XMYkePfdsSK163byOD
|
||||
w3ZeTgQNfU4g8LJK8/homzO0SQIJAdz2+ZFbpsp4A2W2zJ+1jvN5RuX/8/UcVhmk
|
||||
tb1IL/LWCvx5/aoYBWkgIA70UfQJa2jDbdM0v5j/Gu9yE7GI14jh6DFC3xGMGV3b
|
||||
fOwManxf7sDibCI1nGjnFYNGxninRr+tpb+a1KNbVzhett68LrgPmtph6B3HCPAJ
|
||||
zBigk1Phgb8WHozTXxnLyw9/RdKJ0Ro4PFmtQv0EvCSlytptnF+0nXkqr3f851XS
|
||||
bUWwYFchIFWPMhPfD5B3niNWCV42/sU/bQlk+BMQAQKBgQD6NvMq8EdYy2Y7fXT5
|
||||
FgB4s+7EkLgI2d5LUaCXCFgc6iZtCTQKUXj1rIWeRfGrFVCCe8qV+XIMKt/G5eEi
|
||||
tn5ifHhktA2A8GK1scj026qHP3bVn0hMaUnkCF1UpDRKPiEO5G/apPtav8PbCNaX
|
||||
GAimLGw+WZNZuv7+T33bEBeUdwKBgQDAwiidayLXkRkz2deefdDKcXQsB7RHFGGy
|
||||
vfZPBCGqizxml+6ojJkkDsVUKL1IXFfyK9KpQAI6tezn4oktgu4jAQqkYY7QZobs
|
||||
RpQx1dR+KxEm7ISDBTq/B1Q9cFKUKVvQQy8N2pnIbCdzb6MTOKLmJqFGTjr+5T8q
|
||||
F32B5vkDAQKBgDCKfH42AwFc5EZiPlEcTZcdARMtKCa/bXqbKVZjjgR+AFpi0K+3
|
||||
womWoI1l8E5KYkYOEe0qaU+m+aaybgy37qjYkNqoe34qJFwvU1b9ToXScBFdRz9b
|
||||
pbQRU1naSTKl/u/OrUxzeTfPwAU8H7VMOlFSiOVHp2he+J0JetcGtixdAoGBAIJQ
|
||||
QMj7rxhxHcqyEVUy1b6nKNTDeJs9Kjd+uU/+CQyVCQaK3GvScY2w9rLIv/51f3dX
|
||||
LRoDDf7HExxJSFgeVgQQJjOvSK+XQMvngzSVzQxm7TeVWpiBJpAS0l6e2xUTSODp
|
||||
KpyBFsoqZBlkdaj+9xIFN66iILxGG4fHTbBOiDYBAoGBAOZMKjM5N/hGcCmik/6t
|
||||
p/zBA2pN9O6zwPndITTsdyVWSlVqCZhXlRX47CerAN+/WVCidlh7Vp5Tuy75Wa77
|
||||
v16IDLO01txgWNobcLaM4VgFsyLi5JuxK73S18Vb1cKWdHFRF0LH3cUIq20fjpv6
|
||||
Odl4vjNOncXMZCLPHQ+bKWaf
|
||||
-----END PRIVATE KEY-----
|
||||
@@ -1,26 +0,0 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEWjCCAkKgAwIBAgIURBZvq442tp+/K9TZII5Vy/LzVxwwDQYJKoZIhvcNAQEL
|
||||
BQAwOzEZMBcGA1UECgwQU3ByaW5nIEJvb3QgVGVzdDEeMBwGA1UEAwwVQ2VydGlm
|
||||
aWNhdGUgQXV0aG9yaXR5MB4XDTI0MDUwMTE2NTMyNVoXDTM0MDQyOTE2NTMyNVow
|
||||
LzEZMBcGA1UECgwQU3ByaW5nIEJvb3QgVGVzdDESMBAGA1UEAwwJbG9jYWxob3N0
|
||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsllxsSQzTTJlNHMfXC2b
|
||||
CIXCPsfCgCBl7FbPz828jwJk+EYcXh0+WTFGks0WxSwb8NQza5UtyCUDEueZj9fV
|
||||
j5mWBY97WCu01Sl/3xClHmYisXfyyv27GKec7PaSOurCm2JDkyHRNumiJROa4jte
|
||||
N0GOHzw7FYsM3779TuNw14/gtW+eBrGnvgrpU7fbUvx42Di6ftGYQUwIi+3uIaqT
|
||||
//i7ktDMaAQJtkL6haTzZ5JN2qKO5a34/WRz/ApvPw3lpDV8c4qoTk3C0Bg9MP+a
|
||||
DnZtjtLBSN9CJWwr+n11QaMgHTotEKsOahGdi3J2zYxCvJP0LT+hjN2O9aRzSMIs
|
||||
MwIDAQABo2IwYDALBgNVHQ8EBAMCBaAwEQYJYIZIAYb4QgEBBAQDAgZAMB0GA1Ud
|
||||
DgQWBBS9XQHGwJZhG0olAGM1UMNuwZ65DzAfBgNVHSMEGDAWgBRVMLDVqPECWaH6
|
||||
GruL9E52VcTrPjANBgkqhkiG9w0BAQsFAAOCAgEAhBcqm5UQahn8iFMETXvfLMR6
|
||||
OOPijsHQ5lVfhig08s46a9O5eaJ9EYSYyiDnxYvZ4gYVH03f/kPwNLamvGR5KIBQ
|
||||
R0DltkPPX4a11/vjwlSq1cXAt9r59nY+sNcVXWgIWH7zNodL8lyTpYhqvB2wEQkx
|
||||
t2/JKZ8A0sGjed4S6I5HofYd7bnBxQZgfZShQ2SdDbzbcyg4SCEb8ghwnsH0KNZo
|
||||
jJF+20RpK2VMViE6lylLTEMd/PyAdST/NPoqVxyva3QjTrKt+tkkFTsmNVMXcmYC
|
||||
f1xo1/YFp73FFE63VYFI+Yw+Ajau8sYSo4+YvgFCy+Efhf3h3GFDtaiNod56uX9G
|
||||
9M/cu8XsFzFP2e/0YWY3XL+v7ESOdc3g7yS4FQZ7Z6YvfAed9hCB25cDECvZXqJG
|
||||
HSYDR38NHyAPROuCwlEwDyVmWRl9bpwZt+hr9kaTQScIDx+rV/EF3o0GKIwtR7AK
|
||||
jaPAta0f4/Uu+EuWAcccSRUMtfx5/Jse/6iliBvy7JXmA+Y0PrT7K4uHO7iktdI+
|
||||
x8WbfZKfnLVuqw5fneTjC1n48Ltjis/f8DgO7BuWTmLdZXddjqqxzBSukFTBn4Hg
|
||||
/oSg3XiMywOAVrRCNJehcdTG0u/BqZsrRjcYAJaf5qG/0tMLNsuF9Y53XQQAeezE
|
||||
etL+7y0mkeQhVF+Kmy4=
|
||||
-----END CERTIFICATE-----
|
||||
@@ -1,28 +0,0 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEugIBADANBgkqhkiG9w0BAQEFAASCBKQwggSgAgEAAoIBAQCyWXGxJDNNMmU0
|
||||
cx9cLZsIhcI+x8KAIGXsVs/PzbyPAmT4RhxeHT5ZMUaSzRbFLBvw1DNrlS3IJQMS
|
||||
55mP19WPmZYFj3tYK7TVKX/fEKUeZiKxd/LK/bsYp5zs9pI66sKbYkOTIdE26aIl
|
||||
E5riO143QY4fPDsViwzfvv1O43DXj+C1b54Gsae+CulTt9tS/HjYOLp+0ZhBTAiL
|
||||
7e4hqpP/+LuS0MxoBAm2QvqFpPNnkk3aoo7lrfj9ZHP8Cm8/DeWkNXxziqhOTcLQ
|
||||
GD0w/5oOdm2O0sFI30IlbCv6fXVBoyAdOi0Qqw5qEZ2LcnbNjEK8k/QtP6GM3Y71
|
||||
pHNIwiwzAgMBAAECgf9REZuCvy2Bi8SoTnjqQuHG5FuA6cPuisuFZr1k88IO+zJQ
|
||||
uY3WKNs29BV+LcxnoK29W8jQnjqPHXcMfrF5dVWmkrrJdu8JLaGWVHF+uBq8nRb0
|
||||
2LvREh5XhZTGzIESNdc/7GIxdouag/8FlzCUYQGuT3v9+wUCiim+4CuIuPvv7ncD
|
||||
8vANe3Ua5G0mHjVshOiMNpegg45zYlzYpMtUFPs+asLilW6A7UlgC+pLZ1cHUUlU
|
||||
ZB7KOGT9JdrZpilTidl6LLvDDQK30TSWz8A26SuEAE71DR2VEjLVpjTNS76vlx+c
|
||||
CrYr/WwpMb0xul+e/uHiNgo+51FiTiJ/IfuGeskCgYEA804CXQM6i5m4/Upps2yG
|
||||
aTae5xBaYUquZREp5Zb054U6lUAHI41iTMTIwTTvWn5ogNojgi+YjljkzRj2RQ5k
|
||||
NccBkjBBwwUNVWpBoGeZ73KAdejNB4C4ucGc2kkqEDo4MU5x3IE4JK1Yi1jl9mKb
|
||||
IR6m3pqb2PCQHjO8sqKNHYkCgYEAu6fH/qUd/XGmCZJWY5K6jg3dISXH16MTO5M+
|
||||
jetprkGMMybWKZQa1GedXurPexE48oRlRhkjdQkW6Wcj1Qh6OKp6N2Zx8sY4dLeQ
|
||||
yVChnMPFE2LK+UlRCKJUZi+rzX415ML6pZg+yW7O2cHpMKv7PlXISw2YDqtboCAi
|
||||
Y+doqNsCgYBE1yqmBJbZDuqfiCF2KduyA0lcmWzpIEdNw1h2ZIrwwup7dj1O2t8Y
|
||||
V4lx2TdsBF4vLwli+XKRvCcovMpZaaQC70bLhSnmMxS9uS3OY+HTNTORqQfx+oLJ
|
||||
1DU8Mf1b0A08LjTbLhijkASAkOuoFehMq66NR3OXIyGz2fGnHYUN+QKBgCC47SL2
|
||||
X/hl7PIWVoIef/FtcXXqRKLRiPUGhA3zUwZT38K7rvSpItSPDN4UTAHFywxfEdnb
|
||||
YFd0Mk6Y8aKgS8+9ynoGnzAaaJXRvKmeKdBQQvlSbNpzcnHy/IylG2xF6dfuOA7Q
|
||||
MYKmk+Nc8PDPzIveIYMU58MHFn8hm12YaKOpAoGAV1CE8hFkEK9sbRGoKNJkx9nm
|
||||
CZTv7PybaG/RN4ZrBSwVmnER0FEagA/Tzrlp1pi3sC8ZsC9onSOf6Btq8ZE0zbO1
|
||||
vsAm3gTBXcrCJxzw0Wjt8pzEbk3yELm4WE6VDEx4da2jWocdspslpIwdjHnPwsbH
|
||||
r5O3ZAgigZs/ZtKW/U4=
|
||||
-----END PRIVATE KEY-----
|
||||
@@ -27,8 +27,6 @@ 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.context.annotation.ImportCandidates;
|
||||
import org.springframework.boot.tomcat.servlet.TomcatServletWebServerFactory;
|
||||
import org.springframework.boot.web.server.servlet.ServletWebServerFactory;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
@@ -36,10 +34,7 @@ import org.springframework.context.annotation.Import;
|
||||
/**
|
||||
* Enable auto-configuration of the Spring Application Context, attempting to guess and
|
||||
* configure beans that you are likely to need. Auto-configuration classes are usually
|
||||
* applied based on your classpath and what beans you have defined. For example, if you
|
||||
* have {@code tomcat-embedded.jar} on your classpath you are likely to want a
|
||||
* {@link TomcatServletWebServerFactory} (unless you have defined your own
|
||||
* {@link ServletWebServerFactory} bean).
|
||||
* applied based on your classpath and what beans you have defined.
|
||||
* <p>
|
||||
* When using {@link SpringBootApplication @SpringBootApplication}, the auto-configuration
|
||||
* of the context is automatically enabled and adding this annotation has therefore no
|
||||
|
||||
@@ -34,7 +34,6 @@ import org.springframework.context.annotation.ComponentScan.Filter;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.FilterType;
|
||||
import org.springframework.core.annotation.AliasFor;
|
||||
import org.springframework.data.repository.Repository;
|
||||
|
||||
/**
|
||||
* Indicates a {@link Configuration configuration} class that declares one or more
|
||||
@@ -80,9 +79,8 @@ public @interface SpringBootApplication {
|
||||
* <p>
|
||||
* <strong>Note:</strong> this setting is an alias for
|
||||
* {@link ComponentScan @ComponentScan} only. It has no effect on {@code @Entity}
|
||||
* scanning or Spring Data {@link Repository} scanning. For those you should add
|
||||
* {@link org.springframework.boot.autoconfigure.domain.EntityScan @EntityScan} and
|
||||
* {@code @Enable...Repositories} annotations.
|
||||
* scanning or Spring Data repository scanning. For those you should add
|
||||
* {@code @EntityScan} and {@code @Enable...Repositories} annotations.
|
||||
* @return base packages to scan
|
||||
* @since 1.3.0
|
||||
*/
|
||||
@@ -98,9 +96,8 @@ public @interface SpringBootApplication {
|
||||
* <p>
|
||||
* <strong>Note:</strong> this setting is an alias for
|
||||
* {@link ComponentScan @ComponentScan} only. It has no effect on {@code @Entity}
|
||||
* scanning or Spring Data {@link Repository} scanning. For those you should add
|
||||
* {@link org.springframework.boot.autoconfigure.domain.EntityScan @EntityScan} and
|
||||
* {@code @Enable...Repositories} annotations.
|
||||
* scanning or Spring Data repository scanning. For those you should add
|
||||
* {@code @EntityScan} and {@code @Enable...Repositories} annotations.
|
||||
* @return base packages to scan
|
||||
* @since 1.3.0
|
||||
*/
|
||||
|
||||
@@ -1,104 +0,0 @@
|
||||
/*
|
||||
* 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.amqp;
|
||||
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.springframework.amqp.rabbit.connection.AbstractConnectionFactory;
|
||||
import org.springframework.amqp.rabbit.connection.ConnectionNameStrategy;
|
||||
import org.springframework.boot.context.properties.PropertyMapper;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Base class for configurers of sub-classes of {@link AbstractConnectionFactory}.
|
||||
*
|
||||
* @param <T> the connection factory type.
|
||||
* @author Chris Bono
|
||||
* @author Moritz Halbritter
|
||||
* @author Andy Wilkinson
|
||||
* @author Phillip Webb
|
||||
* @since 2.6.0
|
||||
*/
|
||||
public abstract class AbstractConnectionFactoryConfigurer<T extends AbstractConnectionFactory> {
|
||||
|
||||
private final RabbitProperties rabbitProperties;
|
||||
|
||||
private ConnectionNameStrategy connectionNameStrategy;
|
||||
|
||||
private final RabbitConnectionDetails connectionDetails;
|
||||
|
||||
/**
|
||||
* Creates a new configurer that will configure the connection factory using the given
|
||||
* {@code properties}.
|
||||
* @param properties the properties to use to configure the connection factory
|
||||
*/
|
||||
protected AbstractConnectionFactoryConfigurer(RabbitProperties properties) {
|
||||
this(properties, new PropertiesRabbitConnectionDetails(properties, null));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new configurer that will configure the connection factory using the given
|
||||
* {@code properties} and {@code connectionDetails}, with the latter taking priority.
|
||||
* @param properties the properties to use to configure the connection factory
|
||||
* @param connectionDetails the connection details to use to configure the connection
|
||||
* factory
|
||||
* @since 3.1.0
|
||||
*/
|
||||
protected AbstractConnectionFactoryConfigurer(RabbitProperties properties,
|
||||
RabbitConnectionDetails connectionDetails) {
|
||||
Assert.notNull(properties, "'properties' must not be null");
|
||||
Assert.notNull(connectionDetails, "'connectionDetails' must not be null");
|
||||
this.rabbitProperties = properties;
|
||||
this.connectionDetails = connectionDetails;
|
||||
}
|
||||
|
||||
protected final ConnectionNameStrategy getConnectionNameStrategy() {
|
||||
return this.connectionNameStrategy;
|
||||
}
|
||||
|
||||
public final void setConnectionNameStrategy(ConnectionNameStrategy connectionNameStrategy) {
|
||||
this.connectionNameStrategy = connectionNameStrategy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the given {@code connectionFactory} with sensible defaults.
|
||||
* @param connectionFactory connection factory to configure
|
||||
*/
|
||||
public final void configure(T connectionFactory) {
|
||||
Assert.notNull(connectionFactory, "'connectionFactory' must not be null");
|
||||
PropertyMapper map = PropertyMapper.get();
|
||||
String addresses = this.connectionDetails.getAddresses()
|
||||
.stream()
|
||||
.map((address) -> address.host() + ":" + address.port())
|
||||
.collect(Collectors.joining(","));
|
||||
map.from(addresses).to(connectionFactory::setAddresses);
|
||||
map.from(this.rabbitProperties::getAddressShuffleMode)
|
||||
.whenNonNull()
|
||||
.to(connectionFactory::setAddressShuffleMode);
|
||||
map.from(this.connectionNameStrategy).whenNonNull().to(connectionFactory::setConnectionNameStrategy);
|
||||
configure(connectionFactory, this.rabbitProperties);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the given {@code connectionFactory} using the given
|
||||
* {@code rabbitProperties}.
|
||||
* @param connectionFactory connection factory to configure
|
||||
* @param rabbitProperties properties to use for the configuration
|
||||
*/
|
||||
protected abstract void configure(T connectionFactory, RabbitProperties rabbitProperties);
|
||||
|
||||
}
|
||||
@@ -1,152 +0,0 @@
|
||||
/*
|
||||
* 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.amqp;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
import org.springframework.amqp.rabbit.config.AbstractRabbitListenerContainerFactory;
|
||||
import org.springframework.amqp.rabbit.config.RetryInterceptorBuilder;
|
||||
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
|
||||
import org.springframework.amqp.rabbit.retry.MessageRecoverer;
|
||||
import org.springframework.amqp.rabbit.retry.RejectAndDontRequeueRecoverer;
|
||||
import org.springframework.amqp.support.converter.MessageConverter;
|
||||
import org.springframework.boot.autoconfigure.amqp.RabbitProperties.ListenerRetry;
|
||||
import org.springframework.retry.support.RetryTemplate;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Base class for configurers of sub-classes of
|
||||
* {@link AbstractRabbitListenerContainerFactory}.
|
||||
*
|
||||
* @param <T> the container factory type.
|
||||
* @author Gary Russell
|
||||
* @author Stephane Nicoll
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public abstract class AbstractRabbitListenerContainerFactoryConfigurer<T extends AbstractRabbitListenerContainerFactory<?>> {
|
||||
|
||||
private MessageConverter messageConverter;
|
||||
|
||||
private MessageRecoverer messageRecoverer;
|
||||
|
||||
private List<RabbitRetryTemplateCustomizer> retryTemplateCustomizers;
|
||||
|
||||
private final RabbitProperties rabbitProperties;
|
||||
|
||||
private Executor taskExecutor;
|
||||
|
||||
/**
|
||||
* Creates a new configurer that will use the given {@code rabbitProperties}.
|
||||
* @param rabbitProperties properties to use
|
||||
* @since 2.6.0
|
||||
*/
|
||||
protected AbstractRabbitListenerContainerFactoryConfigurer(RabbitProperties rabbitProperties) {
|
||||
this.rabbitProperties = rabbitProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@link MessageConverter} to use or {@code null} if the out-of-the-box
|
||||
* converter should be used.
|
||||
* @param messageConverter the {@link MessageConverter}
|
||||
*/
|
||||
protected void setMessageConverter(MessageConverter messageConverter) {
|
||||
this.messageConverter = messageConverter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@link MessageRecoverer} to use or {@code null} to rely on the default.
|
||||
* @param messageRecoverer the {@link MessageRecoverer}
|
||||
*/
|
||||
protected void setMessageRecoverer(MessageRecoverer messageRecoverer) {
|
||||
this.messageRecoverer = messageRecoverer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@link RabbitRetryTemplateCustomizer} instances to use.
|
||||
* @param retryTemplateCustomizers the retry template customizers
|
||||
*/
|
||||
protected void setRetryTemplateCustomizers(List<RabbitRetryTemplateCustomizer> retryTemplateCustomizers) {
|
||||
this.retryTemplateCustomizers = retryTemplateCustomizers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the task executor to use.
|
||||
* @param taskExecutor the task executor
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public void setTaskExecutor(Executor taskExecutor) {
|
||||
this.taskExecutor = taskExecutor;
|
||||
}
|
||||
|
||||
protected final RabbitProperties getRabbitProperties() {
|
||||
return this.rabbitProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the specified rabbit listener container factory. The factory can be
|
||||
* further tuned and default settings can be overridden.
|
||||
* @param factory the {@link AbstractRabbitListenerContainerFactory} instance to
|
||||
* configure
|
||||
* @param connectionFactory the {@link ConnectionFactory} to use
|
||||
*/
|
||||
public abstract void configure(T factory, ConnectionFactory connectionFactory);
|
||||
|
||||
protected void configure(T factory, ConnectionFactory connectionFactory,
|
||||
RabbitProperties.AmqpContainer configuration) {
|
||||
Assert.notNull(factory, "'factory' must not be null");
|
||||
Assert.notNull(connectionFactory, "'connectionFactory' must not be null");
|
||||
Assert.notNull(configuration, "'configuration' must not be null");
|
||||
factory.setConnectionFactory(connectionFactory);
|
||||
if (this.messageConverter != null) {
|
||||
factory.setMessageConverter(this.messageConverter);
|
||||
}
|
||||
factory.setAutoStartup(configuration.isAutoStartup());
|
||||
if (configuration.getAcknowledgeMode() != null) {
|
||||
factory.setAcknowledgeMode(configuration.getAcknowledgeMode());
|
||||
}
|
||||
if (configuration.getPrefetch() != null) {
|
||||
factory.setPrefetchCount(configuration.getPrefetch());
|
||||
}
|
||||
if (configuration.getDefaultRequeueRejected() != null) {
|
||||
factory.setDefaultRequeueRejected(configuration.getDefaultRequeueRejected());
|
||||
}
|
||||
if (configuration.getIdleEventInterval() != null) {
|
||||
factory.setIdleEventInterval(configuration.getIdleEventInterval().toMillis());
|
||||
}
|
||||
factory.setMissingQueuesFatal(configuration.isMissingQueuesFatal());
|
||||
factory.setDeBatchingEnabled(configuration.isDeBatchingEnabled());
|
||||
factory.setForceStop(configuration.isForceStop());
|
||||
if (this.taskExecutor != null) {
|
||||
factory.setTaskExecutor(this.taskExecutor);
|
||||
}
|
||||
factory.setObservationEnabled(configuration.isObservationEnabled());
|
||||
ListenerRetry retryConfig = configuration.getRetry();
|
||||
if (retryConfig.isEnabled()) {
|
||||
RetryInterceptorBuilder<?, ?> builder = (retryConfig.isStateless()) ? RetryInterceptorBuilder.stateless()
|
||||
: RetryInterceptorBuilder.stateful();
|
||||
RetryTemplate retryTemplate = new RetryTemplateFactory(this.retryTemplateCustomizers)
|
||||
.createRetryTemplate(retryConfig, RabbitRetryTemplateCustomizer.Target.LISTENER);
|
||||
builder.retryOperations(retryTemplate);
|
||||
MessageRecoverer recoverer = (this.messageRecoverer != null) ? this.messageRecoverer
|
||||
: new RejectAndDontRequeueRecoverer();
|
||||
builder.recoverer(recoverer);
|
||||
factory.setAdviceChain(builder.build());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
/*
|
||||
* 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.amqp;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
|
||||
import org.springframework.boot.context.properties.PropertyMapper;
|
||||
|
||||
/**
|
||||
* Configures Rabbit {@link CachingConnectionFactory} with sensible defaults tuned using
|
||||
* configuration properties.
|
||||
* <p>
|
||||
* Can be injected into application code and used to define a custom
|
||||
* {@code CachingConnectionFactory} whose configuration is based upon that produced by
|
||||
* auto-configuration.
|
||||
*
|
||||
* @author Chris Bono
|
||||
* @author Moritz Halbritter
|
||||
* @author Andy Wilkinson
|
||||
* @author Phillip Webb
|
||||
* @since 2.6.0
|
||||
*/
|
||||
public class CachingConnectionFactoryConfigurer extends AbstractConnectionFactoryConfigurer<CachingConnectionFactory> {
|
||||
|
||||
/**
|
||||
* Creates a new configurer that will configure the connection factory using the given
|
||||
* {@code properties}.
|
||||
* @param properties the properties to use to configure the connection factory
|
||||
*/
|
||||
public CachingConnectionFactoryConfigurer(RabbitProperties properties) {
|
||||
this(properties, new PropertiesRabbitConnectionDetails(properties, null));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new configurer that will configure the connection factory using the given
|
||||
* {@code properties} and {@code connectionDetails}, with the latter taking priority.
|
||||
* @param properties the properties to use to configure the connection factory
|
||||
* @param connectionDetails the connection details to use to configure the connection
|
||||
* factory
|
||||
* @since 3.1.0
|
||||
*/
|
||||
public CachingConnectionFactoryConfigurer(RabbitProperties properties, RabbitConnectionDetails connectionDetails) {
|
||||
super(properties, connectionDetails);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(CachingConnectionFactory connectionFactory, RabbitProperties rabbitProperties) {
|
||||
PropertyMapper map = PropertyMapper.get();
|
||||
map.from(rabbitProperties::isPublisherReturns).to(connectionFactory::setPublisherReturns);
|
||||
map.from(rabbitProperties::getPublisherConfirmType)
|
||||
.whenNonNull()
|
||||
.to(connectionFactory::setPublisherConfirmType);
|
||||
RabbitProperties.Cache.Channel channel = rabbitProperties.getCache().getChannel();
|
||||
map.from(channel::getSize).whenNonNull().to(connectionFactory::setChannelCacheSize);
|
||||
map.from(channel::getCheckoutTimeout)
|
||||
.whenNonNull()
|
||||
.as(Duration::toMillis)
|
||||
.to(connectionFactory::setChannelCheckoutTimeout);
|
||||
RabbitProperties.Cache.Connection connection = rabbitProperties.getCache().getConnection();
|
||||
map.from(connection::getMode).whenNonNull().to(connectionFactory::setCacheMode);
|
||||
map.from(connection::getSize).whenNonNull().to(connectionFactory::setConnectionCacheSize);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2021 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.amqp;
|
||||
|
||||
import com.rabbitmq.client.ConnectionFactory;
|
||||
|
||||
/**
|
||||
* Callback interface that can be implemented by beans wishing to customize the
|
||||
* auto-configured RabbitMQ {@link ConnectionFactory}.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
* @since 2.5.0
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface ConnectionFactoryCustomizer {
|
||||
|
||||
/**
|
||||
* Customize the {@link ConnectionFactory}.
|
||||
* @param factory the factory to customize
|
||||
*/
|
||||
void customize(ConnectionFactory factory);
|
||||
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
/*
|
||||
* 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.amqp;
|
||||
|
||||
import org.springframework.amqp.rabbit.config.DirectRabbitListenerContainerFactory;
|
||||
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
|
||||
import org.springframework.boot.context.properties.PropertyMapper;
|
||||
|
||||
/**
|
||||
* Configure {@link DirectRabbitListenerContainerFactory} with sensible defaults tuned
|
||||
* using configuration properties.
|
||||
* <p>
|
||||
* Can be injected into application code and used to define a custom
|
||||
* {@code DirectRabbitListenerContainerFactory} whose configuration is based upon that
|
||||
* produced by auto-configuration.
|
||||
*
|
||||
* @author Gary Russell
|
||||
* @author Stephane Nicoll
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public final class DirectRabbitListenerContainerFactoryConfigurer
|
||||
extends AbstractRabbitListenerContainerFactoryConfigurer<DirectRabbitListenerContainerFactory> {
|
||||
|
||||
/**
|
||||
* Creates a new configurer that will use the given {@code rabbitProperties}.
|
||||
* @param rabbitProperties properties to use
|
||||
* @since 2.6.0
|
||||
*/
|
||||
public DirectRabbitListenerContainerFactoryConfigurer(RabbitProperties rabbitProperties) {
|
||||
super(rabbitProperties);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(DirectRabbitListenerContainerFactory factory, ConnectionFactory connectionFactory) {
|
||||
PropertyMapper map = PropertyMapper.get();
|
||||
RabbitProperties.DirectContainer config = getRabbitProperties().getListener().getDirect();
|
||||
configure(factory, connectionFactory, config);
|
||||
map.from(config::getConsumersPerQueue).whenNonNull().to(factory::setConsumersPerQueue);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2023 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.amqp;
|
||||
|
||||
import com.rabbitmq.stream.Environment;
|
||||
import com.rabbitmq.stream.EnvironmentBuilder;
|
||||
|
||||
/**
|
||||
* Callback interface that can be implemented by beans wishing to customize the
|
||||
* auto-configured {@link Environment} that is created by an {@link EnvironmentBuilder}.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
* @since 3.0.0
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface EnvironmentBuilderCustomizer {
|
||||
|
||||
/**
|
||||
* Customize the {@code EnvironmentBuilder}.
|
||||
* @param builder the builder to customize
|
||||
*/
|
||||
void customize(EnvironmentBuilder builder);
|
||||
|
||||
}
|
||||
@@ -1,86 +0,0 @@
|
||||
/*
|
||||
* 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.amqp;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.boot.autoconfigure.amqp.RabbitProperties.Ssl;
|
||||
import org.springframework.boot.ssl.SslBundle;
|
||||
import org.springframework.boot.ssl.SslBundles;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Adapts {@link RabbitProperties} to {@link RabbitConnectionDetails}.
|
||||
*
|
||||
* @author Moritz Halbritter
|
||||
* @author Andy Wilkinson
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
class PropertiesRabbitConnectionDetails implements RabbitConnectionDetails {
|
||||
|
||||
private final RabbitProperties properties;
|
||||
|
||||
private final SslBundles sslBundles;
|
||||
|
||||
PropertiesRabbitConnectionDetails(RabbitProperties properties, SslBundles sslBundles) {
|
||||
this.properties = properties;
|
||||
this.sslBundles = sslBundles;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUsername() {
|
||||
return this.properties.determineUsername();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPassword() {
|
||||
return this.properties.determinePassword();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getVirtualHost() {
|
||||
return this.properties.determineVirtualHost();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Address> getAddresses() {
|
||||
List<Address> addresses = new ArrayList<>();
|
||||
for (String address : this.properties.determineAddresses()) {
|
||||
int portSeparatorIndex = address.lastIndexOf(':');
|
||||
String host = address.substring(0, portSeparatorIndex);
|
||||
String port = address.substring(portSeparatorIndex + 1);
|
||||
addresses.add(new Address(host, Integer.parseInt(port)));
|
||||
}
|
||||
return addresses;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SslBundle getSslBundle() {
|
||||
Ssl ssl = this.properties.getSsl();
|
||||
if (!ssl.determineEnabled()) {
|
||||
return null;
|
||||
}
|
||||
if (StringUtils.hasLength(ssl.getBundle())) {
|
||||
Assert.notNull(this.sslBundles, "SSL bundle name has been set but no SSL bundles found in context");
|
||||
return this.sslBundles.getBundle(ssl.getBundle());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,148 +0,0 @@
|
||||
/*
|
||||
* 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.amqp;
|
||||
|
||||
import org.springframework.amqp.rabbit.annotation.EnableRabbit;
|
||||
import org.springframework.amqp.rabbit.config.ContainerCustomizer;
|
||||
import org.springframework.amqp.rabbit.config.DirectRabbitListenerContainerFactory;
|
||||
import org.springframework.amqp.rabbit.config.RabbitListenerConfigUtils;
|
||||
import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory;
|
||||
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
|
||||
import org.springframework.amqp.rabbit.listener.DirectMessageListenerContainer;
|
||||
import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer;
|
||||
import org.springframework.amqp.rabbit.retry.MessageRecoverer;
|
||||
import org.springframework.amqp.support.converter.MessageConverter;
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
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.ConditionalOnThreading;
|
||||
import org.springframework.boot.autoconfigure.thread.Threading;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.task.VirtualThreadTaskExecutor;
|
||||
|
||||
/**
|
||||
* Configuration for Spring AMQP annotation driven endpoints.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @author Josh Thornhill
|
||||
* @author Moritz Halbritter
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass(EnableRabbit.class)
|
||||
class RabbitAnnotationDrivenConfiguration {
|
||||
|
||||
private final ObjectProvider<MessageConverter> messageConverter;
|
||||
|
||||
private final ObjectProvider<MessageRecoverer> messageRecoverer;
|
||||
|
||||
private final ObjectProvider<RabbitRetryTemplateCustomizer> retryTemplateCustomizers;
|
||||
|
||||
private final RabbitProperties properties;
|
||||
|
||||
RabbitAnnotationDrivenConfiguration(ObjectProvider<MessageConverter> messageConverter,
|
||||
ObjectProvider<MessageRecoverer> messageRecoverer,
|
||||
ObjectProvider<RabbitRetryTemplateCustomizer> retryTemplateCustomizers, RabbitProperties properties) {
|
||||
this.messageConverter = messageConverter;
|
||||
this.messageRecoverer = messageRecoverer;
|
||||
this.retryTemplateCustomizers = retryTemplateCustomizers;
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
@ConditionalOnThreading(Threading.PLATFORM)
|
||||
SimpleRabbitListenerContainerFactoryConfigurer simpleRabbitListenerContainerFactoryConfigurer() {
|
||||
return simpleListenerConfigurer();
|
||||
}
|
||||
|
||||
@Bean(name = "simpleRabbitListenerContainerFactoryConfigurer")
|
||||
@ConditionalOnMissingBean
|
||||
@ConditionalOnThreading(Threading.VIRTUAL)
|
||||
SimpleRabbitListenerContainerFactoryConfigurer simpleRabbitListenerContainerFactoryConfigurerVirtualThreads() {
|
||||
SimpleRabbitListenerContainerFactoryConfigurer configurer = simpleListenerConfigurer();
|
||||
configurer.setTaskExecutor(new VirtualThreadTaskExecutor("rabbit-simple-"));
|
||||
return configurer;
|
||||
}
|
||||
|
||||
@Bean(name = "rabbitListenerContainerFactory")
|
||||
@ConditionalOnMissingBean(name = "rabbitListenerContainerFactory")
|
||||
@ConditionalOnProperty(name = "spring.rabbitmq.listener.type", havingValue = "simple", matchIfMissing = true)
|
||||
SimpleRabbitListenerContainerFactory simpleRabbitListenerContainerFactory(
|
||||
SimpleRabbitListenerContainerFactoryConfigurer configurer, ConnectionFactory connectionFactory,
|
||||
ObjectProvider<ContainerCustomizer<SimpleMessageListenerContainer>> simpleContainerCustomizer) {
|
||||
SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
|
||||
configurer.configure(factory, connectionFactory);
|
||||
simpleContainerCustomizer.ifUnique(factory::setContainerCustomizer);
|
||||
return factory;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
@ConditionalOnThreading(Threading.PLATFORM)
|
||||
DirectRabbitListenerContainerFactoryConfigurer directRabbitListenerContainerFactoryConfigurer() {
|
||||
return directListenerConfigurer();
|
||||
}
|
||||
|
||||
@Bean(name = "directRabbitListenerContainerFactoryConfigurer")
|
||||
@ConditionalOnMissingBean
|
||||
@ConditionalOnThreading(Threading.VIRTUAL)
|
||||
DirectRabbitListenerContainerFactoryConfigurer directRabbitListenerContainerFactoryConfigurerVirtualThreads() {
|
||||
DirectRabbitListenerContainerFactoryConfigurer configurer = directListenerConfigurer();
|
||||
configurer.setTaskExecutor(new VirtualThreadTaskExecutor("rabbit-direct-"));
|
||||
return configurer;
|
||||
}
|
||||
|
||||
@Bean(name = "rabbitListenerContainerFactory")
|
||||
@ConditionalOnMissingBean(name = "rabbitListenerContainerFactory")
|
||||
@ConditionalOnProperty(name = "spring.rabbitmq.listener.type", havingValue = "direct")
|
||||
DirectRabbitListenerContainerFactory directRabbitListenerContainerFactory(
|
||||
DirectRabbitListenerContainerFactoryConfigurer configurer, ConnectionFactory connectionFactory,
|
||||
ObjectProvider<ContainerCustomizer<DirectMessageListenerContainer>> directContainerCustomizer) {
|
||||
DirectRabbitListenerContainerFactory factory = new DirectRabbitListenerContainerFactory();
|
||||
configurer.configure(factory, connectionFactory);
|
||||
directContainerCustomizer.ifUnique(factory::setContainerCustomizer);
|
||||
return factory;
|
||||
}
|
||||
|
||||
private SimpleRabbitListenerContainerFactoryConfigurer simpleListenerConfigurer() {
|
||||
SimpleRabbitListenerContainerFactoryConfigurer configurer = new SimpleRabbitListenerContainerFactoryConfigurer(
|
||||
this.properties);
|
||||
configurer.setMessageConverter(this.messageConverter.getIfUnique());
|
||||
configurer.setMessageRecoverer(this.messageRecoverer.getIfUnique());
|
||||
configurer.setRetryTemplateCustomizers(this.retryTemplateCustomizers.orderedStream().toList());
|
||||
return configurer;
|
||||
}
|
||||
|
||||
private DirectRabbitListenerContainerFactoryConfigurer directListenerConfigurer() {
|
||||
DirectRabbitListenerContainerFactoryConfigurer configurer = new DirectRabbitListenerContainerFactoryConfigurer(
|
||||
this.properties);
|
||||
configurer.setMessageConverter(this.messageConverter.getIfUnique());
|
||||
configurer.setMessageRecoverer(this.messageRecoverer.getIfUnique());
|
||||
configurer.setRetryTemplateCustomizers(this.retryTemplateCustomizers.orderedStream().toList());
|
||||
return configurer;
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableRabbit
|
||||
@ConditionalOnMissingBean(name = RabbitListenerConfigUtils.RABBIT_LISTENER_ANNOTATION_PROCESSOR_BEAN_NAME)
|
||||
static class EnableRabbitConfiguration {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,188 +0,0 @@
|
||||
/*
|
||||
* 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.amqp;
|
||||
|
||||
import com.rabbitmq.client.Channel;
|
||||
import com.rabbitmq.client.impl.CredentialsProvider;
|
||||
import com.rabbitmq.client.impl.CredentialsRefreshService;
|
||||
|
||||
import org.springframework.amqp.core.AmqpAdmin;
|
||||
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
|
||||
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
|
||||
import org.springframework.amqp.rabbit.connection.ConnectionNameStrategy;
|
||||
import org.springframework.amqp.rabbit.connection.RabbitConnectionFactoryBean;
|
||||
import org.springframework.amqp.rabbit.core.RabbitAdmin;
|
||||
import org.springframework.amqp.rabbit.core.RabbitMessagingTemplate;
|
||||
import org.springframework.amqp.rabbit.core.RabbitOperations;
|
||||
import org.springframework.amqp.rabbit.core.RabbitTemplate;
|
||||
import org.springframework.amqp.support.converter.MessageConverter;
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.boot.ssl.SslBundles;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
|
||||
/**
|
||||
* {@link EnableAutoConfiguration Auto-configuration} for {@link RabbitTemplate}.
|
||||
* <p>
|
||||
* This configuration class is active only when the RabbitMQ and Spring AMQP client
|
||||
* libraries are on the classpath.
|
||||
* <p>
|
||||
* Registers the following beans:
|
||||
* <ul>
|
||||
* <li>{@link org.springframework.amqp.rabbit.core.RabbitTemplate RabbitTemplate} if there
|
||||
* is no other bean of the same type in the context.</li>
|
||||
* <li>{@link org.springframework.amqp.rabbit.connection.CachingConnectionFactory
|
||||
* CachingConnectionFactory} instance if there is no other bean of the same type in the
|
||||
* context.</li>
|
||||
* <li>{@link org.springframework.amqp.core.AmqpAdmin } instance as long as
|
||||
* {@literal spring.rabbitmq.dynamic=true}.</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author Greg Turnquist
|
||||
* @author Josh Long
|
||||
* @author Stephane Nicoll
|
||||
* @author Gary Russell
|
||||
* @author Phillip Webb
|
||||
* @author Artsiom Yudovin
|
||||
* @author Chris Bono
|
||||
* @author Moritz Halbritter
|
||||
* @author Andy Wilkinson
|
||||
* @author Scott Frederick
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@AutoConfiguration
|
||||
@ConditionalOnClass({ RabbitTemplate.class, Channel.class })
|
||||
@EnableConfigurationProperties(RabbitProperties.class)
|
||||
@Import({ RabbitAnnotationDrivenConfiguration.class, RabbitStreamConfiguration.class })
|
||||
public class RabbitAutoConfiguration {
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
protected static class RabbitConnectionFactoryCreator {
|
||||
|
||||
private final RabbitProperties properties;
|
||||
|
||||
protected RabbitConnectionFactoryCreator(RabbitProperties properties) {
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
RabbitConnectionDetails rabbitConnectionDetails(ObjectProvider<SslBundles> sslBundles) {
|
||||
return new PropertiesRabbitConnectionDetails(this.properties, sslBundles.getIfAvailable());
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
RabbitConnectionFactoryBeanConfigurer rabbitConnectionFactoryBeanConfigurer(ResourceLoader resourceLoader,
|
||||
RabbitConnectionDetails connectionDetails, ObjectProvider<CredentialsProvider> credentialsProvider,
|
||||
ObjectProvider<CredentialsRefreshService> credentialsRefreshService) {
|
||||
RabbitConnectionFactoryBeanConfigurer configurer = new RabbitConnectionFactoryBeanConfigurer(resourceLoader,
|
||||
this.properties, connectionDetails);
|
||||
configurer.setCredentialsProvider(credentialsProvider.getIfUnique());
|
||||
configurer.setCredentialsRefreshService(credentialsRefreshService.getIfUnique());
|
||||
return configurer;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
CachingConnectionFactoryConfigurer rabbitConnectionFactoryConfigurer(RabbitConnectionDetails connectionDetails,
|
||||
ObjectProvider<ConnectionNameStrategy> connectionNameStrategy) {
|
||||
CachingConnectionFactoryConfigurer configurer = new CachingConnectionFactoryConfigurer(this.properties,
|
||||
connectionDetails);
|
||||
configurer.setConnectionNameStrategy(connectionNameStrategy.getIfUnique());
|
||||
return configurer;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(ConnectionFactory.class)
|
||||
CachingConnectionFactory rabbitConnectionFactory(
|
||||
RabbitConnectionFactoryBeanConfigurer rabbitConnectionFactoryBeanConfigurer,
|
||||
CachingConnectionFactoryConfigurer rabbitCachingConnectionFactoryConfigurer,
|
||||
ObjectProvider<ConnectionFactoryCustomizer> connectionFactoryCustomizers) throws Exception {
|
||||
RabbitConnectionFactoryBean connectionFactoryBean = new SslBundleRabbitConnectionFactoryBean();
|
||||
rabbitConnectionFactoryBeanConfigurer.configure(connectionFactoryBean);
|
||||
connectionFactoryBean.afterPropertiesSet();
|
||||
com.rabbitmq.client.ConnectionFactory connectionFactory = connectionFactoryBean.getObject();
|
||||
connectionFactoryCustomizers.orderedStream()
|
||||
.forEach((customizer) -> customizer.customize(connectionFactory));
|
||||
CachingConnectionFactory factory = new CachingConnectionFactory(connectionFactory);
|
||||
rabbitCachingConnectionFactoryConfigurer.configure(factory);
|
||||
return factory;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@Import(RabbitConnectionFactoryCreator.class)
|
||||
protected static class RabbitTemplateConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public RabbitTemplateConfigurer rabbitTemplateConfigurer(RabbitProperties properties,
|
||||
ObjectProvider<MessageConverter> messageConverter,
|
||||
ObjectProvider<RabbitRetryTemplateCustomizer> retryTemplateCustomizers) {
|
||||
RabbitTemplateConfigurer configurer = new RabbitTemplateConfigurer(properties);
|
||||
configurer.setMessageConverter(messageConverter.getIfUnique());
|
||||
configurer.setRetryTemplateCustomizers(retryTemplateCustomizers.orderedStream().toList());
|
||||
return configurer;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnSingleCandidate(ConnectionFactory.class)
|
||||
@ConditionalOnMissingBean(RabbitOperations.class)
|
||||
public RabbitTemplate rabbitTemplate(RabbitTemplateConfigurer configurer, ConnectionFactory connectionFactory,
|
||||
ObjectProvider<RabbitTemplateCustomizer> customizers) {
|
||||
RabbitTemplate template = new RabbitTemplate();
|
||||
configurer.configure(template, connectionFactory);
|
||||
customizers.orderedStream().forEach((customizer) -> customizer.customize(template));
|
||||
return template;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnSingleCandidate(ConnectionFactory.class)
|
||||
@ConditionalOnBooleanProperty(name = "spring.rabbitmq.dynamic", matchIfMissing = true)
|
||||
@ConditionalOnMissingBean
|
||||
public AmqpAdmin amqpAdmin(ConnectionFactory connectionFactory) {
|
||||
return new RabbitAdmin(connectionFactory);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass(RabbitMessagingTemplate.class)
|
||||
@ConditionalOnMissingBean(RabbitMessagingTemplate.class)
|
||||
@Import(RabbitTemplateConfiguration.class)
|
||||
protected static class RabbitMessagingTemplateConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnSingleCandidate(RabbitTemplate.class)
|
||||
public RabbitMessagingTemplate rabbitMessagingTemplate(RabbitTemplate rabbitTemplate) {
|
||||
return new RabbitMessagingTemplate(rabbitTemplate);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,95 +0,0 @@
|
||||
/*
|
||||
* 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.amqp;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.boot.autoconfigure.service.connection.ConnectionDetails;
|
||||
import org.springframework.boot.ssl.SslBundle;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Details required to establish a connection to a RabbitMQ service.
|
||||
*
|
||||
* @author Moritz Halbritter
|
||||
* @author Andy Wilkinson
|
||||
* @author Phillip Webb
|
||||
* @since 3.1.0
|
||||
*/
|
||||
public interface RabbitConnectionDetails extends ConnectionDetails {
|
||||
|
||||
/**
|
||||
* Login user to authenticate to the broker.
|
||||
* @return the login user to authenticate to the broker or {@code null}
|
||||
*/
|
||||
default String getUsername() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Login to authenticate against the broker.
|
||||
* @return the login to authenticate against the broker or {@code null}
|
||||
*/
|
||||
default String getPassword() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Virtual host to use when connecting to the broker.
|
||||
* @return the virtual host to use when connecting to the broker or {@code null}
|
||||
*/
|
||||
default String getVirtualHost() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* List of addresses to which the client should connect. Must return at least one
|
||||
* address.
|
||||
* @return the list of addresses to which the client should connect
|
||||
*/
|
||||
List<Address> getAddresses();
|
||||
|
||||
/**
|
||||
* Returns the first address.
|
||||
* @return the first address
|
||||
* @throws IllegalStateException if the address list is empty
|
||||
*/
|
||||
default Address getFirstAddress() {
|
||||
List<Address> addresses = getAddresses();
|
||||
Assert.state(!addresses.isEmpty(), "Address list is empty");
|
||||
return addresses.get(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* SSL bundle to use.
|
||||
* @return the SSL bundle to use
|
||||
* @since 3.5.0
|
||||
*/
|
||||
default SslBundle getSslBundle() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* A RabbitMQ address.
|
||||
*
|
||||
* @param host the host
|
||||
* @param port the port
|
||||
*/
|
||||
record Address(String host, int port) {
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,179 +0,0 @@
|
||||
/*
|
||||
* 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.amqp;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
import com.rabbitmq.client.impl.CredentialsProvider;
|
||||
import com.rabbitmq.client.impl.CredentialsRefreshService;
|
||||
|
||||
import org.springframework.amqp.rabbit.connection.RabbitConnectionFactoryBean;
|
||||
import org.springframework.boot.autoconfigure.amqp.RabbitConnectionDetails.Address;
|
||||
import org.springframework.boot.context.properties.PropertyMapper;
|
||||
import org.springframework.boot.ssl.SslBundle;
|
||||
import org.springframework.boot.ssl.SslBundles;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.unit.DataSize;
|
||||
|
||||
/**
|
||||
* Configures {@link RabbitConnectionFactoryBean} with sensible defaults tuned using
|
||||
* configuration properties.
|
||||
* <p>
|
||||
* Can be injected into application code and used to define a custom
|
||||
* {@code RabbitConnectionFactoryBean} whose configuration is based upon that produced by
|
||||
* auto-configuration.
|
||||
*
|
||||
* @author Chris Bono
|
||||
* @author Moritz Halbritter
|
||||
* @author Andy Wilkinson
|
||||
* @author Phillip Webb
|
||||
* @author Scott Frederick
|
||||
* @since 2.6.0
|
||||
*/
|
||||
public class RabbitConnectionFactoryBeanConfigurer {
|
||||
|
||||
private final RabbitProperties rabbitProperties;
|
||||
|
||||
private final ResourceLoader resourceLoader;
|
||||
|
||||
private final RabbitConnectionDetails connectionDetails;
|
||||
|
||||
private CredentialsProvider credentialsProvider;
|
||||
|
||||
private CredentialsRefreshService credentialsRefreshService;
|
||||
|
||||
/**
|
||||
* Creates a new configurer that will use the given {@code resourceLoader} and
|
||||
* {@code properties}.
|
||||
* @param resourceLoader the resource loader
|
||||
* @param properties the properties
|
||||
*/
|
||||
public RabbitConnectionFactoryBeanConfigurer(ResourceLoader resourceLoader, RabbitProperties properties) {
|
||||
this(resourceLoader, properties, new PropertiesRabbitConnectionDetails(properties, null));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new configurer that will use the given {@code resourceLoader},
|
||||
* {@code properties}, and {@code connectionDetails}. The connection details have
|
||||
* priority over the properties.
|
||||
* @param resourceLoader the resource loader
|
||||
* @param properties the properties
|
||||
* @param connectionDetails the connection details
|
||||
* @since 3.1.0
|
||||
*/
|
||||
public RabbitConnectionFactoryBeanConfigurer(ResourceLoader resourceLoader, RabbitProperties properties,
|
||||
RabbitConnectionDetails connectionDetails) {
|
||||
this(resourceLoader, properties, connectionDetails, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new configurer that will use the given {@code resourceLoader},
|
||||
* {@code properties}, {@code connectionDetails}, and {@code sslBundles}. The
|
||||
* connection details have priority over the properties.
|
||||
* @param resourceLoader the resource loader
|
||||
* @param properties the properties
|
||||
* @param connectionDetails the connection details
|
||||
* @param sslBundles the SSL bundles
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public RabbitConnectionFactoryBeanConfigurer(ResourceLoader resourceLoader, RabbitProperties properties,
|
||||
RabbitConnectionDetails connectionDetails, SslBundles sslBundles) {
|
||||
Assert.notNull(resourceLoader, "'resourceLoader' must not be null");
|
||||
Assert.notNull(properties, "'properties' must not be null");
|
||||
Assert.notNull(connectionDetails, "'connectionDetails' must not be null");
|
||||
this.resourceLoader = resourceLoader;
|
||||
this.rabbitProperties = properties;
|
||||
this.connectionDetails = connectionDetails;
|
||||
}
|
||||
|
||||
public void setCredentialsProvider(CredentialsProvider credentialsProvider) {
|
||||
this.credentialsProvider = credentialsProvider;
|
||||
}
|
||||
|
||||
public void setCredentialsRefreshService(CredentialsRefreshService credentialsRefreshService) {
|
||||
this.credentialsRefreshService = credentialsRefreshService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the specified rabbit connection factory bean. The factory bean can be
|
||||
* further tuned and default settings can be overridden. It is the responsibility of
|
||||
* the caller to invoke {@link RabbitConnectionFactoryBean#afterPropertiesSet()}
|
||||
* though.
|
||||
* @param factory the {@link RabbitConnectionFactoryBean} instance to configure
|
||||
*/
|
||||
public void configure(RabbitConnectionFactoryBean factory) {
|
||||
Assert.notNull(factory, "'factory' must not be null");
|
||||
factory.setResourceLoader(this.resourceLoader);
|
||||
Address address = this.connectionDetails.getFirstAddress();
|
||||
PropertyMapper map = PropertyMapper.get();
|
||||
map.from(address::host).whenNonNull().to(factory::setHost);
|
||||
map.from(address::port).to(factory::setPort);
|
||||
map.from(this.connectionDetails::getUsername).whenNonNull().to(factory::setUsername);
|
||||
map.from(this.connectionDetails::getPassword).whenNonNull().to(factory::setPassword);
|
||||
map.from(this.connectionDetails::getVirtualHost).whenNonNull().to(factory::setVirtualHost);
|
||||
map.from(this.rabbitProperties::getRequestedHeartbeat)
|
||||
.whenNonNull()
|
||||
.asInt(Duration::getSeconds)
|
||||
.to(factory::setRequestedHeartbeat);
|
||||
map.from(this.rabbitProperties::getRequestedChannelMax).to(factory::setRequestedChannelMax);
|
||||
SslBundle sslBundle = this.connectionDetails.getSslBundle();
|
||||
if (sslBundle != null) {
|
||||
applySslBundle(factory, sslBundle);
|
||||
}
|
||||
else {
|
||||
RabbitProperties.Ssl ssl = this.rabbitProperties.getSsl();
|
||||
if (ssl.determineEnabled()) {
|
||||
factory.setUseSSL(true);
|
||||
map.from(ssl::getAlgorithm).whenNonNull().to(factory::setSslAlgorithm);
|
||||
map.from(ssl::getKeyStoreType).to(factory::setKeyStoreType);
|
||||
map.from(ssl::getKeyStore).to(factory::setKeyStore);
|
||||
map.from(ssl::getKeyStorePassword).to(factory::setKeyStorePassphrase);
|
||||
map.from(ssl::getKeyStoreAlgorithm).whenNonNull().to(factory::setKeyStoreAlgorithm);
|
||||
map.from(ssl::getTrustStoreType).to(factory::setTrustStoreType);
|
||||
map.from(ssl::getTrustStore).to(factory::setTrustStore);
|
||||
map.from(ssl::getTrustStorePassword).to(factory::setTrustStorePassphrase);
|
||||
map.from(ssl::getTrustStoreAlgorithm).whenNonNull().to(factory::setTrustStoreAlgorithm);
|
||||
map.from(ssl::isValidateServerCertificate)
|
||||
.to((validate) -> factory.setSkipServerCertificateValidation(!validate));
|
||||
map.from(ssl::isVerifyHostname).to(factory::setEnableHostnameVerification);
|
||||
}
|
||||
}
|
||||
map.from(this.rabbitProperties::getConnectionTimeout)
|
||||
.whenNonNull()
|
||||
.asInt(Duration::toMillis)
|
||||
.to(factory::setConnectionTimeout);
|
||||
map.from(this.rabbitProperties::getChannelRpcTimeout)
|
||||
.whenNonNull()
|
||||
.asInt(Duration::toMillis)
|
||||
.to(factory::setChannelRpcTimeout);
|
||||
map.from(this.credentialsProvider).whenNonNull().to(factory::setCredentialsProvider);
|
||||
map.from(this.credentialsRefreshService).whenNonNull().to(factory::setCredentialsRefreshService);
|
||||
map.from(this.rabbitProperties.getMaxInboundMessageBodySize())
|
||||
.whenNonNull()
|
||||
.asInt(DataSize::toBytes)
|
||||
.to(factory::setMaxInboundMessageBodySize);
|
||||
}
|
||||
|
||||
private static void applySslBundle(RabbitConnectionFactoryBean factory, SslBundle bundle) {
|
||||
factory.setUseSSL(true);
|
||||
if (factory instanceof SslBundleRabbitConnectionFactoryBean sslFactory) {
|
||||
sslFactory.setSslBundle(bundle);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,58 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2019 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.amqp;
|
||||
|
||||
import org.springframework.amqp.rabbit.core.RabbitTemplate;
|
||||
import org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer;
|
||||
import org.springframework.retry.support.RetryTemplate;
|
||||
|
||||
/**
|
||||
* Callback interface that can be used to customize a {@link RetryTemplate} used as part
|
||||
* of the Rabbit infrastructure.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @since 2.1.0
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface RabbitRetryTemplateCustomizer {
|
||||
|
||||
/**
|
||||
* Callback to customize a {@link RetryTemplate} instance used in the context of the
|
||||
* specified {@link Target}.
|
||||
* @param target the {@link Target} of the retry template
|
||||
* @param retryTemplate the template to customize
|
||||
*/
|
||||
void customize(Target target, RetryTemplate retryTemplate);
|
||||
|
||||
/**
|
||||
* Define the available target for a {@link RetryTemplate}.
|
||||
*/
|
||||
enum Target {
|
||||
|
||||
/**
|
||||
* {@link RabbitTemplate} target.
|
||||
*/
|
||||
SENDER,
|
||||
|
||||
/**
|
||||
* {@link AbstractMessageListenerContainer} target.
|
||||
*/
|
||||
LISTENER
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,132 +0,0 @@
|
||||
/*
|
||||
* 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.amqp;
|
||||
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import com.rabbitmq.stream.Environment;
|
||||
import com.rabbitmq.stream.EnvironmentBuilder;
|
||||
|
||||
import org.springframework.amqp.rabbit.config.ContainerCustomizer;
|
||||
import org.springframework.amqp.support.converter.MessageConverter;
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.autoconfigure.amqp.RabbitProperties.StreamContainer;
|
||||
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.PropertyMapper;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.rabbit.stream.config.StreamRabbitListenerContainerFactory;
|
||||
import org.springframework.rabbit.stream.listener.ConsumerCustomizer;
|
||||
import org.springframework.rabbit.stream.listener.StreamListenerContainer;
|
||||
import org.springframework.rabbit.stream.producer.ProducerCustomizer;
|
||||
import org.springframework.rabbit.stream.producer.RabbitStreamOperations;
|
||||
import org.springframework.rabbit.stream.producer.RabbitStreamTemplate;
|
||||
import org.springframework.rabbit.stream.support.converter.StreamMessageConverter;
|
||||
|
||||
/**
|
||||
* Configuration for Spring RabbitMQ Stream plugin support.
|
||||
*
|
||||
* @author Gary Russell
|
||||
* @author Eddú Meléndez
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass(StreamRabbitListenerContainerFactory.class)
|
||||
class RabbitStreamConfiguration {
|
||||
|
||||
@Bean(name = "rabbitListenerContainerFactory")
|
||||
@ConditionalOnMissingBean(name = "rabbitListenerContainerFactory")
|
||||
@ConditionalOnProperty(name = "spring.rabbitmq.listener.type", havingValue = "stream")
|
||||
StreamRabbitListenerContainerFactory streamRabbitListenerContainerFactory(Environment rabbitStreamEnvironment,
|
||||
RabbitProperties properties, ObjectProvider<ConsumerCustomizer> consumerCustomizer,
|
||||
ObjectProvider<ContainerCustomizer<StreamListenerContainer>> containerCustomizer) {
|
||||
StreamRabbitListenerContainerFactory factory = new StreamRabbitListenerContainerFactory(
|
||||
rabbitStreamEnvironment);
|
||||
StreamContainer stream = properties.getListener().getStream();
|
||||
factory.setObservationEnabled(stream.isObservationEnabled());
|
||||
factory.setNativeListener(stream.isNativeListener());
|
||||
consumerCustomizer.ifUnique(factory::setConsumerCustomizer);
|
||||
containerCustomizer.ifUnique(factory::setContainerCustomizer);
|
||||
return factory;
|
||||
}
|
||||
|
||||
@Bean(name = "rabbitStreamEnvironment")
|
||||
@ConditionalOnMissingBean(name = "rabbitStreamEnvironment")
|
||||
Environment rabbitStreamEnvironment(RabbitProperties properties, RabbitConnectionDetails connectionDetails,
|
||||
ObjectProvider<EnvironmentBuilderCustomizer> customizers) {
|
||||
EnvironmentBuilder builder = configure(Environment.builder(), properties, connectionDetails);
|
||||
customizers.orderedStream().forEach((customizer) -> customizer.customize(builder));
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
RabbitStreamTemplateConfigurer rabbitStreamTemplateConfigurer(RabbitProperties properties,
|
||||
ObjectProvider<MessageConverter> messageConverter,
|
||||
ObjectProvider<StreamMessageConverter> streamMessageConverter,
|
||||
ObjectProvider<ProducerCustomizer> producerCustomizer) {
|
||||
RabbitStreamTemplateConfigurer configurer = new RabbitStreamTemplateConfigurer();
|
||||
configurer.setMessageConverter(messageConverter.getIfUnique());
|
||||
configurer.setStreamMessageConverter(streamMessageConverter.getIfUnique());
|
||||
configurer.setProducerCustomizer(producerCustomizer.getIfUnique());
|
||||
return configurer;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(RabbitStreamOperations.class)
|
||||
@ConditionalOnProperty(name = "spring.rabbitmq.stream.name")
|
||||
RabbitStreamTemplate rabbitStreamTemplate(Environment rabbitStreamEnvironment, RabbitProperties properties,
|
||||
RabbitStreamTemplateConfigurer configurer) {
|
||||
RabbitStreamTemplate template = new RabbitStreamTemplate(rabbitStreamEnvironment,
|
||||
properties.getStream().getName());
|
||||
configurer.configure(template);
|
||||
return template;
|
||||
}
|
||||
|
||||
static EnvironmentBuilder configure(EnvironmentBuilder builder, RabbitProperties properties,
|
||||
RabbitConnectionDetails connectionDetails) {
|
||||
return configure(builder, properties.getStream(), connectionDetails);
|
||||
}
|
||||
|
||||
private static EnvironmentBuilder configure(EnvironmentBuilder builder, RabbitProperties.Stream stream,
|
||||
RabbitConnectionDetails connectionDetails) {
|
||||
builder.lazyInitialization(true);
|
||||
PropertyMapper map = PropertyMapper.get();
|
||||
map.from(stream.getHost()).to(builder::host);
|
||||
map.from(stream.getPort()).to(builder::port);
|
||||
map.from(stream.getVirtualHost())
|
||||
.as(withFallback(connectionDetails::getVirtualHost))
|
||||
.whenNonNull()
|
||||
.to(builder::virtualHost);
|
||||
map.from(stream.getUsername())
|
||||
.as(withFallback(connectionDetails::getUsername))
|
||||
.whenNonNull()
|
||||
.to(builder::username);
|
||||
map.from(stream.getPassword())
|
||||
.as(withFallback(connectionDetails::getPassword))
|
||||
.whenNonNull()
|
||||
.to(builder::password);
|
||||
return builder;
|
||||
}
|
||||
|
||||
private static Function<String, String> withFallback(Supplier<String> fallback) {
|
||||
return (value) -> (value != null) ? value : fallback.get();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,85 +0,0 @@
|
||||
/*
|
||||
* 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.amqp;
|
||||
|
||||
import org.springframework.amqp.support.converter.MessageConverter;
|
||||
import org.springframework.rabbit.stream.producer.ProducerCustomizer;
|
||||
import org.springframework.rabbit.stream.producer.RabbitStreamTemplate;
|
||||
import org.springframework.rabbit.stream.support.converter.StreamMessageConverter;
|
||||
|
||||
/**
|
||||
* Configure {@link RabbitStreamTemplate} with sensible defaults.
|
||||
* <p>
|
||||
* Can be injected into application code and used to define a custom
|
||||
* {@code RabbitStreamTemplate} whose configuration is based upon that produced by
|
||||
* auto-configuration.
|
||||
*
|
||||
* @author Eddú Meléndez
|
||||
* @since 2.7.0
|
||||
*/
|
||||
public class RabbitStreamTemplateConfigurer {
|
||||
|
||||
private MessageConverter messageConverter;
|
||||
|
||||
private StreamMessageConverter streamMessageConverter;
|
||||
|
||||
private ProducerCustomizer producerCustomizer;
|
||||
|
||||
/**
|
||||
* Set the {@link MessageConverter} to use or {@code null} if the out-of-the-box
|
||||
* converter should be used.
|
||||
* @param messageConverter the {@link MessageConverter}
|
||||
*/
|
||||
public void setMessageConverter(MessageConverter messageConverter) {
|
||||
this.messageConverter = messageConverter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@link StreamMessageConverter} to use or {@code null} if the out-of-the-box
|
||||
* stream message converter should be used.
|
||||
* @param streamMessageConverter the {@link StreamMessageConverter}
|
||||
*/
|
||||
public void setStreamMessageConverter(StreamMessageConverter streamMessageConverter) {
|
||||
this.streamMessageConverter = streamMessageConverter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@link ProducerCustomizer} instances to use.
|
||||
* @param producerCustomizer the producer customizer
|
||||
*/
|
||||
public void setProducerCustomizer(ProducerCustomizer producerCustomizer) {
|
||||
this.producerCustomizer = producerCustomizer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the specified {@link RabbitStreamTemplate}. The template can be further
|
||||
* tuned and default settings can be overridden.
|
||||
* @param template the {@link RabbitStreamTemplate} instance to configure
|
||||
*/
|
||||
public void configure(RabbitStreamTemplate template) {
|
||||
if (this.messageConverter != null) {
|
||||
template.setMessageConverter(this.messageConverter);
|
||||
}
|
||||
if (this.streamMessageConverter != null) {
|
||||
template.setStreamConverter(this.streamMessageConverter);
|
||||
}
|
||||
if (this.producerCustomizer != null) {
|
||||
template.setProducerCustomizer(this.producerCustomizer);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,134 +0,0 @@
|
||||
/*
|
||||
* 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.amqp;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
|
||||
import org.springframework.amqp.rabbit.core.RabbitTemplate;
|
||||
import org.springframework.amqp.support.converter.AllowedListDeserializingMessageConverter;
|
||||
import org.springframework.amqp.support.converter.MessageConverter;
|
||||
import org.springframework.boot.context.properties.PropertyMapper;
|
||||
import org.springframework.boot.context.properties.source.InvalidConfigurationPropertyValueException;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
/**
|
||||
* Configure {@link RabbitTemplate} with sensible defaults tuned using configuration
|
||||
* properties.
|
||||
* <p>
|
||||
* Can be injected into application code and used to define a custom
|
||||
* {@code RabbitTemplateConfigurer} whose configuration is based upon that produced by
|
||||
* auto-configuration.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @author Yanming Zhou
|
||||
* @since 2.3.0
|
||||
*/
|
||||
public class RabbitTemplateConfigurer {
|
||||
|
||||
private MessageConverter messageConverter;
|
||||
|
||||
private List<RabbitRetryTemplateCustomizer> retryTemplateCustomizers;
|
||||
|
||||
private final RabbitProperties rabbitProperties;
|
||||
|
||||
/**
|
||||
* Creates a new configurer that will use the given {@code rabbitProperties}.
|
||||
* @param rabbitProperties properties to use
|
||||
* @since 2.6.0
|
||||
*/
|
||||
public RabbitTemplateConfigurer(RabbitProperties rabbitProperties) {
|
||||
Assert.notNull(rabbitProperties, "'rabbitProperties' must not be null");
|
||||
this.rabbitProperties = rabbitProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@link MessageConverter} to use or {@code null} if the out-of-the-box
|
||||
* converter should be used.
|
||||
* @param messageConverter the {@link MessageConverter}
|
||||
* @since 2.6.0
|
||||
*/
|
||||
public void setMessageConverter(MessageConverter messageConverter) {
|
||||
this.messageConverter = messageConverter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@link RabbitRetryTemplateCustomizer} instances to use.
|
||||
* @param retryTemplateCustomizers the retry template customizers
|
||||
* @since 2.6.0
|
||||
*/
|
||||
public void setRetryTemplateCustomizers(List<RabbitRetryTemplateCustomizer> retryTemplateCustomizers) {
|
||||
this.retryTemplateCustomizers = retryTemplateCustomizers;
|
||||
}
|
||||
|
||||
protected final RabbitProperties getRabbitProperties() {
|
||||
return this.rabbitProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the specified {@link RabbitTemplate}. The template can be further tuned
|
||||
* and default settings can be overridden.
|
||||
* @param template the {@link RabbitTemplate} instance to configure
|
||||
* @param connectionFactory the {@link ConnectionFactory} to use
|
||||
*/
|
||||
public void configure(RabbitTemplate template, ConnectionFactory connectionFactory) {
|
||||
PropertyMapper map = PropertyMapper.get();
|
||||
template.setConnectionFactory(connectionFactory);
|
||||
if (this.messageConverter != null) {
|
||||
template.setMessageConverter(this.messageConverter);
|
||||
}
|
||||
template.setMandatory(determineMandatoryFlag());
|
||||
RabbitProperties.Template templateProperties = this.rabbitProperties.getTemplate();
|
||||
if (templateProperties.getRetry().isEnabled()) {
|
||||
template.setRetryTemplate(new RetryTemplateFactory(this.retryTemplateCustomizers)
|
||||
.createRetryTemplate(templateProperties.getRetry(), RabbitRetryTemplateCustomizer.Target.SENDER));
|
||||
}
|
||||
map.from(templateProperties::getReceiveTimeout)
|
||||
.whenNonNull()
|
||||
.as(Duration::toMillis)
|
||||
.to(template::setReceiveTimeout);
|
||||
map.from(templateProperties::getReplyTimeout)
|
||||
.whenNonNull()
|
||||
.as(Duration::toMillis)
|
||||
.to(template::setReplyTimeout);
|
||||
map.from(templateProperties::getExchange).to(template::setExchange);
|
||||
map.from(templateProperties::getRoutingKey).to(template::setRoutingKey);
|
||||
map.from(templateProperties::getDefaultReceiveQueue).whenNonNull().to(template::setDefaultReceiveQueue);
|
||||
map.from(templateProperties::isObservationEnabled).to(template::setObservationEnabled);
|
||||
map.from(templateProperties::getAllowedListPatterns)
|
||||
.whenNot(CollectionUtils::isEmpty)
|
||||
.to((allowedListPatterns) -> setAllowedListPatterns(template.getMessageConverter(), allowedListPatterns));
|
||||
}
|
||||
|
||||
private void setAllowedListPatterns(MessageConverter messageConverter, List<String> allowedListPatterns) {
|
||||
if (messageConverter instanceof AllowedListDeserializingMessageConverter allowedListDeserializingMessageConverter) {
|
||||
allowedListDeserializingMessageConverter.setAllowedListPatterns(allowedListPatterns);
|
||||
return;
|
||||
}
|
||||
throw new InvalidConfigurationPropertyValueException("spring.rabbitmq.template.allowed-list-patterns",
|
||||
allowedListPatterns,
|
||||
"Allowed list patterns can only be applied to an AllowedListDeserializingMessageConverter");
|
||||
}
|
||||
|
||||
private boolean determineMandatoryFlag() {
|
||||
Boolean mandatory = this.rabbitProperties.getTemplate().getMandatory();
|
||||
return (mandatory != null) ? mandatory : this.rabbitProperties.isPublisherReturns();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2023 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.amqp;
|
||||
|
||||
import org.springframework.amqp.rabbit.core.RabbitTemplate;
|
||||
|
||||
/**
|
||||
* Callback interface that can be used to customize a {@link RabbitTemplate}.
|
||||
*
|
||||
* @author dang zhicairang
|
||||
* @since 3.1.0
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface RabbitTemplateCustomizer {
|
||||
|
||||
/**
|
||||
* Callback to customize a {@link RabbitTemplate} instance.
|
||||
* @param rabbitTemplate the rabbitTemplate to customize
|
||||
*/
|
||||
void customize(RabbitTemplate rabbitTemplate);
|
||||
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2023 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.amqp;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.boot.context.properties.PropertyMapper;
|
||||
import org.springframework.retry.backoff.ExponentialBackOffPolicy;
|
||||
import org.springframework.retry.policy.SimpleRetryPolicy;
|
||||
import org.springframework.retry.support.RetryTemplate;
|
||||
|
||||
/**
|
||||
* Factory to create {@link RetryTemplate} instance from properties defined in
|
||||
* {@link RabbitProperties}.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
class RetryTemplateFactory {
|
||||
|
||||
private final List<RabbitRetryTemplateCustomizer> customizers;
|
||||
|
||||
RetryTemplateFactory(List<RabbitRetryTemplateCustomizer> customizers) {
|
||||
this.customizers = customizers;
|
||||
}
|
||||
|
||||
RetryTemplate createRetryTemplate(RabbitProperties.Retry properties, RabbitRetryTemplateCustomizer.Target target) {
|
||||
PropertyMapper map = PropertyMapper.get();
|
||||
RetryTemplate template = new RetryTemplate();
|
||||
SimpleRetryPolicy policy = new SimpleRetryPolicy();
|
||||
map.from(properties::getMaxAttempts).to(policy::setMaxAttempts);
|
||||
template.setRetryPolicy(policy);
|
||||
ExponentialBackOffPolicy backOffPolicy = new ExponentialBackOffPolicy();
|
||||
map.from(properties::getInitialInterval)
|
||||
.whenNonNull()
|
||||
.as(Duration::toMillis)
|
||||
.to(backOffPolicy::setInitialInterval);
|
||||
map.from(properties::getMultiplier).to(backOffPolicy::setMultiplier);
|
||||
map.from(properties::getMaxInterval).whenNonNull().as(Duration::toMillis).to(backOffPolicy::setMaxInterval);
|
||||
template.setBackOffPolicy(backOffPolicy);
|
||||
if (this.customizers != null) {
|
||||
for (RabbitRetryTemplateCustomizer customizer : this.customizers) {
|
||||
customizer.customize(target, template);
|
||||
}
|
||||
}
|
||||
return template;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
/*
|
||||
* 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.amqp;
|
||||
|
||||
import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory;
|
||||
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
|
||||
import org.springframework.boot.context.properties.PropertyMapper;
|
||||
|
||||
/**
|
||||
* Configure {@link SimpleRabbitListenerContainerFactory} with sensible defaults tuned
|
||||
* using configuration properties.
|
||||
* <p>
|
||||
* Can be injected into application code and used to define a custom
|
||||
* {@code SimpleRabbitListenerContainerFactory} whose configuration is based upon that
|
||||
* produced by auto-configuration.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @author Gary Russell
|
||||
* @since 1.3.3
|
||||
*/
|
||||
public final class SimpleRabbitListenerContainerFactoryConfigurer
|
||||
extends AbstractRabbitListenerContainerFactoryConfigurer<SimpleRabbitListenerContainerFactory> {
|
||||
|
||||
/**
|
||||
* Creates a new configurer that will use the given {@code rabbitProperties}.
|
||||
* @param rabbitProperties properties to use
|
||||
* @since 2.6.0
|
||||
*/
|
||||
public SimpleRabbitListenerContainerFactoryConfigurer(RabbitProperties rabbitProperties) {
|
||||
super(rabbitProperties);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(SimpleRabbitListenerContainerFactory factory, ConnectionFactory connectionFactory) {
|
||||
PropertyMapper map = PropertyMapper.get();
|
||||
RabbitProperties.SimpleContainer config = getRabbitProperties().getListener().getSimple();
|
||||
configure(factory, connectionFactory, config);
|
||||
map.from(config::getConcurrency).whenNonNull().to(factory::setConcurrentConsumers);
|
||||
map.from(config::getMaxConcurrency).whenNonNull().to(factory::setMaxConcurrentConsumers);
|
||||
map.from(config::getBatchSize).whenNonNull().to(factory::setBatchSize);
|
||||
map.from(config::isConsumerBatchEnabled).to(factory::setConsumerBatchEnabled);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2023 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.amqp;
|
||||
|
||||
import org.springframework.amqp.rabbit.connection.RabbitConnectionFactoryBean;
|
||||
import org.springframework.boot.ssl.SslBundle;
|
||||
|
||||
/**
|
||||
* A {@link RabbitConnectionFactoryBean} that can be configured with custom SSL trust
|
||||
* material from an {@link SslBundle}.
|
||||
*
|
||||
* @author Scott Frederick
|
||||
*/
|
||||
class SslBundleRabbitConnectionFactoryBean extends RabbitConnectionFactoryBean {
|
||||
|
||||
private SslBundle sslBundle;
|
||||
|
||||
private boolean enableHostnameVerification;
|
||||
|
||||
@Override
|
||||
protected void setUpSSL() {
|
||||
if (this.sslBundle != null) {
|
||||
this.connectionFactory.useSslProtocol(this.sslBundle.createSslContext());
|
||||
if (this.enableHostnameVerification) {
|
||||
this.connectionFactory.enableHostnameVerification();
|
||||
}
|
||||
}
|
||||
else {
|
||||
super.setUpSSL();
|
||||
}
|
||||
}
|
||||
|
||||
void setSslBundle(SslBundle sslBundle) {
|
||||
this.sslBundle = sslBundle;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEnableHostnameVerification(boolean enable) {
|
||||
this.enableHostnameVerification = enable;
|
||||
super.setEnableHostnameVerification(enable);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2019 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Auto-configuration for RabbitMQ.
|
||||
*/
|
||||
package org.springframework.boot.autoconfigure.amqp;
|
||||
@@ -1,87 +0,0 @@
|
||||
/*
|
||||
* 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.aop;
|
||||
|
||||
import org.aspectj.weaver.Advice;
|
||||
|
||||
import org.springframework.aop.config.AopConfigUtils;
|
||||
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.EnableAspectJAutoProxy;
|
||||
|
||||
/**
|
||||
* {@link org.springframework.boot.autoconfigure.EnableAutoConfiguration
|
||||
* Auto-configuration} for Spring's AOP support. Equivalent to enabling
|
||||
* {@link EnableAspectJAutoProxy @EnableAspectJAutoProxy} in your configuration.
|
||||
* <p>
|
||||
* The configuration will not be activated if {@literal spring.aop.auto=false}. The
|
||||
* {@literal proxyTargetClass} attribute will be {@literal true}, by default, but can be
|
||||
* overridden by specifying {@literal spring.aop.proxy-target-class=false}.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @author Josh Long
|
||||
* @since 1.0.0
|
||||
* @see EnableAspectJAutoProxy
|
||||
*/
|
||||
@AutoConfiguration
|
||||
@ConditionalOnBooleanProperty(name = "spring.aop.auto", matchIfMissing = true)
|
||||
public class AopAutoConfiguration {
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass(Advice.class)
|
||||
static class AspectJAutoProxyingConfiguration {
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableAspectJAutoProxy(proxyTargetClass = false)
|
||||
@ConditionalOnBooleanProperty(name = "spring.aop.proxy-target-class", havingValue = false)
|
||||
static class JdkDynamicAutoProxyConfiguration {
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableAspectJAutoProxy(proxyTargetClass = true)
|
||||
@ConditionalOnBooleanProperty(name = "spring.aop.proxy-target-class", matchIfMissing = true)
|
||||
static class CglibAutoProxyConfiguration {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnMissingClass("org.aspectj.weaver.Advice")
|
||||
@ConditionalOnBooleanProperty(name = "spring.aop.proxy-target-class", matchIfMissing = true)
|
||||
static class ClassProxyingConfiguration {
|
||||
|
||||
@Bean
|
||||
static BeanFactoryPostProcessor forceAutoProxyCreatorToUseClassProxying() {
|
||||
return (beanFactory) -> {
|
||||
if (beanFactory instanceof BeanDefinitionRegistry registry) {
|
||||
AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
|
||||
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2019 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Auto-configuration for Spring AOP.
|
||||
*/
|
||||
package org.springframework.boot.autoconfigure.aop;
|
||||
@@ -1,210 +0,0 @@
|
||||
/*
|
||||
* 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.batch;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
|
||||
import org.springframework.batch.core.configuration.support.DefaultBatchConfiguration;
|
||||
import org.springframework.batch.core.converter.JobParametersConverter;
|
||||
import org.springframework.batch.core.explore.JobExplorer;
|
||||
import org.springframework.batch.core.launch.JobLauncher;
|
||||
import org.springframework.batch.core.repository.ExecutionContextSerializer;
|
||||
import org.springframework.batch.core.repository.JobRepository;
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.ExitCodeGenerator;
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.sql.init.OnDatabaseInitializationCondition;
|
||||
import org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.boot.sql.init.dependency.DatabaseInitializationDependencyConfigurer;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.core.convert.support.ConfigurableConversionService;
|
||||
import org.springframework.core.task.TaskExecutor;
|
||||
import org.springframework.jdbc.datasource.init.DatabasePopulator;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.transaction.annotation.Isolation;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* {@link EnableAutoConfiguration Auto-configuration} for Spring Batch. If a single job is
|
||||
* found in the context, it will be executed on startup.
|
||||
* <p>
|
||||
* Disable this behavior with {@literal spring.batch.job.enabled=false}).
|
||||
* <p>
|
||||
* If multiple jobs are found, a job name to execute on startup can be supplied by the
|
||||
* User with : {@literal spring.batch.job.name=job1}. In this case the Runner will first
|
||||
* find jobs registered as Beans, then those in the existing JobRegistry.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @author Eddú Meléndez
|
||||
* @author Kazuki Shimizu
|
||||
* @author Mahmoud Ben Hassine
|
||||
* @author Lars Uffmann
|
||||
* @author Lasse Wulff
|
||||
* @author Yanming Zhou
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@AutoConfiguration(after = { HibernateJpaAutoConfiguration.class, TransactionAutoConfiguration.class })
|
||||
@ConditionalOnClass({ JobLauncher.class, DataSource.class, DatabasePopulator.class })
|
||||
@ConditionalOnBean({ DataSource.class, PlatformTransactionManager.class })
|
||||
@ConditionalOnMissingBean(value = DefaultBatchConfiguration.class, annotation = EnableBatchProcessing.class)
|
||||
@EnableConfigurationProperties(BatchProperties.class)
|
||||
@Import(DatabaseInitializationDependencyConfigurer.class)
|
||||
public class BatchAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
@ConditionalOnBooleanProperty(name = "spring.batch.job.enabled", matchIfMissing = true)
|
||||
public JobLauncherApplicationRunner jobLauncherApplicationRunner(JobLauncher jobLauncher, JobExplorer jobExplorer,
|
||||
JobRepository jobRepository, BatchProperties properties) {
|
||||
JobLauncherApplicationRunner runner = new JobLauncherApplicationRunner(jobLauncher, jobExplorer, jobRepository);
|
||||
String jobName = properties.getJob().getName();
|
||||
if (StringUtils.hasText(jobName)) {
|
||||
runner.setJobName(jobName);
|
||||
}
|
||||
return runner;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(ExitCodeGenerator.class)
|
||||
public JobExecutionExitCodeGenerator jobExecutionExitCodeGenerator() {
|
||||
return new JobExecutionExitCodeGenerator();
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class SpringBootBatchConfiguration extends DefaultBatchConfiguration {
|
||||
|
||||
private final DataSource dataSource;
|
||||
|
||||
private final PlatformTransactionManager transactionManager;
|
||||
|
||||
private final TaskExecutor taskExecutor;
|
||||
|
||||
private final BatchProperties properties;
|
||||
|
||||
private final List<BatchConversionServiceCustomizer> batchConversionServiceCustomizers;
|
||||
|
||||
private final ExecutionContextSerializer executionContextSerializer;
|
||||
|
||||
private final JobParametersConverter jobParametersConverter;
|
||||
|
||||
SpringBootBatchConfiguration(DataSource dataSource, @BatchDataSource ObjectProvider<DataSource> batchDataSource,
|
||||
PlatformTransactionManager transactionManager,
|
||||
@BatchTransactionManager ObjectProvider<PlatformTransactionManager> batchTransactionManager,
|
||||
@BatchTaskExecutor ObjectProvider<TaskExecutor> batchTaskExecutor, BatchProperties properties,
|
||||
ObjectProvider<BatchConversionServiceCustomizer> batchConversionServiceCustomizers,
|
||||
ObjectProvider<ExecutionContextSerializer> executionContextSerializer,
|
||||
ObjectProvider<JobParametersConverter> jobParametersConverter) {
|
||||
this.dataSource = batchDataSource.getIfAvailable(() -> dataSource);
|
||||
this.transactionManager = batchTransactionManager.getIfAvailable(() -> transactionManager);
|
||||
this.taskExecutor = batchTaskExecutor.getIfAvailable();
|
||||
this.properties = properties;
|
||||
this.batchConversionServiceCustomizers = batchConversionServiceCustomizers.orderedStream().toList();
|
||||
this.executionContextSerializer = executionContextSerializer.getIfAvailable();
|
||||
this.jobParametersConverter = jobParametersConverter.getIfAvailable();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected DataSource getDataSource() {
|
||||
return this.dataSource;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected PlatformTransactionManager getTransactionManager() {
|
||||
return this.transactionManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getTablePrefix() {
|
||||
String tablePrefix = this.properties.getJdbc().getTablePrefix();
|
||||
return (tablePrefix != null) ? tablePrefix : super.getTablePrefix();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean getValidateTransactionState() {
|
||||
return this.properties.getJdbc().isValidateTransactionState();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Isolation getIsolationLevelForCreate() {
|
||||
Isolation isolation = this.properties.getJdbc().getIsolationLevelForCreate();
|
||||
return (isolation != null) ? isolation : super.getIsolationLevelForCreate();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ConfigurableConversionService getConversionService() {
|
||||
ConfigurableConversionService conversionService = super.getConversionService();
|
||||
for (BatchConversionServiceCustomizer customizer : this.batchConversionServiceCustomizers) {
|
||||
customizer.customize(conversionService);
|
||||
}
|
||||
return conversionService;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ExecutionContextSerializer getExecutionContextSerializer() {
|
||||
return (this.executionContextSerializer != null) ? this.executionContextSerializer
|
||||
: super.getExecutionContextSerializer();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JobParametersConverter getJobParametersConverter() {
|
||||
return (this.jobParametersConverter != null) ? this.jobParametersConverter
|
||||
: super.getJobParametersConverter();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TaskExecutor getTaskExecutor() {
|
||||
return (this.taskExecutor != null) ? this.taskExecutor : super.getTaskExecutor();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@Conditional(OnBatchDatasourceInitializationCondition.class)
|
||||
static class DataSourceInitializerConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
BatchDataSourceScriptDatabaseInitializer batchDataSourceInitializer(DataSource dataSource,
|
||||
@BatchDataSource ObjectProvider<DataSource> batchDataSource, BatchProperties properties) {
|
||||
return new BatchDataSourceScriptDatabaseInitializer(batchDataSource.getIfAvailable(() -> dataSource),
|
||||
properties.getJdbc());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class OnBatchDatasourceInitializationCondition extends OnDatabaseInitializationCondition {
|
||||
|
||||
OnBatchDatasourceInitializationCondition() {
|
||||
super("Batch", "spring.batch.jdbc.initialize-schema");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2023 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.batch;
|
||||
|
||||
import org.springframework.batch.core.configuration.support.DefaultBatchConfiguration;
|
||||
import org.springframework.core.convert.support.ConfigurableConversionService;
|
||||
|
||||
/**
|
||||
* Callback interface that can be implemented by beans wishing to customize the
|
||||
* {@link ConfigurableConversionService} that is
|
||||
* {@link DefaultBatchConfiguration#getConversionService provided by
|
||||
* DefaultBatchConfiguration} while retaining its default auto-configuration.
|
||||
*
|
||||
* @author Claudio Nave
|
||||
* @since 3.1.0
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface BatchConversionServiceCustomizer {
|
||||
|
||||
/**
|
||||
* Customize the {@link ConfigurableConversionService}.
|
||||
* @param configurableConversionService the ConfigurableConversionService to customize
|
||||
*/
|
||||
void customize(ConfigurableConversionService configurableConversionService);
|
||||
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2019 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.batch;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
|
||||
/**
|
||||
* Qualifier annotation for a DataSource to be injected into Batch auto-configuration. Can
|
||||
* be used on a secondary data source, if there is another one marked as
|
||||
* {@link Primary @Primary}.
|
||||
*
|
||||
* @author Dmytro Nosan
|
||||
* @since 2.2.0
|
||||
*/
|
||||
@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@Qualifier
|
||||
public @interface BatchDataSource {
|
||||
|
||||
}
|
||||
@@ -1,86 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2022 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.batch;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.springframework.boot.jdbc.init.DataSourceScriptDatabaseInitializer;
|
||||
import org.springframework.boot.jdbc.init.PlatformPlaceholderDatabaseDriverResolver;
|
||||
import org.springframework.boot.sql.init.DatabaseInitializationSettings;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* {@link DataSourceScriptDatabaseInitializer} for the Spring Batch database. May be
|
||||
* registered as a bean to override auto-configuration.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @author Vedran Pavic
|
||||
* @author Andy Wilkinson
|
||||
* @author Phillip Webb
|
||||
* @since 2.6.0
|
||||
*/
|
||||
public class BatchDataSourceScriptDatabaseInitializer extends DataSourceScriptDatabaseInitializer {
|
||||
|
||||
/**
|
||||
* Create a new {@link BatchDataSourceScriptDatabaseInitializer} instance.
|
||||
* @param dataSource the Spring Batch data source
|
||||
* @param properties the Spring Batch JDBC properties
|
||||
* @see #getSettings
|
||||
*/
|
||||
public BatchDataSourceScriptDatabaseInitializer(DataSource dataSource, BatchProperties.Jdbc properties) {
|
||||
this(dataSource, getSettings(dataSource, properties));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link BatchDataSourceScriptDatabaseInitializer} instance.
|
||||
* @param dataSource the Spring Batch data source
|
||||
* @param settings the database initialization settings
|
||||
* @see #getSettings
|
||||
*/
|
||||
public BatchDataSourceScriptDatabaseInitializer(DataSource dataSource, DatabaseInitializationSettings settings) {
|
||||
super(dataSource, settings);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adapts {@link BatchProperties.Jdbc Spring Batch JDBC properties} to
|
||||
* {@link DatabaseInitializationSettings} replacing any {@literal @@platform@@}
|
||||
* placeholders.
|
||||
* @param dataSource the Spring Batch data source
|
||||
* @param properties batch JDBC properties
|
||||
* @return a new {@link DatabaseInitializationSettings} instance
|
||||
* @see #BatchDataSourceScriptDatabaseInitializer(DataSource,
|
||||
* DatabaseInitializationSettings)
|
||||
*/
|
||||
public static DatabaseInitializationSettings getSettings(DataSource dataSource, BatchProperties.Jdbc properties) {
|
||||
DatabaseInitializationSettings settings = new DatabaseInitializationSettings();
|
||||
settings.setSchemaLocations(resolveSchemaLocations(dataSource, properties));
|
||||
settings.setMode(properties.getInitializeSchema());
|
||||
settings.setContinueOnError(true);
|
||||
return settings;
|
||||
}
|
||||
|
||||
private static List<String> resolveSchemaLocations(DataSource dataSource, BatchProperties.Jdbc properties) {
|
||||
PlatformPlaceholderDatabaseDriverResolver platformResolver = new PlatformPlaceholderDatabaseDriverResolver();
|
||||
if (StringUtils.hasText(properties.getPlatform())) {
|
||||
return platformResolver.resolveAll(properties.getPlatform(), properties.getSchema());
|
||||
}
|
||||
return platformResolver.resolveAll(dataSource, properties.getSchema());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,152 +0,0 @@
|
||||
/*
|
||||
* 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.batch;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.boot.sql.init.DatabaseInitializationMode;
|
||||
import org.springframework.transaction.annotation.Isolation;
|
||||
|
||||
/**
|
||||
* Configuration properties for Spring Batch.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @author Eddú Meléndez
|
||||
* @author Vedran Pavic
|
||||
* @author Mukul Kumar Chaundhyan
|
||||
* @author Yanming Zhou
|
||||
* @since 1.2.0
|
||||
*/
|
||||
@ConfigurationProperties("spring.batch")
|
||||
public class BatchProperties {
|
||||
|
||||
private final Job job = new Job();
|
||||
|
||||
private final Jdbc jdbc = new Jdbc();
|
||||
|
||||
public Job getJob() {
|
||||
return this.job;
|
||||
}
|
||||
|
||||
public Jdbc getJdbc() {
|
||||
return this.jdbc;
|
||||
}
|
||||
|
||||
public static class Job {
|
||||
|
||||
/**
|
||||
* Job name to execute on startup. Must be specified if multiple Jobs are found in
|
||||
* the context.
|
||||
*/
|
||||
private String name = "";
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class Jdbc {
|
||||
|
||||
private static final String DEFAULT_SCHEMA_LOCATION = "classpath:org/springframework/"
|
||||
+ "batch/core/schema-@@platform@@.sql";
|
||||
|
||||
/**
|
||||
* Whether to validate the transaction state.
|
||||
*/
|
||||
private boolean validateTransactionState = true;
|
||||
|
||||
/**
|
||||
* Transaction isolation level to use when creating job meta-data for new jobs.
|
||||
*/
|
||||
private Isolation isolationLevelForCreate;
|
||||
|
||||
/**
|
||||
* Path to the SQL file to use to initialize the database schema.
|
||||
*/
|
||||
private String schema = DEFAULT_SCHEMA_LOCATION;
|
||||
|
||||
/**
|
||||
* Platform to use in initialization scripts if the @@platform@@ placeholder is
|
||||
* used. Auto-detected by default.
|
||||
*/
|
||||
private String platform;
|
||||
|
||||
/**
|
||||
* Table prefix for all the batch meta-data tables.
|
||||
*/
|
||||
private String tablePrefix;
|
||||
|
||||
/**
|
||||
* Database schema initialization mode.
|
||||
*/
|
||||
private DatabaseInitializationMode initializeSchema = DatabaseInitializationMode.EMBEDDED;
|
||||
|
||||
public boolean isValidateTransactionState() {
|
||||
return this.validateTransactionState;
|
||||
}
|
||||
|
||||
public void setValidateTransactionState(boolean validateTransactionState) {
|
||||
this.validateTransactionState = validateTransactionState;
|
||||
}
|
||||
|
||||
public Isolation getIsolationLevelForCreate() {
|
||||
return this.isolationLevelForCreate;
|
||||
}
|
||||
|
||||
public void setIsolationLevelForCreate(Isolation isolationLevelForCreate) {
|
||||
this.isolationLevelForCreate = isolationLevelForCreate;
|
||||
}
|
||||
|
||||
public String getSchema() {
|
||||
return this.schema;
|
||||
}
|
||||
|
||||
public void setSchema(String schema) {
|
||||
this.schema = schema;
|
||||
}
|
||||
|
||||
public String getPlatform() {
|
||||
return this.platform;
|
||||
}
|
||||
|
||||
public void setPlatform(String platform) {
|
||||
this.platform = platform;
|
||||
}
|
||||
|
||||
public String getTablePrefix() {
|
||||
return this.tablePrefix;
|
||||
}
|
||||
|
||||
public void setTablePrefix(String tablePrefix) {
|
||||
this.tablePrefix = tablePrefix;
|
||||
}
|
||||
|
||||
public DatabaseInitializationMode getInitializeSchema() {
|
||||
return this.initializeSchema;
|
||||
}
|
||||
|
||||
public void setInitializeSchema(DatabaseInitializationMode initializeSchema) {
|
||||
this.initializeSchema = initializeSchema;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2024 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.batch;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.core.task.TaskExecutor;
|
||||
|
||||
/**
|
||||
* Qualifier annotation for a {@link TaskExecutor} to be injected into Batch
|
||||
* auto-configuration. Can be used on a secondary task executor source, if there is
|
||||
* another one marked as {@link Primary @Primary}.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
* @since 3.4.0
|
||||
*/
|
||||
@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@Qualifier
|
||||
public @interface BatchTaskExecutor {
|
||||
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2024 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.batch;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
|
||||
/**
|
||||
* Qualifier annotation for a {@link PlatformTransactionManager} to be injected into Batch
|
||||
* auto-configuration. Can be used on a secondary {@link PlatformTransactionManager}, if
|
||||
* there is another one marked as {@link Primary @Primary}.
|
||||
*
|
||||
* @author Lasse Wulff
|
||||
* @since 3.3.0
|
||||
*/
|
||||
@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@Qualifier
|
||||
public @interface BatchTransactionManager {
|
||||
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2019 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.batch;
|
||||
|
||||
import org.springframework.batch.core.JobExecution;
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
|
||||
/**
|
||||
* Spring {@link ApplicationEvent} encapsulating a {@link JobExecution}.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class JobExecutionEvent extends ApplicationEvent {
|
||||
|
||||
private final JobExecution execution;
|
||||
|
||||
/**
|
||||
* Create a new {@link JobExecutionEvent} instance.
|
||||
* @param execution the job execution
|
||||
*/
|
||||
public JobExecutionEvent(JobExecution execution) {
|
||||
super(execution);
|
||||
this.execution = execution;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the job execution.
|
||||
* @return the job execution
|
||||
*/
|
||||
public JobExecution getJobExecution() {
|
||||
return this.execution;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2022 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.batch;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
import org.springframework.batch.core.JobExecution;
|
||||
import org.springframework.boot.ExitCodeGenerator;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
|
||||
/**
|
||||
* {@link ExitCodeGenerator} for {@link JobExecutionEvent}s.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class JobExecutionExitCodeGenerator implements ApplicationListener<JobExecutionEvent>, ExitCodeGenerator {
|
||||
|
||||
private final List<JobExecution> executions = new CopyOnWriteArrayList<>();
|
||||
|
||||
@Override
|
||||
public void onApplicationEvent(JobExecutionEvent event) {
|
||||
this.executions.add(event.getJobExecution());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getExitCode() {
|
||||
for (JobExecution execution : this.executions) {
|
||||
if (execution.getStatus().ordinal() > 0) {
|
||||
return execution.getStatus().ordinal();
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,251 +0,0 @@
|
||||
/*
|
||||
* 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.batch;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.batch.core.BatchStatus;
|
||||
import org.springframework.batch.core.Job;
|
||||
import org.springframework.batch.core.JobExecution;
|
||||
import org.springframework.batch.core.JobExecutionException;
|
||||
import org.springframework.batch.core.JobParameter;
|
||||
import org.springframework.batch.core.JobParameters;
|
||||
import org.springframework.batch.core.JobParametersBuilder;
|
||||
import org.springframework.batch.core.JobParametersInvalidException;
|
||||
import org.springframework.batch.core.configuration.JobRegistry;
|
||||
import org.springframework.batch.core.converter.DefaultJobParametersConverter;
|
||||
import org.springframework.batch.core.converter.JobParametersConverter;
|
||||
import org.springframework.batch.core.explore.JobExplorer;
|
||||
import org.springframework.batch.core.launch.JobLauncher;
|
||||
import org.springframework.batch.core.repository.JobExecutionAlreadyRunningException;
|
||||
import org.springframework.batch.core.repository.JobInstanceAlreadyCompleteException;
|
||||
import org.springframework.batch.core.repository.JobRepository;
|
||||
import org.springframework.batch.core.repository.JobRestartException;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.ApplicationArguments;
|
||||
import org.springframework.boot.ApplicationRunner;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.context.ApplicationEventPublisherAware;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.log.LogMessage;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* {@link ApplicationRunner} to {@link JobLauncher launch} Spring Batch jobs. If a single
|
||||
* job is found in the context, it will be executed by default. If multiple jobs are
|
||||
* found, launch a specific job by providing a jobName.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @author Jean-Pierre Bergamin
|
||||
* @author Mahmoud Ben Hassine
|
||||
* @author Stephane Nicoll
|
||||
* @author Akshay Dubey
|
||||
* @since 2.3.0
|
||||
*/
|
||||
public class JobLauncherApplicationRunner
|
||||
implements ApplicationRunner, InitializingBean, Ordered, ApplicationEventPublisherAware {
|
||||
|
||||
/**
|
||||
* The default order for the command line runner.
|
||||
*/
|
||||
public static final int DEFAULT_ORDER = 0;
|
||||
|
||||
private static final Log logger = LogFactory.getLog(JobLauncherApplicationRunner.class);
|
||||
|
||||
private JobParametersConverter converter = new DefaultJobParametersConverter();
|
||||
|
||||
private final JobLauncher jobLauncher;
|
||||
|
||||
private final JobExplorer jobExplorer;
|
||||
|
||||
private final JobRepository jobRepository;
|
||||
|
||||
private JobRegistry jobRegistry;
|
||||
|
||||
private String jobName;
|
||||
|
||||
private Collection<Job> jobs = Collections.emptySet();
|
||||
|
||||
private int order = DEFAULT_ORDER;
|
||||
|
||||
private ApplicationEventPublisher publisher;
|
||||
|
||||
/**
|
||||
* Create a new {@link JobLauncherApplicationRunner}.
|
||||
* @param jobLauncher to launch jobs
|
||||
* @param jobExplorer to check the job repository for previous executions
|
||||
* @param jobRepository to check if a job instance exists with the given parameters
|
||||
* when running a job
|
||||
*/
|
||||
public JobLauncherApplicationRunner(JobLauncher jobLauncher, JobExplorer jobExplorer, JobRepository jobRepository) {
|
||||
Assert.notNull(jobLauncher, "'jobLauncher' must not be null");
|
||||
Assert.notNull(jobExplorer, "'jobExplorer' must not be null");
|
||||
Assert.notNull(jobRepository, "'jobRepository' must not be null");
|
||||
this.jobLauncher = jobLauncher;
|
||||
this.jobExplorer = jobExplorer;
|
||||
this.jobRepository = jobRepository;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() {
|
||||
Assert.state(this.jobs.size() <= 1 || StringUtils.hasText(this.jobName),
|
||||
"Job name must be specified in case of multiple jobs");
|
||||
if (StringUtils.hasText(this.jobName)) {
|
||||
Assert.state(isLocalJob(this.jobName) || isRegisteredJob(this.jobName),
|
||||
() -> "No job found with name '" + this.jobName + "'");
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated(since = "3.0.10", forRemoval = true)
|
||||
public void validate() {
|
||||
afterPropertiesSet();
|
||||
}
|
||||
|
||||
public void setOrder(int order) {
|
||||
this.order = order;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return this.order;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setApplicationEventPublisher(ApplicationEventPublisher publisher) {
|
||||
this.publisher = publisher;
|
||||
}
|
||||
|
||||
@Autowired(required = false)
|
||||
public void setJobRegistry(JobRegistry jobRegistry) {
|
||||
this.jobRegistry = jobRegistry;
|
||||
}
|
||||
|
||||
public void setJobName(String jobName) {
|
||||
this.jobName = jobName;
|
||||
}
|
||||
|
||||
@Autowired(required = false)
|
||||
public void setJobParametersConverter(JobParametersConverter converter) {
|
||||
this.converter = converter;
|
||||
}
|
||||
|
||||
@Autowired(required = false)
|
||||
public void setJobs(Collection<Job> jobs) {
|
||||
this.jobs = jobs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(ApplicationArguments args) throws Exception {
|
||||
String[] jobArguments = args.getNonOptionArgs().toArray(new String[0]);
|
||||
run(jobArguments);
|
||||
}
|
||||
|
||||
public void run(String... args) throws JobExecutionException {
|
||||
logger.info("Running default command line with: " + Arrays.asList(args));
|
||||
launchJobFromProperties(StringUtils.splitArrayElementsIntoProperties(args, "="));
|
||||
}
|
||||
|
||||
protected void launchJobFromProperties(Properties properties) throws JobExecutionException {
|
||||
JobParameters jobParameters = this.converter.getJobParameters(properties);
|
||||
executeLocalJobs(jobParameters);
|
||||
executeRegisteredJobs(jobParameters);
|
||||
}
|
||||
|
||||
private boolean isLocalJob(String jobName) {
|
||||
return this.jobs.stream().anyMatch((job) -> job.getName().equals(jobName));
|
||||
}
|
||||
|
||||
private boolean isRegisteredJob(String jobName) {
|
||||
return this.jobRegistry != null && this.jobRegistry.getJobNames().contains(jobName);
|
||||
}
|
||||
|
||||
private void executeLocalJobs(JobParameters jobParameters) throws JobExecutionException {
|
||||
for (Job job : this.jobs) {
|
||||
if (StringUtils.hasText(this.jobName)) {
|
||||
if (!this.jobName.equals(job.getName())) {
|
||||
logger.debug(LogMessage.format("Skipped job: %s", job.getName()));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
execute(job, jobParameters);
|
||||
}
|
||||
}
|
||||
|
||||
private void executeRegisteredJobs(JobParameters jobParameters) throws JobExecutionException {
|
||||
if (this.jobRegistry != null && StringUtils.hasText(this.jobName)) {
|
||||
if (!isLocalJob(this.jobName)) {
|
||||
Job job = this.jobRegistry.getJob(this.jobName);
|
||||
execute(job, jobParameters);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void execute(Job job, JobParameters jobParameters) throws JobExecutionAlreadyRunningException,
|
||||
JobRestartException, JobInstanceAlreadyCompleteException, JobParametersInvalidException {
|
||||
JobParameters parameters = getNextJobParameters(job, jobParameters);
|
||||
JobExecution execution = this.jobLauncher.run(job, parameters);
|
||||
if (this.publisher != null) {
|
||||
this.publisher.publishEvent(new JobExecutionEvent(execution));
|
||||
}
|
||||
}
|
||||
|
||||
private JobParameters getNextJobParameters(Job job, JobParameters jobParameters) {
|
||||
if (this.jobRepository != null && this.jobRepository.isJobInstanceExists(job.getName(), jobParameters)) {
|
||||
return getNextJobParametersForExisting(job, jobParameters);
|
||||
}
|
||||
if (job.getJobParametersIncrementer() == null) {
|
||||
return jobParameters;
|
||||
}
|
||||
JobParameters nextParameters = new JobParametersBuilder(jobParameters, this.jobExplorer)
|
||||
.getNextJobParameters(job)
|
||||
.toJobParameters();
|
||||
return merge(nextParameters, jobParameters);
|
||||
}
|
||||
|
||||
private JobParameters getNextJobParametersForExisting(Job job, JobParameters jobParameters) {
|
||||
JobExecution lastExecution = this.jobRepository.getLastJobExecution(job.getName(), jobParameters);
|
||||
if (isStoppedOrFailed(lastExecution) && job.isRestartable()) {
|
||||
JobParameters previousIdentifyingParameters = new JobParameters(
|
||||
lastExecution.getJobParameters().getIdentifyingParameters());
|
||||
return merge(previousIdentifyingParameters, jobParameters);
|
||||
}
|
||||
return jobParameters;
|
||||
}
|
||||
|
||||
private boolean isStoppedOrFailed(JobExecution execution) {
|
||||
BatchStatus status = (execution != null) ? execution.getStatus() : null;
|
||||
return (status == BatchStatus.STOPPED || status == BatchStatus.FAILED);
|
||||
}
|
||||
|
||||
private JobParameters merge(JobParameters parameters, JobParameters additionals) {
|
||||
Map<String, JobParameter<?>> merged = new LinkedHashMap<>();
|
||||
merged.putAll(parameters.getParameters());
|
||||
merged.putAll(additionals.getParameters());
|
||||
return new JobParameters(merged);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2021 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.batch;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.batch.core.repository.JobRepository;
|
||||
import org.springframework.boot.sql.init.dependency.AbstractBeansOfTypeDependsOnDatabaseInitializationDetector;
|
||||
import org.springframework.boot.sql.init.dependency.DependsOnDatabaseInitializationDetector;
|
||||
|
||||
/**
|
||||
* {@link DependsOnDatabaseInitializationDetector} for Spring Batch's
|
||||
* {@link JobRepository}.
|
||||
*
|
||||
* @author Henning Pöttker
|
||||
*/
|
||||
class JobRepositoryDependsOnDatabaseInitializationDetector
|
||||
extends AbstractBeansOfTypeDependsOnDatabaseInitializationDetector {
|
||||
|
||||
@Override
|
||||
protected Set<Class<?>> getDependsOnDatabaseInitializationBeanTypes() {
|
||||
return Collections.singleton(JobRepository.class);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2019 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Auto-configuration for Spring Batch.
|
||||
*/
|
||||
package org.springframework.boot.autoconfigure.batch;
|
||||
@@ -1,38 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2023 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.cache;
|
||||
|
||||
import org.cache2k.Cache2kBuilder;
|
||||
|
||||
/**
|
||||
* Callback interface that can be implemented by beans wishing to customize the default
|
||||
* setup for caches added to the manager through addCaches and for dynamically created
|
||||
* caches.
|
||||
*
|
||||
* @author Jens Wilke
|
||||
* @author Stephane Nicoll
|
||||
* @since 2.7.0
|
||||
*/
|
||||
public interface Cache2kBuilderCustomizer {
|
||||
|
||||
/**
|
||||
* Customize the default cache settings.
|
||||
* @param builder the builder to customize
|
||||
*/
|
||||
void customize(Cache2kBuilder<?, ?> builder);
|
||||
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2022 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.cache;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.cache2k.Cache2kBuilder;
|
||||
import org.cache2k.extra.spring.SpringCache2kCacheManager;
|
||||
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
/**
|
||||
* Cache2k cache configuration.
|
||||
*
|
||||
* @author Jens Wilke
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass({ Cache2kBuilder.class, SpringCache2kCacheManager.class })
|
||||
@ConditionalOnMissingBean(CacheManager.class)
|
||||
@Conditional(CacheCondition.class)
|
||||
class Cache2kCacheConfiguration {
|
||||
|
||||
@Bean
|
||||
SpringCache2kCacheManager cacheManager(CacheProperties cacheProperties, CacheManagerCustomizers customizers,
|
||||
ObjectProvider<Cache2kBuilderCustomizer> cache2kBuilderCustomizers) {
|
||||
SpringCache2kCacheManager cacheManager = new SpringCache2kCacheManager();
|
||||
cacheManager.defaultSetup(configureDefaults(cache2kBuilderCustomizers));
|
||||
Collection<String> cacheNames = cacheProperties.getCacheNames();
|
||||
if (!CollectionUtils.isEmpty(cacheNames)) {
|
||||
cacheManager.setDefaultCacheNames(cacheNames);
|
||||
}
|
||||
return customizers.customize(cacheManager);
|
||||
}
|
||||
|
||||
private Function<Cache2kBuilder<?, ?>, Cache2kBuilder<?, ?>> configureDefaults(
|
||||
ObjectProvider<Cache2kBuilderCustomizer> cache2kBuilderCustomizers) {
|
||||
return (builder) -> {
|
||||
cache2kBuilderCustomizers.orderedStream().forEach((customizer) -> customizer.customize(builder));
|
||||
return builder;
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,129 +0,0 @@
|
||||
/*
|
||||
* 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.cache;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration.CacheConfigurationImportSelector;
|
||||
import org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration.CacheManagerEntityManagerFactoryDependsOnPostProcessor;
|
||||
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.data.couchbase.CouchbaseDataAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.hazelcast.HazelcastAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.orm.jpa.EntityManagerFactoryDependsOnPostProcessor;
|
||||
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.cache.annotation.EnableCaching;
|
||||
import org.springframework.cache.interceptor.CacheAspectSupport;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.context.annotation.ImportSelector;
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
import org.springframework.orm.jpa.AbstractEntityManagerFactoryBean;
|
||||
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* {@link EnableAutoConfiguration Auto-configuration} for the cache abstraction. Creates a
|
||||
* {@link CacheManager} if necessary when caching is enabled via
|
||||
* {@link EnableCaching @EnableCaching}.
|
||||
* <p>
|
||||
* Cache store can be auto-detected or specified explicitly through configuration.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @since 1.3.0
|
||||
* @see EnableCaching
|
||||
*/
|
||||
@AutoConfiguration(after = { CouchbaseDataAutoConfiguration.class, HazelcastAutoConfiguration.class,
|
||||
HibernateJpaAutoConfiguration.class, RedisAutoConfiguration.class })
|
||||
@ConditionalOnClass(CacheManager.class)
|
||||
@ConditionalOnBean(CacheAspectSupport.class)
|
||||
@ConditionalOnMissingBean(value = CacheManager.class, name = "cacheResolver")
|
||||
@EnableConfigurationProperties(CacheProperties.class)
|
||||
@Import({ CacheConfigurationImportSelector.class, CacheManagerEntityManagerFactoryDependsOnPostProcessor.class })
|
||||
public class CacheAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public CacheManagerCustomizers cacheManagerCustomizers(ObjectProvider<CacheManagerCustomizer<?>> customizers) {
|
||||
return new CacheManagerCustomizers(customizers.orderedStream().toList());
|
||||
}
|
||||
|
||||
@Bean
|
||||
public CacheManagerValidator cacheAutoConfigurationValidator(CacheProperties cacheProperties,
|
||||
ObjectProvider<CacheManager> cacheManager) {
|
||||
return new CacheManagerValidator(cacheProperties, cacheManager);
|
||||
}
|
||||
|
||||
@ConditionalOnClass(LocalContainerEntityManagerFactoryBean.class)
|
||||
@ConditionalOnBean(AbstractEntityManagerFactoryBean.class)
|
||||
static class CacheManagerEntityManagerFactoryDependsOnPostProcessor
|
||||
extends EntityManagerFactoryDependsOnPostProcessor {
|
||||
|
||||
CacheManagerEntityManagerFactoryDependsOnPostProcessor() {
|
||||
super("cacheManager");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Bean used to validate that a CacheManager exists and provide a more meaningful
|
||||
* exception.
|
||||
*/
|
||||
static class CacheManagerValidator implements InitializingBean {
|
||||
|
||||
private final CacheProperties cacheProperties;
|
||||
|
||||
private final ObjectProvider<CacheManager> cacheManager;
|
||||
|
||||
CacheManagerValidator(CacheProperties cacheProperties, ObjectProvider<CacheManager> cacheManager) {
|
||||
this.cacheProperties = cacheProperties;
|
||||
this.cacheManager = cacheManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() {
|
||||
Assert.state(this.cacheManager.getIfAvailable() != null,
|
||||
() -> "No cache manager could be auto-configured, check your configuration (caching type is '"
|
||||
+ this.cacheProperties.getType() + "')");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link ImportSelector} to add {@link CacheType} configuration classes.
|
||||
*/
|
||||
static class CacheConfigurationImportSelector implements ImportSelector {
|
||||
|
||||
@Override
|
||||
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
|
||||
CacheType[] types = CacheType.values();
|
||||
String[] imports = new String[types.length];
|
||||
for (int i = 0; i < types.length; i++) {
|
||||
imports[i] = CacheConfigurations.getConfigurationClass(types[i]);
|
||||
}
|
||||
return imports;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2024 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.cache;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionMessage;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionOutcome;
|
||||
import org.springframework.boot.autoconfigure.condition.SpringBootCondition;
|
||||
import org.springframework.boot.context.properties.bind.BindException;
|
||||
import org.springframework.boot.context.properties.bind.BindResult;
|
||||
import org.springframework.boot.context.properties.bind.Binder;
|
||||
import org.springframework.context.annotation.ConditionContext;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.core.type.AnnotatedTypeMetadata;
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
import org.springframework.core.type.ClassMetadata;
|
||||
|
||||
/**
|
||||
* General cache condition used with all cache configuration classes.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @author Phillip Webb
|
||||
* @author Madhura Bhave
|
||||
*/
|
||||
class CacheCondition extends SpringBootCondition {
|
||||
|
||||
@Override
|
||||
public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
|
||||
String sourceClass = "";
|
||||
if (metadata instanceof ClassMetadata classMetadata) {
|
||||
sourceClass = classMetadata.getClassName();
|
||||
}
|
||||
ConditionMessage.Builder message = ConditionMessage.forCondition("Cache", sourceClass);
|
||||
Environment environment = context.getEnvironment();
|
||||
try {
|
||||
BindResult<CacheType> specified = Binder.get(environment).bind("spring.cache.type", CacheType.class);
|
||||
if (!specified.isBound()) {
|
||||
return ConditionOutcome.match(message.because("automatic cache type"));
|
||||
}
|
||||
CacheType required = CacheConfigurations.getType(((AnnotationMetadata) metadata).getClassName());
|
||||
if (specified.get() == required) {
|
||||
return ConditionOutcome.match(message.because(specified.get() + " cache type"));
|
||||
}
|
||||
}
|
||||
catch (BindException ex) {
|
||||
// Ignore
|
||||
}
|
||||
return ConditionOutcome.noMatch(message.because("unknown cache type"));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2022 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.cache;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.EnumMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Mappings between {@link CacheType} and {@code @Configuration}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @author Eddú Meléndez
|
||||
* @author Sebastien Deleuze
|
||||
*/
|
||||
final class CacheConfigurations {
|
||||
|
||||
private static final Map<CacheType, String> MAPPINGS;
|
||||
|
||||
static {
|
||||
Map<CacheType, String> mappings = new EnumMap<>(CacheType.class);
|
||||
mappings.put(CacheType.GENERIC, GenericCacheConfiguration.class.getName());
|
||||
mappings.put(CacheType.HAZELCAST, HazelcastCacheConfiguration.class.getName());
|
||||
mappings.put(CacheType.INFINISPAN, InfinispanCacheConfiguration.class.getName());
|
||||
mappings.put(CacheType.JCACHE, JCacheCacheConfiguration.class.getName());
|
||||
mappings.put(CacheType.COUCHBASE, CouchbaseCacheConfiguration.class.getName());
|
||||
mappings.put(CacheType.REDIS, RedisCacheConfiguration.class.getName());
|
||||
mappings.put(CacheType.CAFFEINE, CaffeineCacheConfiguration.class.getName());
|
||||
mappings.put(CacheType.CACHE2K, Cache2kCacheConfiguration.class.getName());
|
||||
mappings.put(CacheType.SIMPLE, SimpleCacheConfiguration.class.getName());
|
||||
mappings.put(CacheType.NONE, NoOpCacheConfiguration.class.getName());
|
||||
MAPPINGS = Collections.unmodifiableMap(mappings);
|
||||
}
|
||||
|
||||
private CacheConfigurations() {
|
||||
}
|
||||
|
||||
static String getConfigurationClass(CacheType cacheType) {
|
||||
String configurationClassName = MAPPINGS.get(cacheType);
|
||||
Assert.state(configurationClassName != null, () -> "Unknown cache type " + cacheType);
|
||||
return configurationClassName;
|
||||
}
|
||||
|
||||
static CacheType getType(String configurationClassName) {
|
||||
for (Map.Entry<CacheType, String> entry : MAPPINGS.entrySet()) {
|
||||
if (entry.getValue().equals(configurationClassName)) {
|
||||
return entry.getKey();
|
||||
}
|
||||
}
|
||||
throw new IllegalStateException("Unknown configuration class " + configurationClassName);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2019 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.cache;
|
||||
|
||||
import org.springframework.cache.CacheManager;
|
||||
|
||||
/**
|
||||
* Callback interface that can be implemented by beans wishing to customize the cache
|
||||
* manager before it is fully initialized, in particular to tune its configuration.
|
||||
*
|
||||
* @param <T> the type of the {@link CacheManager}
|
||||
* @author Stephane Nicoll
|
||||
* @since 1.3.3
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface CacheManagerCustomizer<T extends CacheManager> {
|
||||
|
||||
/**
|
||||
* Customize the cache manager.
|
||||
* @param cacheManager the {@code CacheManager} to customize
|
||||
*/
|
||||
void customize(T cacheManager);
|
||||
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2023 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.cache;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.boot.util.LambdaSafe;
|
||||
import org.springframework.cache.CacheManager;
|
||||
|
||||
/**
|
||||
* Invokes the available {@link CacheManagerCustomizer} instances in the context for a
|
||||
* given {@link CacheManager}.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @since 1.5.0
|
||||
*/
|
||||
public class CacheManagerCustomizers {
|
||||
|
||||
private final List<CacheManagerCustomizer<?>> customizers;
|
||||
|
||||
public CacheManagerCustomizers(List<? extends CacheManagerCustomizer<?>> customizers) {
|
||||
this.customizers = (customizers != null) ? new ArrayList<>(customizers) : Collections.emptyList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Customize the specified {@link CacheManager}. Locates all
|
||||
* {@link CacheManagerCustomizer} beans able to handle the specified instance and
|
||||
* invoke {@link CacheManagerCustomizer#customize(CacheManager)} on them.
|
||||
* @param <T> the type of cache manager
|
||||
* @param cacheManager the cache manager to customize
|
||||
* @return the cache manager
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T extends CacheManager> T customize(T cacheManager) {
|
||||
LambdaSafe.callbacks(CacheManagerCustomizer.class, this.customizers, cacheManager)
|
||||
.withLogger(CacheManagerCustomizers.class)
|
||||
.invoke((customizer) -> customizer.customize(cacheManager));
|
||||
return cacheManager;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,281 +0,0 @@
|
||||
/*
|
||||
* 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.cache;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Configuration properties for the cache abstraction.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @author Eddú Meléndez
|
||||
* @author Ryon Day
|
||||
* @since 1.3.0
|
||||
*/
|
||||
@ConfigurationProperties("spring.cache")
|
||||
public class CacheProperties {
|
||||
|
||||
/**
|
||||
* Cache type. By default, auto-detected according to the environment.
|
||||
*/
|
||||
private CacheType type;
|
||||
|
||||
/**
|
||||
* List of cache names to create if supported by the underlying cache manager.
|
||||
* Usually, this disables the ability to create additional caches on-the-fly.
|
||||
*/
|
||||
private List<String> cacheNames = new ArrayList<>();
|
||||
|
||||
private final Caffeine caffeine = new Caffeine();
|
||||
|
||||
private final Couchbase couchbase = new Couchbase();
|
||||
|
||||
private final Infinispan infinispan = new Infinispan();
|
||||
|
||||
private final JCache jcache = new JCache();
|
||||
|
||||
private final Redis redis = new Redis();
|
||||
|
||||
public CacheType getType() {
|
||||
return this.type;
|
||||
}
|
||||
|
||||
public void setType(CacheType mode) {
|
||||
this.type = mode;
|
||||
}
|
||||
|
||||
public List<String> getCacheNames() {
|
||||
return this.cacheNames;
|
||||
}
|
||||
|
||||
public void setCacheNames(List<String> cacheNames) {
|
||||
this.cacheNames = cacheNames;
|
||||
}
|
||||
|
||||
public Caffeine getCaffeine() {
|
||||
return this.caffeine;
|
||||
}
|
||||
|
||||
public Couchbase getCouchbase() {
|
||||
return this.couchbase;
|
||||
}
|
||||
|
||||
public Infinispan getInfinispan() {
|
||||
return this.infinispan;
|
||||
}
|
||||
|
||||
public JCache getJcache() {
|
||||
return this.jcache;
|
||||
}
|
||||
|
||||
public Redis getRedis() {
|
||||
return this.redis;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the config location if set.
|
||||
* @param config the config resource
|
||||
* @return the location or {@code null} if it is not set
|
||||
* @throws IllegalArgumentException if the config attribute is set to an unknown
|
||||
* location
|
||||
*/
|
||||
public Resource resolveConfigLocation(Resource config) {
|
||||
if (config != null) {
|
||||
Assert.isTrue(config.exists(),
|
||||
() -> "'config' resource [%s] must exist".formatted(config.getDescription()));
|
||||
return config;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Caffeine specific cache properties.
|
||||
*/
|
||||
public static class Caffeine {
|
||||
|
||||
/**
|
||||
* The spec to use to create caches. See CaffeineSpec for more details on the spec
|
||||
* format.
|
||||
*/
|
||||
private String spec;
|
||||
|
||||
public String getSpec() {
|
||||
return this.spec;
|
||||
}
|
||||
|
||||
public void setSpec(String spec) {
|
||||
this.spec = spec;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Couchbase specific cache properties.
|
||||
*/
|
||||
public static class Couchbase {
|
||||
|
||||
/**
|
||||
* Entry expiration. By default the entries never expire. Note that this value is
|
||||
* ultimately converted to seconds.
|
||||
*/
|
||||
private Duration expiration;
|
||||
|
||||
public Duration getExpiration() {
|
||||
return this.expiration;
|
||||
}
|
||||
|
||||
public void setExpiration(Duration expiration) {
|
||||
this.expiration = expiration;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Infinispan specific cache properties.
|
||||
*/
|
||||
public static class Infinispan {
|
||||
|
||||
/**
|
||||
* The location of the configuration file to use to initialize Infinispan.
|
||||
*/
|
||||
private Resource config;
|
||||
|
||||
public Resource getConfig() {
|
||||
return this.config;
|
||||
}
|
||||
|
||||
public void setConfig(Resource config) {
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* JCache (JSR-107) specific cache properties.
|
||||
*/
|
||||
public static class JCache {
|
||||
|
||||
/**
|
||||
* The location of the configuration file to use to initialize the cache manager.
|
||||
* The configuration file is dependent of the underlying cache implementation.
|
||||
*/
|
||||
private Resource config;
|
||||
|
||||
/**
|
||||
* Fully qualified name of the CachingProvider implementation to use to retrieve
|
||||
* the JSR-107 compliant cache manager. Needed only if more than one JSR-107
|
||||
* implementation is available on the classpath.
|
||||
*/
|
||||
private String provider;
|
||||
|
||||
public String getProvider() {
|
||||
return this.provider;
|
||||
}
|
||||
|
||||
public void setProvider(String provider) {
|
||||
this.provider = provider;
|
||||
}
|
||||
|
||||
public Resource getConfig() {
|
||||
return this.config;
|
||||
}
|
||||
|
||||
public void setConfig(Resource config) {
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Redis-specific cache properties.
|
||||
*/
|
||||
public static class Redis {
|
||||
|
||||
/**
|
||||
* Entry expiration. By default the entries never expire.
|
||||
*/
|
||||
private Duration timeToLive;
|
||||
|
||||
/**
|
||||
* Allow caching null values.
|
||||
*/
|
||||
private boolean cacheNullValues = true;
|
||||
|
||||
/**
|
||||
* Key prefix.
|
||||
*/
|
||||
private String keyPrefix;
|
||||
|
||||
/**
|
||||
* Whether to use the key prefix when writing to Redis.
|
||||
*/
|
||||
private boolean useKeyPrefix = true;
|
||||
|
||||
/**
|
||||
* Whether to enable cache statistics.
|
||||
*/
|
||||
private boolean enableStatistics;
|
||||
|
||||
public Duration getTimeToLive() {
|
||||
return this.timeToLive;
|
||||
}
|
||||
|
||||
public void setTimeToLive(Duration timeToLive) {
|
||||
this.timeToLive = timeToLive;
|
||||
}
|
||||
|
||||
public boolean isCacheNullValues() {
|
||||
return this.cacheNullValues;
|
||||
}
|
||||
|
||||
public void setCacheNullValues(boolean cacheNullValues) {
|
||||
this.cacheNullValues = cacheNullValues;
|
||||
}
|
||||
|
||||
public String getKeyPrefix() {
|
||||
return this.keyPrefix;
|
||||
}
|
||||
|
||||
public void setKeyPrefix(String keyPrefix) {
|
||||
this.keyPrefix = keyPrefix;
|
||||
}
|
||||
|
||||
public boolean isUseKeyPrefix() {
|
||||
return this.useKeyPrefix;
|
||||
}
|
||||
|
||||
public void setUseKeyPrefix(boolean useKeyPrefix) {
|
||||
this.useKeyPrefix = useKeyPrefix;
|
||||
}
|
||||
|
||||
public boolean isEnableStatistics() {
|
||||
return this.enableStatistics;
|
||||
}
|
||||
|
||||
public void setEnableStatistics(boolean enableStatistics) {
|
||||
this.enableStatistics = enableStatistics;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2022 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.cache;
|
||||
|
||||
/**
|
||||
* Supported cache types (defined in order of precedence).
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @author Phillip Webb
|
||||
* @author Eddú Meléndez
|
||||
* @since 1.3.0
|
||||
*/
|
||||
public enum CacheType {
|
||||
|
||||
/**
|
||||
* Generic caching using 'Cache' beans from the context.
|
||||
*/
|
||||
GENERIC,
|
||||
|
||||
/**
|
||||
* JCache (JSR-107) backed caching.
|
||||
*/
|
||||
JCACHE,
|
||||
|
||||
/**
|
||||
* Hazelcast backed caching.
|
||||
*/
|
||||
HAZELCAST,
|
||||
|
||||
/**
|
||||
* Couchbase backed caching.
|
||||
*/
|
||||
COUCHBASE,
|
||||
|
||||
/**
|
||||
* Infinispan backed caching.
|
||||
*/
|
||||
INFINISPAN,
|
||||
|
||||
/**
|
||||
* Redis backed caching.
|
||||
*/
|
||||
REDIS,
|
||||
|
||||
/**
|
||||
* Cache2k backed caching.
|
||||
*/
|
||||
CACHE2K,
|
||||
|
||||
/**
|
||||
* Caffeine backed caching.
|
||||
*/
|
||||
CAFFEINE,
|
||||
|
||||
/**
|
||||
* Simple in-memory caching.
|
||||
*/
|
||||
SIMPLE,
|
||||
|
||||
/**
|
||||
* No caching.
|
||||
*/
|
||||
NONE
|
||||
|
||||
}
|
||||
@@ -1,82 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2019 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.cache;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.github.benmanes.caffeine.cache.CacheLoader;
|
||||
import com.github.benmanes.caffeine.cache.Caffeine;
|
||||
import com.github.benmanes.caffeine.cache.CaffeineSpec;
|
||||
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.cache.caffeine.CaffeineCacheManager;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Caffeine cache configuration.
|
||||
*
|
||||
* @author Eddú Meléndez
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass({ Caffeine.class, CaffeineCacheManager.class })
|
||||
@ConditionalOnMissingBean(CacheManager.class)
|
||||
@Conditional({ CacheCondition.class })
|
||||
class CaffeineCacheConfiguration {
|
||||
|
||||
@Bean
|
||||
CaffeineCacheManager cacheManager(CacheProperties cacheProperties, CacheManagerCustomizers customizers,
|
||||
ObjectProvider<Caffeine<Object, Object>> caffeine, ObjectProvider<CaffeineSpec> caffeineSpec,
|
||||
ObjectProvider<CacheLoader<Object, Object>> cacheLoader) {
|
||||
CaffeineCacheManager cacheManager = createCacheManager(cacheProperties, caffeine, caffeineSpec, cacheLoader);
|
||||
List<String> cacheNames = cacheProperties.getCacheNames();
|
||||
if (!CollectionUtils.isEmpty(cacheNames)) {
|
||||
cacheManager.setCacheNames(cacheNames);
|
||||
}
|
||||
return customizers.customize(cacheManager);
|
||||
}
|
||||
|
||||
private CaffeineCacheManager createCacheManager(CacheProperties cacheProperties,
|
||||
ObjectProvider<Caffeine<Object, Object>> caffeine, ObjectProvider<CaffeineSpec> caffeineSpec,
|
||||
ObjectProvider<CacheLoader<Object, Object>> cacheLoader) {
|
||||
CaffeineCacheManager cacheManager = new CaffeineCacheManager();
|
||||
setCacheBuilder(cacheProperties, caffeineSpec.getIfAvailable(), caffeine.getIfAvailable(), cacheManager);
|
||||
cacheLoader.ifAvailable(cacheManager::setCacheLoader);
|
||||
return cacheManager;
|
||||
}
|
||||
|
||||
private void setCacheBuilder(CacheProperties cacheProperties, CaffeineSpec caffeineSpec,
|
||||
Caffeine<Object, Object> caffeine, CaffeineCacheManager cacheManager) {
|
||||
String specification = cacheProperties.getCaffeine().getSpec();
|
||||
if (StringUtils.hasText(specification)) {
|
||||
cacheManager.setCacheSpecification(specification);
|
||||
}
|
||||
else if (caffeineSpec != null) {
|
||||
cacheManager.setCaffeineSpec(caffeineSpec);
|
||||
}
|
||||
else if (caffeine != null) {
|
||||
cacheManager.setCaffeine(caffeine);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2023 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.cache;
|
||||
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
|
||||
import com.couchbase.client.java.Cluster;
|
||||
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.autoconfigure.cache.CacheProperties.Couchbase;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.couchbase.CouchbaseClientFactory;
|
||||
import org.springframework.data.couchbase.cache.CouchbaseCacheManager;
|
||||
import org.springframework.data.couchbase.cache.CouchbaseCacheManager.CouchbaseCacheManagerBuilder;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* Couchbase cache configuration.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass({ Cluster.class, CouchbaseClientFactory.class, CouchbaseCacheManager.class })
|
||||
@ConditionalOnMissingBean(CacheManager.class)
|
||||
@ConditionalOnSingleCandidate(CouchbaseClientFactory.class)
|
||||
@Conditional(CacheCondition.class)
|
||||
class CouchbaseCacheConfiguration {
|
||||
|
||||
@Bean
|
||||
CouchbaseCacheManager cacheManager(CacheProperties cacheProperties, CacheManagerCustomizers customizers,
|
||||
ObjectProvider<CouchbaseCacheManagerBuilderCustomizer> couchbaseCacheManagerBuilderCustomizers,
|
||||
CouchbaseClientFactory clientFactory) {
|
||||
List<String> cacheNames = cacheProperties.getCacheNames();
|
||||
CouchbaseCacheManagerBuilder builder = CouchbaseCacheManager.builder(clientFactory);
|
||||
Couchbase couchbase = cacheProperties.getCouchbase();
|
||||
org.springframework.data.couchbase.cache.CouchbaseCacheConfiguration config = org.springframework.data.couchbase.cache.CouchbaseCacheConfiguration
|
||||
.defaultCacheConfig();
|
||||
if (couchbase.getExpiration() != null) {
|
||||
config = config.entryExpiry(couchbase.getExpiration());
|
||||
}
|
||||
builder.cacheDefaults(config);
|
||||
if (!ObjectUtils.isEmpty(cacheNames)) {
|
||||
builder.initialCacheNames(new LinkedHashSet<>(cacheNames));
|
||||
}
|
||||
couchbaseCacheManagerBuilderCustomizers.orderedStream().forEach((customizer) -> customizer.customize(builder));
|
||||
CouchbaseCacheManager cacheManager = builder.build();
|
||||
return customizers.customize(cacheManager);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2022 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.cache;
|
||||
|
||||
import org.springframework.data.couchbase.cache.CouchbaseCacheManager;
|
||||
import org.springframework.data.couchbase.cache.CouchbaseCacheManager.CouchbaseCacheManagerBuilder;
|
||||
|
||||
/**
|
||||
* Callback interface that can be implemented by beans wishing to customize the
|
||||
* {@link CouchbaseCacheManagerBuilder} before it is used to build the auto-configured
|
||||
* {@link CouchbaseCacheManager}.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @since 2.3.3
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface CouchbaseCacheManagerBuilderCustomizer {
|
||||
|
||||
/**
|
||||
* Customize the {@link CouchbaseCacheManagerBuilder}.
|
||||
* @param builder the builder to customize
|
||||
*/
|
||||
void customize(CouchbaseCacheManagerBuilder builder);
|
||||
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2019 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.cache;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.cache.support.SimpleCacheManager;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* Generic cache configuration based on arbitrary {@link Cache} instances defined in the
|
||||
* context.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnBean(Cache.class)
|
||||
@ConditionalOnMissingBean(CacheManager.class)
|
||||
@Conditional(CacheCondition.class)
|
||||
class GenericCacheConfiguration {
|
||||
|
||||
@Bean
|
||||
SimpleCacheManager cacheManager(CacheManagerCustomizers customizers, Collection<Cache> caches) {
|
||||
SimpleCacheManager cacheManager = new SimpleCacheManager();
|
||||
cacheManager.setCaches(caches);
|
||||
return customizers.customize(cacheManager);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2022 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.cache;
|
||||
|
||||
import com.hazelcast.core.HazelcastInstance;
|
||||
import com.hazelcast.spring.cache.HazelcastCacheManager;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;
|
||||
import org.springframework.boot.autoconfigure.hazelcast.HazelcastAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.hazelcast.HazelcastConfigResourceCondition;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* Hazelcast cache configuration. Can either reuse the {@link HazelcastInstance} that has
|
||||
* been configured by the general {@link HazelcastAutoConfiguration} or create a separate
|
||||
* one if the {@code spring.cache.hazelcast.config} property has been set.
|
||||
* <p>
|
||||
* If the {@link HazelcastAutoConfiguration} has been disabled, an attempt to configure a
|
||||
* default {@link HazelcastInstance} is still made, using the same defaults.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @see HazelcastConfigResourceCondition
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass({ HazelcastInstance.class, HazelcastCacheManager.class })
|
||||
@ConditionalOnMissingBean(CacheManager.class)
|
||||
@Conditional(CacheCondition.class)
|
||||
@ConditionalOnSingleCandidate(HazelcastInstance.class)
|
||||
class HazelcastCacheConfiguration {
|
||||
|
||||
@Bean
|
||||
HazelcastCacheManager cacheManager(CacheManagerCustomizers customizers,
|
||||
HazelcastInstance existingHazelcastInstance) {
|
||||
HazelcastCacheManager cacheManager = new HazelcastCacheManager(existingHazelcastInstance);
|
||||
return customizers.customize(cacheManager);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,81 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2024 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.cache;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.util.Properties;
|
||||
|
||||
import com.hazelcast.core.HazelcastInstance;
|
||||
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.io.Resource;
|
||||
|
||||
/**
|
||||
* JCache customization for Hazelcast.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass(HazelcastInstance.class)
|
||||
class HazelcastJCacheCustomizationConfiguration {
|
||||
|
||||
@Bean
|
||||
HazelcastPropertiesCustomizer hazelcastPropertiesCustomizer(ObjectProvider<HazelcastInstance> hazelcastInstance,
|
||||
CacheProperties cacheProperties) {
|
||||
return new HazelcastPropertiesCustomizer(hazelcastInstance.getIfUnique(), cacheProperties);
|
||||
}
|
||||
|
||||
static class HazelcastPropertiesCustomizer implements JCachePropertiesCustomizer {
|
||||
|
||||
private final HazelcastInstance hazelcastInstance;
|
||||
|
||||
private final CacheProperties cacheProperties;
|
||||
|
||||
HazelcastPropertiesCustomizer(HazelcastInstance hazelcastInstance, CacheProperties cacheProperties) {
|
||||
this.hazelcastInstance = hazelcastInstance;
|
||||
this.cacheProperties = cacheProperties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void customize(Properties properties) {
|
||||
Resource configLocation = this.cacheProperties
|
||||
.resolveConfigLocation(this.cacheProperties.getJcache().getConfig());
|
||||
if (configLocation != null) {
|
||||
// Hazelcast does not use the URI as a mean to specify a custom config.
|
||||
properties.setProperty("hazelcast.config.location", toUri(configLocation).toString());
|
||||
}
|
||||
else if (this.hazelcastInstance != null) {
|
||||
properties.put("hazelcast.instance.itself", this.hazelcastInstance);
|
||||
}
|
||||
}
|
||||
|
||||
private static URI toUri(Resource config) {
|
||||
try {
|
||||
return config.getURI();
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw new IllegalArgumentException("Could not get URI from " + config, ex);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,90 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2022 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.cache;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.List;
|
||||
|
||||
import org.infinispan.configuration.cache.ConfigurationBuilder;
|
||||
import org.infinispan.manager.DefaultCacheManager;
|
||||
import org.infinispan.manager.EmbeddedCacheManager;
|
||||
import org.infinispan.spring.embedded.provider.SpringEmbeddedCacheManager;
|
||||
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
/**
|
||||
* Infinispan cache configuration.
|
||||
*
|
||||
* @author Eddú Meléndez
|
||||
* @author Stephane Nicoll
|
||||
* @author Raja Kolli
|
||||
* @since 1.3.0
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass(SpringEmbeddedCacheManager.class)
|
||||
@ConditionalOnMissingBean(CacheManager.class)
|
||||
@Conditional(CacheCondition.class)
|
||||
public class InfinispanCacheConfiguration {
|
||||
|
||||
@Bean
|
||||
public SpringEmbeddedCacheManager cacheManager(CacheManagerCustomizers customizers,
|
||||
EmbeddedCacheManager embeddedCacheManager) {
|
||||
SpringEmbeddedCacheManager cacheManager = new SpringEmbeddedCacheManager(embeddedCacheManager);
|
||||
return customizers.customize(cacheManager);
|
||||
}
|
||||
|
||||
@Bean(destroyMethod = "stop")
|
||||
@ConditionalOnMissingBean
|
||||
public EmbeddedCacheManager infinispanCacheManager(CacheProperties cacheProperties,
|
||||
ObjectProvider<ConfigurationBuilder> defaultConfigurationBuilder) throws IOException {
|
||||
EmbeddedCacheManager cacheManager = createEmbeddedCacheManager(cacheProperties);
|
||||
List<String> cacheNames = cacheProperties.getCacheNames();
|
||||
if (!CollectionUtils.isEmpty(cacheNames)) {
|
||||
cacheNames.forEach((cacheName) -> cacheManager.defineConfiguration(cacheName,
|
||||
getDefaultCacheConfiguration(defaultConfigurationBuilder.getIfAvailable())));
|
||||
}
|
||||
return cacheManager;
|
||||
}
|
||||
|
||||
private EmbeddedCacheManager createEmbeddedCacheManager(CacheProperties cacheProperties) throws IOException {
|
||||
Resource location = cacheProperties.resolveConfigLocation(cacheProperties.getInfinispan().getConfig());
|
||||
if (location != null) {
|
||||
try (InputStream in = location.getInputStream()) {
|
||||
return new DefaultCacheManager(in);
|
||||
}
|
||||
}
|
||||
return new DefaultCacheManager();
|
||||
}
|
||||
|
||||
private org.infinispan.configuration.cache.Configuration getDefaultCacheConfiguration(
|
||||
ConfigurationBuilder defaultConfigurationBuilder) {
|
||||
if (defaultConfigurationBuilder != null) {
|
||||
return defaultConfigurationBuilder.build();
|
||||
}
|
||||
return new ConfigurationBuilder().build();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,172 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2024 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.cache;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
|
||||
import javax.cache.CacheManager;
|
||||
import javax.cache.Caching;
|
||||
import javax.cache.configuration.MutableConfiguration;
|
||||
import javax.cache.spi.CachingProvider;
|
||||
|
||||
import org.springframework.beans.factory.BeanClassLoaderAware;
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.autoconfigure.condition.AnyNestedCondition;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionMessage;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionOutcome;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;
|
||||
import org.springframework.boot.autoconfigure.condition.SpringBootCondition;
|
||||
import org.springframework.cache.jcache.JCacheCacheManager;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.ConditionContext;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.type.AnnotatedTypeMetadata;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Cache configuration for JSR-107 compliant providers.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @author Madhura Bhave
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass({ Caching.class, JCacheCacheManager.class })
|
||||
@ConditionalOnMissingBean(org.springframework.cache.CacheManager.class)
|
||||
@Conditional({ CacheCondition.class, JCacheCacheConfiguration.JCacheAvailableCondition.class })
|
||||
@Import(HazelcastJCacheCustomizationConfiguration.class)
|
||||
class JCacheCacheConfiguration implements BeanClassLoaderAware {
|
||||
|
||||
private ClassLoader beanClassLoader;
|
||||
|
||||
@Override
|
||||
public void setBeanClassLoader(ClassLoader classLoader) {
|
||||
this.beanClassLoader = classLoader;
|
||||
}
|
||||
|
||||
@Bean
|
||||
JCacheCacheManager cacheManager(CacheManagerCustomizers customizers, CacheManager jCacheCacheManager) {
|
||||
JCacheCacheManager cacheManager = new JCacheCacheManager(jCacheCacheManager);
|
||||
return customizers.customize(cacheManager);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
CacheManager jCacheCacheManager(CacheProperties cacheProperties,
|
||||
ObjectProvider<javax.cache.configuration.Configuration<?, ?>> defaultCacheConfiguration,
|
||||
ObjectProvider<JCacheManagerCustomizer> cacheManagerCustomizers,
|
||||
ObjectProvider<JCachePropertiesCustomizer> cachePropertiesCustomizers) throws IOException {
|
||||
CacheManager jCacheCacheManager = createCacheManager(cacheProperties, cachePropertiesCustomizers);
|
||||
List<String> cacheNames = cacheProperties.getCacheNames();
|
||||
if (!CollectionUtils.isEmpty(cacheNames)) {
|
||||
for (String cacheName : cacheNames) {
|
||||
jCacheCacheManager.createCache(cacheName,
|
||||
defaultCacheConfiguration.getIfAvailable(MutableConfiguration::new));
|
||||
}
|
||||
}
|
||||
cacheManagerCustomizers.orderedStream().forEach((customizer) -> customizer.customize(jCacheCacheManager));
|
||||
return jCacheCacheManager;
|
||||
}
|
||||
|
||||
private CacheManager createCacheManager(CacheProperties cacheProperties,
|
||||
ObjectProvider<JCachePropertiesCustomizer> cachePropertiesCustomizers) throws IOException {
|
||||
CachingProvider cachingProvider = getCachingProvider(cacheProperties.getJcache().getProvider());
|
||||
Properties properties = createCacheManagerProperties(cachePropertiesCustomizers);
|
||||
Resource configLocation = cacheProperties.resolveConfigLocation(cacheProperties.getJcache().getConfig());
|
||||
if (configLocation != null) {
|
||||
return cachingProvider.getCacheManager(configLocation.getURI(), this.beanClassLoader, properties);
|
||||
}
|
||||
return cachingProvider.getCacheManager(null, this.beanClassLoader, properties);
|
||||
}
|
||||
|
||||
private CachingProvider getCachingProvider(String cachingProviderFqn) {
|
||||
if (StringUtils.hasText(cachingProviderFqn)) {
|
||||
return Caching.getCachingProvider(cachingProviderFqn);
|
||||
}
|
||||
return Caching.getCachingProvider();
|
||||
}
|
||||
|
||||
private Properties createCacheManagerProperties(
|
||||
ObjectProvider<JCachePropertiesCustomizer> cachePropertiesCustomizers) {
|
||||
Properties properties = new Properties();
|
||||
cachePropertiesCustomizers.orderedStream().forEach((customizer) -> customizer.customize(properties));
|
||||
return properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if JCache is available. This either kicks in if a provider is available
|
||||
* as defined per {@link JCacheProviderAvailableCondition} or if a
|
||||
* {@link CacheManager} has already been defined.
|
||||
*/
|
||||
@Order(Ordered.LOWEST_PRECEDENCE)
|
||||
static class JCacheAvailableCondition extends AnyNestedCondition {
|
||||
|
||||
JCacheAvailableCondition() {
|
||||
super(ConfigurationPhase.REGISTER_BEAN);
|
||||
}
|
||||
|
||||
@Conditional(JCacheProviderAvailableCondition.class)
|
||||
static class JCacheProvider {
|
||||
|
||||
}
|
||||
|
||||
@ConditionalOnSingleCandidate(CacheManager.class)
|
||||
static class CustomJCacheCacheManager {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if a JCache provider is available. This either kicks in if a default
|
||||
* {@link CachingProvider} has been found or if the property referring to the provider
|
||||
* to use has been set.
|
||||
*/
|
||||
@Order(Ordered.LOWEST_PRECEDENCE)
|
||||
static class JCacheProviderAvailableCondition extends SpringBootCondition {
|
||||
|
||||
@Override
|
||||
public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
|
||||
ConditionMessage.Builder message = ConditionMessage.forCondition("JCache");
|
||||
String providerProperty = "spring.cache.jcache.provider";
|
||||
if (context.getEnvironment().containsProperty(providerProperty)) {
|
||||
return ConditionOutcome.match(message.because("JCache provider specified"));
|
||||
}
|
||||
Iterator<CachingProvider> providers = Caching.getCachingProviders().iterator();
|
||||
if (!providers.hasNext()) {
|
||||
return ConditionOutcome.noMatch(message.didNotFind("JSR-107 provider").atAll());
|
||||
}
|
||||
providers.next();
|
||||
if (providers.hasNext()) {
|
||||
return ConditionOutcome.noMatch(message.foundExactly("multiple JSR-107 providers"));
|
||||
}
|
||||
return ConditionOutcome.match(message.foundExactly("single JSR-107 provider"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2019 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.cache;
|
||||
|
||||
import javax.cache.CacheManager;
|
||||
|
||||
/**
|
||||
* Callback interface that can be implemented by beans wishing to customize the cache
|
||||
* manager before it is used, in particular to create additional caches.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @since 1.3.0
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface JCacheManagerCustomizer {
|
||||
|
||||
/**
|
||||
* Customize the cache manager.
|
||||
* @param cacheManager the {@code javax.cache.CacheManager} to customize
|
||||
*/
|
||||
void customize(CacheManager cacheManager);
|
||||
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2024 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.cache;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import javax.cache.CacheManager;
|
||||
import javax.cache.spi.CachingProvider;
|
||||
|
||||
/**
|
||||
* Callback interface that can be implemented by beans wishing to customize the properties
|
||||
* used by the {@link CachingProvider} to create the {@link CacheManager}.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @since 3.4.0
|
||||
* @see CachingProvider#getCacheManager(java.net.URI, ClassLoader, Properties)
|
||||
*/
|
||||
public interface JCachePropertiesCustomizer {
|
||||
|
||||
/**
|
||||
* Customize the properties.
|
||||
* @param properties the current properties
|
||||
*/
|
||||
void customize(Properties properties);
|
||||
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2023 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.cache;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.cache.support.NoOpCacheManager;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* No-op cache configuration used to disable caching through configuration.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnMissingBean(CacheManager.class)
|
||||
@Conditional(CacheCondition.class)
|
||||
class NoOpCacheConfiguration {
|
||||
|
||||
@Bean
|
||||
NoOpCacheManager cacheManager() {
|
||||
return new NoOpCacheManager();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,103 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2023 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.cache;
|
||||
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.cache.CacheProperties.Redis;
|
||||
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.data.redis.RedisAutoConfiguration;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.data.redis.cache.RedisCacheManager;
|
||||
import org.springframework.data.redis.cache.RedisCacheManager.RedisCacheManagerBuilder;
|
||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||
import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
|
||||
import org.springframework.data.redis.serializer.RedisSerializationContext.SerializationPair;
|
||||
|
||||
/**
|
||||
* Redis cache configuration.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @author Mark Paluch
|
||||
* @author Ryon Day
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass(RedisConnectionFactory.class)
|
||||
@AutoConfigureAfter(RedisAutoConfiguration.class)
|
||||
@ConditionalOnBean(RedisConnectionFactory.class)
|
||||
@ConditionalOnMissingBean(CacheManager.class)
|
||||
@Conditional(CacheCondition.class)
|
||||
class RedisCacheConfiguration {
|
||||
|
||||
@Bean
|
||||
RedisCacheManager cacheManager(CacheProperties cacheProperties, CacheManagerCustomizers cacheManagerCustomizers,
|
||||
ObjectProvider<org.springframework.data.redis.cache.RedisCacheConfiguration> redisCacheConfiguration,
|
||||
ObjectProvider<RedisCacheManagerBuilderCustomizer> redisCacheManagerBuilderCustomizers,
|
||||
RedisConnectionFactory redisConnectionFactory, ResourceLoader resourceLoader) {
|
||||
RedisCacheManagerBuilder builder = RedisCacheManager.builder(redisConnectionFactory)
|
||||
.cacheDefaults(
|
||||
determineConfiguration(cacheProperties, redisCacheConfiguration, resourceLoader.getClassLoader()));
|
||||
List<String> cacheNames = cacheProperties.getCacheNames();
|
||||
if (!cacheNames.isEmpty()) {
|
||||
builder.initialCacheNames(new LinkedHashSet<>(cacheNames));
|
||||
}
|
||||
if (cacheProperties.getRedis().isEnableStatistics()) {
|
||||
builder.enableStatistics();
|
||||
}
|
||||
redisCacheManagerBuilderCustomizers.orderedStream().forEach((customizer) -> customizer.customize(builder));
|
||||
return cacheManagerCustomizers.customize(builder.build());
|
||||
}
|
||||
|
||||
private org.springframework.data.redis.cache.RedisCacheConfiguration determineConfiguration(
|
||||
CacheProperties cacheProperties,
|
||||
ObjectProvider<org.springframework.data.redis.cache.RedisCacheConfiguration> redisCacheConfiguration,
|
||||
ClassLoader classLoader) {
|
||||
return redisCacheConfiguration.getIfAvailable(() -> createConfiguration(cacheProperties, classLoader));
|
||||
}
|
||||
|
||||
private org.springframework.data.redis.cache.RedisCacheConfiguration createConfiguration(
|
||||
CacheProperties cacheProperties, ClassLoader classLoader) {
|
||||
Redis redisProperties = cacheProperties.getRedis();
|
||||
org.springframework.data.redis.cache.RedisCacheConfiguration config = org.springframework.data.redis.cache.RedisCacheConfiguration
|
||||
.defaultCacheConfig();
|
||||
config = config
|
||||
.serializeValuesWith(SerializationPair.fromSerializer(new JdkSerializationRedisSerializer(classLoader)));
|
||||
if (redisProperties.getTimeToLive() != null) {
|
||||
config = config.entryTtl(redisProperties.getTimeToLive());
|
||||
}
|
||||
if (redisProperties.getKeyPrefix() != null) {
|
||||
config = config.prefixCacheNameWith(redisProperties.getKeyPrefix());
|
||||
}
|
||||
if (!redisProperties.isCacheNullValues()) {
|
||||
config = config.disableCachingNullValues();
|
||||
}
|
||||
if (!redisProperties.isUseKeyPrefix()) {
|
||||
config = config.disableKeyPrefix();
|
||||
}
|
||||
return config;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2019 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.cache;
|
||||
|
||||
import org.springframework.data.redis.cache.RedisCacheManager.RedisCacheManagerBuilder;
|
||||
|
||||
/**
|
||||
* Callback interface that can be used to customize a {@link RedisCacheManagerBuilder}.
|
||||
*
|
||||
* @author Dmytro Nosan
|
||||
* @since 2.2.0
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface RedisCacheManagerBuilderCustomizer {
|
||||
|
||||
/**
|
||||
* Customize the {@link RedisCacheManagerBuilder}.
|
||||
* @param builder the builder to customize
|
||||
*/
|
||||
void customize(RedisCacheManagerBuilder builder);
|
||||
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2019 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.cache;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.cache.concurrent.ConcurrentMapCacheManager;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* Simplest cache configuration, usually used as a fallback.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnMissingBean(CacheManager.class)
|
||||
@Conditional(CacheCondition.class)
|
||||
class SimpleCacheConfiguration {
|
||||
|
||||
@Bean
|
||||
ConcurrentMapCacheManager cacheManager(CacheProperties cacheProperties,
|
||||
CacheManagerCustomizers cacheManagerCustomizers) {
|
||||
ConcurrentMapCacheManager cacheManager = new ConcurrentMapCacheManager();
|
||||
List<String> cacheNames = cacheProperties.getCacheNames();
|
||||
if (!cacheNames.isEmpty()) {
|
||||
cacheManager.setCacheNames(cacheNames);
|
||||
}
|
||||
return cacheManagerCustomizers.customize(cacheManager);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2019 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Auto-configuration for the cache abstraction.
|
||||
*/
|
||||
package org.springframework.boot.autoconfigure.cache;
|
||||
@@ -1,367 +0,0 @@
|
||||
/*
|
||||
* 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.cassandra;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.time.Duration;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.datastax.oss.driver.api.core.CqlSession;
|
||||
import com.datastax.oss.driver.api.core.CqlSessionBuilder;
|
||||
import com.datastax.oss.driver.api.core.config.DefaultDriverOption;
|
||||
import com.datastax.oss.driver.api.core.config.DriverConfigLoader;
|
||||
import com.datastax.oss.driver.api.core.config.DriverOption;
|
||||
import com.datastax.oss.driver.api.core.config.ProgrammaticDriverConfigLoaderBuilder;
|
||||
import com.datastax.oss.driver.api.core.ssl.ProgrammaticSslEngineFactory;
|
||||
import com.datastax.oss.driver.internal.core.config.typesafe.DefaultDriverConfigLoader;
|
||||
import com.datastax.oss.driver.internal.core.config.typesafe.DefaultProgrammaticDriverConfigLoaderBuilder;
|
||||
import com.typesafe.config.Config;
|
||||
import com.typesafe.config.ConfigFactory;
|
||||
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.cassandra.CassandraProperties.Connection;
|
||||
import org.springframework.boot.autoconfigure.cassandra.CassandraProperties.Controlconnection;
|
||||
import org.springframework.boot.autoconfigure.cassandra.CassandraProperties.Request;
|
||||
import org.springframework.boot.autoconfigure.cassandra.CassandraProperties.Ssl;
|
||||
import org.springframework.boot.autoconfigure.cassandra.CassandraProperties.Throttler;
|
||||
import org.springframework.boot.autoconfigure.cassandra.CassandraProperties.ThrottlerType;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.boot.context.properties.PropertyMapper;
|
||||
import org.springframework.boot.ssl.SslBundle;
|
||||
import org.springframework.boot.ssl.SslBundles;
|
||||
import org.springframework.boot.ssl.SslOptions;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* {@link EnableAutoConfiguration Auto-configuration} for Cassandra.
|
||||
*
|
||||
* @author Julien Dubois
|
||||
* @author Phillip Webb
|
||||
* @author Eddú Meléndez
|
||||
* @author Stephane Nicoll
|
||||
* @author Steffen F. Qvistgaard
|
||||
* @author Ittay Stern
|
||||
* @author Moritz Halbritter
|
||||
* @author Andy Wilkinson
|
||||
* @author Phillip Webb
|
||||
* @author Scott Frederick
|
||||
* @since 1.3.0
|
||||
*/
|
||||
@AutoConfiguration
|
||||
@ConditionalOnClass(CqlSession.class)
|
||||
@EnableConfigurationProperties(CassandraProperties.class)
|
||||
public class CassandraAutoConfiguration {
|
||||
|
||||
private static final Config SPRING_BOOT_DEFAULTS;
|
||||
static {
|
||||
CassandraDriverOptions options = new CassandraDriverOptions();
|
||||
options.add(DefaultDriverOption.CONTACT_POINTS, Collections.singletonList("127.0.0.1:9042"));
|
||||
options.add(DefaultDriverOption.PROTOCOL_COMPRESSION, "none");
|
||||
options.add(DefaultDriverOption.CONTROL_CONNECTION_TIMEOUT, (int) Duration.ofSeconds(5).toMillis());
|
||||
SPRING_BOOT_DEFAULTS = options.build();
|
||||
}
|
||||
|
||||
private final CassandraProperties properties;
|
||||
|
||||
CassandraAutoConfiguration(CassandraProperties properties) {
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(CassandraConnectionDetails.class)
|
||||
PropertiesCassandraConnectionDetails cassandraConnectionDetails(ObjectProvider<SslBundles> sslBundles) {
|
||||
return new PropertiesCassandraConnectionDetails(this.properties, sslBundles.getIfAvailable());
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
@Lazy
|
||||
public CqlSession cassandraSession(CqlSessionBuilder cqlSessionBuilder) {
|
||||
return cqlSessionBuilder.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
|
||||
public CqlSessionBuilder cassandraSessionBuilder(DriverConfigLoader driverConfigLoader,
|
||||
CassandraConnectionDetails connectionDetails,
|
||||
ObjectProvider<CqlSessionBuilderCustomizer> builderCustomizers) {
|
||||
CqlSessionBuilder builder = CqlSession.builder().withConfigLoader(driverConfigLoader);
|
||||
configureAuthentication(builder, connectionDetails);
|
||||
configureSsl(builder, connectionDetails);
|
||||
builder.withKeyspace(this.properties.getKeyspaceName());
|
||||
builderCustomizers.orderedStream().forEach((customizer) -> customizer.customize(builder));
|
||||
return builder;
|
||||
}
|
||||
|
||||
private void configureAuthentication(CqlSessionBuilder builder, CassandraConnectionDetails connectionDetails) {
|
||||
String username = connectionDetails.getUsername();
|
||||
if (username != null) {
|
||||
builder.withAuthCredentials(username, connectionDetails.getPassword());
|
||||
}
|
||||
}
|
||||
|
||||
private void configureSsl(CqlSessionBuilder builder, CassandraConnectionDetails connectionDetails) {
|
||||
SslBundle sslBundle = connectionDetails.getSslBundle();
|
||||
if (sslBundle == null) {
|
||||
return;
|
||||
}
|
||||
SslOptions options = sslBundle.getOptions();
|
||||
Assert.state(options.getEnabledProtocols() == null, "SSL protocol options cannot be specified with Cassandra");
|
||||
builder
|
||||
.withSslEngineFactory(new ProgrammaticSslEngineFactory(sslBundle.createSslContext(), options.getCiphers()));
|
||||
}
|
||||
|
||||
@Bean(destroyMethod = "")
|
||||
@ConditionalOnMissingBean
|
||||
public DriverConfigLoader cassandraDriverConfigLoader(CassandraConnectionDetails connectionDetails,
|
||||
ObjectProvider<DriverConfigLoaderBuilderCustomizer> builderCustomizers) {
|
||||
ProgrammaticDriverConfigLoaderBuilder builder = new DefaultProgrammaticDriverConfigLoaderBuilder(
|
||||
() -> cassandraConfiguration(connectionDetails), DefaultDriverConfigLoader.DEFAULT_ROOT_PATH);
|
||||
builderCustomizers.orderedStream().forEach((customizer) -> customizer.customize(builder));
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
private Config cassandraConfiguration(CassandraConnectionDetails connectionDetails) {
|
||||
ConfigFactory.invalidateCaches();
|
||||
Config config = ConfigFactory.defaultOverrides();
|
||||
config = config.withFallback(mapConfig(connectionDetails));
|
||||
if (this.properties.getConfig() != null) {
|
||||
config = config.withFallback(loadConfig(this.properties.getConfig()));
|
||||
}
|
||||
config = config.withFallback(SPRING_BOOT_DEFAULTS);
|
||||
config = config.withFallback(ConfigFactory.defaultReferenceUnresolved());
|
||||
return config.resolve();
|
||||
}
|
||||
|
||||
private Config loadConfig(Resource resource) {
|
||||
try {
|
||||
return ConfigFactory.parseURL(resource.getURL());
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw new IllegalStateException("Failed to load cassandra configuration from " + resource, ex);
|
||||
}
|
||||
}
|
||||
|
||||
private Config mapConfig(CassandraConnectionDetails connectionDetails) {
|
||||
CassandraDriverOptions options = new CassandraDriverOptions();
|
||||
PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull();
|
||||
map.from(this.properties.getSessionName())
|
||||
.whenHasText()
|
||||
.to((sessionName) -> options.add(DefaultDriverOption.SESSION_NAME, sessionName));
|
||||
map.from(connectionDetails.getUsername())
|
||||
.to((value) -> options.add(DefaultDriverOption.AUTH_PROVIDER_USER_NAME, value)
|
||||
.add(DefaultDriverOption.AUTH_PROVIDER_PASSWORD, connectionDetails.getPassword()));
|
||||
map.from(this.properties::getCompression)
|
||||
.to((compression) -> options.add(DefaultDriverOption.PROTOCOL_COMPRESSION, compression));
|
||||
mapConnectionOptions(options);
|
||||
mapPoolingOptions(options);
|
||||
mapRequestOptions(options);
|
||||
mapControlConnectionOptions(options);
|
||||
map.from(mapContactPoints(connectionDetails))
|
||||
.to((contactPoints) -> options.add(DefaultDriverOption.CONTACT_POINTS, contactPoints));
|
||||
map.from(connectionDetails.getLocalDatacenter())
|
||||
.whenHasText()
|
||||
.to((localDatacenter) -> options.add(DefaultDriverOption.LOAD_BALANCING_LOCAL_DATACENTER, localDatacenter));
|
||||
return options.build();
|
||||
}
|
||||
|
||||
private void mapConnectionOptions(CassandraDriverOptions options) {
|
||||
PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull();
|
||||
Connection connectionProperties = this.properties.getConnection();
|
||||
map.from(connectionProperties::getConnectTimeout)
|
||||
.asInt(Duration::toMillis)
|
||||
.to((connectTimeout) -> options.add(DefaultDriverOption.CONNECTION_CONNECT_TIMEOUT, connectTimeout));
|
||||
map.from(connectionProperties::getInitQueryTimeout)
|
||||
.asInt(Duration::toMillis)
|
||||
.to((initQueryTimeout) -> options.add(DefaultDriverOption.CONNECTION_INIT_QUERY_TIMEOUT, initQueryTimeout));
|
||||
}
|
||||
|
||||
private void mapPoolingOptions(CassandraDriverOptions options) {
|
||||
PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull();
|
||||
CassandraProperties.Pool poolProperties = this.properties.getPool();
|
||||
map.from(poolProperties::getIdleTimeout)
|
||||
.asInt(Duration::toMillis)
|
||||
.to((idleTimeout) -> options.add(DefaultDriverOption.HEARTBEAT_TIMEOUT, idleTimeout));
|
||||
map.from(poolProperties::getHeartbeatInterval)
|
||||
.asInt(Duration::toMillis)
|
||||
.to((heartBeatInterval) -> options.add(DefaultDriverOption.HEARTBEAT_INTERVAL, heartBeatInterval));
|
||||
}
|
||||
|
||||
private void mapRequestOptions(CassandraDriverOptions options) {
|
||||
PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull();
|
||||
Request requestProperties = this.properties.getRequest();
|
||||
map.from(requestProperties::getTimeout)
|
||||
.asInt(Duration::toMillis)
|
||||
.to(((timeout) -> options.add(DefaultDriverOption.REQUEST_TIMEOUT, timeout)));
|
||||
map.from(requestProperties::getConsistency)
|
||||
.to(((consistency) -> options.add(DefaultDriverOption.REQUEST_CONSISTENCY, consistency)));
|
||||
map.from(requestProperties::getSerialConsistency)
|
||||
.to((serialConsistency) -> options.add(DefaultDriverOption.REQUEST_SERIAL_CONSISTENCY, serialConsistency));
|
||||
map.from(requestProperties::getPageSize)
|
||||
.to((pageSize) -> options.add(DefaultDriverOption.REQUEST_PAGE_SIZE, pageSize));
|
||||
Throttler throttlerProperties = requestProperties.getThrottler();
|
||||
map.from(throttlerProperties::getType)
|
||||
.as(ThrottlerType::type)
|
||||
.to((type) -> options.add(DefaultDriverOption.REQUEST_THROTTLER_CLASS, type));
|
||||
map.from(throttlerProperties::getMaxQueueSize)
|
||||
.to((maxQueueSize) -> options.add(DefaultDriverOption.REQUEST_THROTTLER_MAX_QUEUE_SIZE, maxQueueSize));
|
||||
map.from(throttlerProperties::getMaxConcurrentRequests)
|
||||
.to((maxConcurrentRequests) -> options.add(DefaultDriverOption.REQUEST_THROTTLER_MAX_CONCURRENT_REQUESTS,
|
||||
maxConcurrentRequests));
|
||||
map.from(throttlerProperties::getMaxRequestsPerSecond)
|
||||
.to((maxRequestsPerSecond) -> options.add(DefaultDriverOption.REQUEST_THROTTLER_MAX_REQUESTS_PER_SECOND,
|
||||
maxRequestsPerSecond));
|
||||
map.from(throttlerProperties::getDrainInterval)
|
||||
.asInt(Duration::toMillis)
|
||||
.to((drainInterval) -> options.add(DefaultDriverOption.REQUEST_THROTTLER_DRAIN_INTERVAL, drainInterval));
|
||||
}
|
||||
|
||||
private void mapControlConnectionOptions(CassandraDriverOptions options) {
|
||||
PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull();
|
||||
Controlconnection controlProperties = this.properties.getControlconnection();
|
||||
map.from(controlProperties::getTimeout)
|
||||
.asInt(Duration::toMillis)
|
||||
.to((timeout) -> options.add(DefaultDriverOption.CONTROL_CONNECTION_TIMEOUT, timeout));
|
||||
}
|
||||
|
||||
private List<String> mapContactPoints(CassandraConnectionDetails connectionDetails) {
|
||||
return connectionDetails.getContactPoints().stream().map((node) -> node.host() + ":" + node.port()).toList();
|
||||
}
|
||||
|
||||
private static final class CassandraDriverOptions {
|
||||
|
||||
private final Map<String, String> options = new LinkedHashMap<>();
|
||||
|
||||
private CassandraDriverOptions add(DriverOption option, String value) {
|
||||
String key = createKeyFor(option);
|
||||
this.options.put(key, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
private CassandraDriverOptions add(DriverOption option, int value) {
|
||||
return add(option, String.valueOf(value));
|
||||
}
|
||||
|
||||
private CassandraDriverOptions add(DriverOption option, Enum<?> value) {
|
||||
return add(option, value.name());
|
||||
}
|
||||
|
||||
private CassandraDriverOptions add(DriverOption option, List<String> values) {
|
||||
for (int i = 0; i < values.size(); i++) {
|
||||
this.options.put(String.format("%s.%s", createKeyFor(option), i), values.get(i));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
private Config build() {
|
||||
return ConfigFactory.parseMap(this.options, "Environment");
|
||||
}
|
||||
|
||||
private static String createKeyFor(DriverOption option) {
|
||||
return String.format("%s.%s", DefaultDriverConfigLoader.DEFAULT_ROOT_PATH, option.getPath());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Adapts {@link CassandraProperties} to {@link CassandraConnectionDetails}.
|
||||
*/
|
||||
static final class PropertiesCassandraConnectionDetails implements CassandraConnectionDetails {
|
||||
|
||||
private final CassandraProperties properties;
|
||||
|
||||
private final SslBundles sslBundles;
|
||||
|
||||
private PropertiesCassandraConnectionDetails(CassandraProperties properties, SslBundles sslBundles) {
|
||||
this.properties = properties;
|
||||
this.sslBundles = sslBundles;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Node> getContactPoints() {
|
||||
List<String> contactPoints = this.properties.getContactPoints();
|
||||
return (contactPoints != null) ? contactPoints.stream().map(this::asNode).toList()
|
||||
: Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUsername() {
|
||||
return this.properties.getUsername();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPassword() {
|
||||
return this.properties.getPassword();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLocalDatacenter() {
|
||||
return this.properties.getLocalDatacenter();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SslBundle getSslBundle() {
|
||||
Ssl ssl = this.properties.getSsl();
|
||||
if (ssl == null || !ssl.isEnabled()) {
|
||||
return null;
|
||||
}
|
||||
if (StringUtils.hasLength(ssl.getBundle())) {
|
||||
Assert.notNull(this.sslBundles, "SSL bundle name has been set but no SSL bundles found in context");
|
||||
return this.sslBundles.getBundle(ssl.getBundle());
|
||||
}
|
||||
return SslBundle.systemDefault();
|
||||
}
|
||||
|
||||
private Node asNode(String contactPoint) {
|
||||
int i = contactPoint.lastIndexOf(':');
|
||||
if (i >= 0) {
|
||||
String portCandidate = contactPoint.substring(i + 1);
|
||||
Integer port = asPort(portCandidate);
|
||||
if (port != null) {
|
||||
return new Node(contactPoint.substring(0, i), port);
|
||||
}
|
||||
}
|
||||
return new Node(contactPoint, this.properties.getPort());
|
||||
}
|
||||
|
||||
private Integer asPort(String value) {
|
||||
try {
|
||||
int i = Integer.parseInt(value);
|
||||
return (i > 0 && i < 65535) ? i : null;
|
||||
}
|
||||
catch (Exception ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,81 +0,0 @@
|
||||
/*
|
||||
* 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.cassandra;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.boot.autoconfigure.service.connection.ConnectionDetails;
|
||||
import org.springframework.boot.ssl.SslBundle;
|
||||
|
||||
/**
|
||||
* Details required to establish a connection to a Cassandra service.
|
||||
*
|
||||
* @author Moritz Halbritter
|
||||
* @author Andy Wilkinson
|
||||
* @author Phillip Webb
|
||||
* @since 3.1.0
|
||||
*/
|
||||
public interface CassandraConnectionDetails extends ConnectionDetails {
|
||||
|
||||
/**
|
||||
* Cluster node addresses.
|
||||
* @return the cluster node addresses
|
||||
*/
|
||||
List<Node> getContactPoints();
|
||||
|
||||
/**
|
||||
* Login user of the server.
|
||||
* @return the login user of the server or {@code null}
|
||||
*/
|
||||
default String getUsername() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Login password of the server.
|
||||
* @return the login password of the server or {@code null}
|
||||
*/
|
||||
default String getPassword() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Datacenter that is considered "local". Contact points should be from this
|
||||
* datacenter.
|
||||
* @return the datacenter that is considered "local"
|
||||
*/
|
||||
String getLocalDatacenter();
|
||||
|
||||
/**
|
||||
* SSL bundle to use.
|
||||
* @return the SSL bundle to use
|
||||
* @since 3.5.0
|
||||
*/
|
||||
default SslBundle getSslBundle() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* A Cassandra node.
|
||||
*
|
||||
* @param host the hostname
|
||||
* @param port the port
|
||||
*/
|
||||
record Node(String host, int port) {
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,518 +0,0 @@
|
||||
/*
|
||||
* 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.cassandra;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.List;
|
||||
|
||||
import com.datastax.oss.driver.api.core.DefaultConsistencyLevel;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.core.io.Resource;
|
||||
|
||||
/**
|
||||
* Configuration properties for Cassandra.
|
||||
*
|
||||
* @author Julien Dubois
|
||||
* @author Phillip Webb
|
||||
* @author Mark Paluch
|
||||
* @author Stephane Nicoll
|
||||
* @author Scott Frederick
|
||||
* @since 1.3.0
|
||||
*/
|
||||
@ConfigurationProperties("spring.cassandra")
|
||||
public class CassandraProperties {
|
||||
|
||||
/**
|
||||
* Location of the configuration file to use.
|
||||
*/
|
||||
private Resource config;
|
||||
|
||||
/**
|
||||
* Keyspace name to use.
|
||||
*/
|
||||
private String keyspaceName;
|
||||
|
||||
/**
|
||||
* Name of the Cassandra session.
|
||||
*/
|
||||
private String sessionName;
|
||||
|
||||
/**
|
||||
* Cluster node addresses in the form 'host:port', or a simple 'host' to use the
|
||||
* configured port.
|
||||
*/
|
||||
private List<String> contactPoints;
|
||||
|
||||
/**
|
||||
* Port to use if a contact point does not specify one.
|
||||
*/
|
||||
private int port = 9042;
|
||||
|
||||
/**
|
||||
* Datacenter that is considered "local". Contact points should be from this
|
||||
* datacenter.
|
||||
*/
|
||||
private String localDatacenter;
|
||||
|
||||
/**
|
||||
* Login user of the server.
|
||||
*/
|
||||
private String username;
|
||||
|
||||
/**
|
||||
* Login password of the server.
|
||||
*/
|
||||
private String password;
|
||||
|
||||
/**
|
||||
* Compression supported by the Cassandra binary protocol.
|
||||
*/
|
||||
private Compression compression;
|
||||
|
||||
/**
|
||||
* Schema action to take at startup.
|
||||
*/
|
||||
private String schemaAction = "none";
|
||||
|
||||
/**
|
||||
* SSL configuration.
|
||||
*/
|
||||
private Ssl ssl = new Ssl();
|
||||
|
||||
/**
|
||||
* Connection configuration.
|
||||
*/
|
||||
private final Connection connection = new Connection();
|
||||
|
||||
/**
|
||||
* Pool configuration.
|
||||
*/
|
||||
private final Pool pool = new Pool();
|
||||
|
||||
/**
|
||||
* Request configuration.
|
||||
*/
|
||||
private final Request request = new Request();
|
||||
|
||||
/**
|
||||
* Control connection configuration.
|
||||
*/
|
||||
private final Controlconnection controlconnection = new Controlconnection();
|
||||
|
||||
public Resource getConfig() {
|
||||
return this.config;
|
||||
}
|
||||
|
||||
public void setConfig(Resource config) {
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
public String getKeyspaceName() {
|
||||
return this.keyspaceName;
|
||||
}
|
||||
|
||||
public void setKeyspaceName(String keyspaceName) {
|
||||
this.keyspaceName = keyspaceName;
|
||||
}
|
||||
|
||||
public String getSessionName() {
|
||||
return this.sessionName;
|
||||
}
|
||||
|
||||
public void setSessionName(String sessionName) {
|
||||
this.sessionName = sessionName;
|
||||
}
|
||||
|
||||
public List<String> getContactPoints() {
|
||||
return this.contactPoints;
|
||||
}
|
||||
|
||||
public void setContactPoints(List<String> contactPoints) {
|
||||
this.contactPoints = contactPoints;
|
||||
}
|
||||
|
||||
public int getPort() {
|
||||
return this.port;
|
||||
}
|
||||
|
||||
public void setPort(int port) {
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
public String getLocalDatacenter() {
|
||||
return this.localDatacenter;
|
||||
}
|
||||
|
||||
public void setLocalDatacenter(String localDatacenter) {
|
||||
this.localDatacenter = localDatacenter;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return this.username;
|
||||
}
|
||||
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return this.password;
|
||||
}
|
||||
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public Compression getCompression() {
|
||||
return this.compression;
|
||||
}
|
||||
|
||||
public void setCompression(Compression compression) {
|
||||
this.compression = compression;
|
||||
}
|
||||
|
||||
public Ssl getSsl() {
|
||||
return this.ssl;
|
||||
}
|
||||
|
||||
public void setSsl(Ssl ssl) {
|
||||
this.ssl = ssl;
|
||||
}
|
||||
|
||||
public String getSchemaAction() {
|
||||
return this.schemaAction;
|
||||
}
|
||||
|
||||
public void setSchemaAction(String schemaAction) {
|
||||
this.schemaAction = schemaAction;
|
||||
}
|
||||
|
||||
public Connection getConnection() {
|
||||
return this.connection;
|
||||
}
|
||||
|
||||
public Pool getPool() {
|
||||
return this.pool;
|
||||
}
|
||||
|
||||
public Request getRequest() {
|
||||
return this.request;
|
||||
}
|
||||
|
||||
public Controlconnection getControlconnection() {
|
||||
return this.controlconnection;
|
||||
}
|
||||
|
||||
public static class Ssl {
|
||||
|
||||
/**
|
||||
* Whether to enable SSL support.
|
||||
*/
|
||||
private Boolean enabled;
|
||||
|
||||
/**
|
||||
* SSL bundle name.
|
||||
*/
|
||||
private String bundle;
|
||||
|
||||
public boolean isEnabled() {
|
||||
return (this.enabled != null) ? this.enabled : this.bundle != null;
|
||||
}
|
||||
|
||||
public void setEnabled(boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
public String getBundle() {
|
||||
return this.bundle;
|
||||
}
|
||||
|
||||
public void setBundle(String bundle) {
|
||||
this.bundle = bundle;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class Connection {
|
||||
|
||||
/**
|
||||
* Timeout to use when establishing driver connections.
|
||||
*/
|
||||
private Duration connectTimeout;
|
||||
|
||||
/**
|
||||
* Timeout to use for internal queries that run as part of the initialization
|
||||
* process, just after a connection is opened.
|
||||
*/
|
||||
private Duration initQueryTimeout;
|
||||
|
||||
public Duration getConnectTimeout() {
|
||||
return this.connectTimeout;
|
||||
}
|
||||
|
||||
public void setConnectTimeout(Duration connectTimeout) {
|
||||
this.connectTimeout = connectTimeout;
|
||||
}
|
||||
|
||||
public Duration getInitQueryTimeout() {
|
||||
return this.initQueryTimeout;
|
||||
}
|
||||
|
||||
public void setInitQueryTimeout(Duration initQueryTimeout) {
|
||||
this.initQueryTimeout = initQueryTimeout;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class Request {
|
||||
|
||||
/**
|
||||
* How long the driver waits for a request to complete.
|
||||
*/
|
||||
private Duration timeout;
|
||||
|
||||
/**
|
||||
* Queries consistency level.
|
||||
*/
|
||||
private DefaultConsistencyLevel consistency;
|
||||
|
||||
/**
|
||||
* Queries serial consistency level.
|
||||
*/
|
||||
private DefaultConsistencyLevel serialConsistency;
|
||||
|
||||
/**
|
||||
* How many rows will be retrieved simultaneously in a single network round-trip.
|
||||
*/
|
||||
private Integer pageSize;
|
||||
|
||||
private final Throttler throttler = new Throttler();
|
||||
|
||||
public Duration getTimeout() {
|
||||
return this.timeout;
|
||||
}
|
||||
|
||||
public void setTimeout(Duration timeout) {
|
||||
this.timeout = timeout;
|
||||
}
|
||||
|
||||
public DefaultConsistencyLevel getConsistency() {
|
||||
return this.consistency;
|
||||
}
|
||||
|
||||
public void setConsistency(DefaultConsistencyLevel consistency) {
|
||||
this.consistency = consistency;
|
||||
}
|
||||
|
||||
public DefaultConsistencyLevel getSerialConsistency() {
|
||||
return this.serialConsistency;
|
||||
}
|
||||
|
||||
public void setSerialConsistency(DefaultConsistencyLevel serialConsistency) {
|
||||
this.serialConsistency = serialConsistency;
|
||||
}
|
||||
|
||||
public Integer getPageSize() {
|
||||
return this.pageSize;
|
||||
}
|
||||
|
||||
public void setPageSize(int pageSize) {
|
||||
this.pageSize = pageSize;
|
||||
}
|
||||
|
||||
public Throttler getThrottler() {
|
||||
return this.throttler;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Pool properties.
|
||||
*/
|
||||
public static class Pool {
|
||||
|
||||
/**
|
||||
* Idle timeout before an idle connection is removed.
|
||||
*/
|
||||
private Duration idleTimeout;
|
||||
|
||||
/**
|
||||
* Heartbeat interval after which a message is sent on an idle connection to make
|
||||
* sure it's still alive.
|
||||
*/
|
||||
private Duration heartbeatInterval;
|
||||
|
||||
public Duration getIdleTimeout() {
|
||||
return this.idleTimeout;
|
||||
}
|
||||
|
||||
public void setIdleTimeout(Duration idleTimeout) {
|
||||
this.idleTimeout = idleTimeout;
|
||||
}
|
||||
|
||||
public Duration getHeartbeatInterval() {
|
||||
return this.heartbeatInterval;
|
||||
}
|
||||
|
||||
public void setHeartbeatInterval(Duration heartbeatInterval) {
|
||||
this.heartbeatInterval = heartbeatInterval;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class Controlconnection {
|
||||
|
||||
/**
|
||||
* Timeout to use for control queries.
|
||||
*/
|
||||
private Duration timeout;
|
||||
|
||||
public Duration getTimeout() {
|
||||
return this.timeout;
|
||||
}
|
||||
|
||||
public void setTimeout(Duration timeout) {
|
||||
this.timeout = timeout;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class Throttler {
|
||||
|
||||
/**
|
||||
* Request throttling type.
|
||||
*/
|
||||
private ThrottlerType type;
|
||||
|
||||
/**
|
||||
* Maximum number of requests that can be enqueued when the throttling threshold
|
||||
* is exceeded.
|
||||
*/
|
||||
private Integer maxQueueSize;
|
||||
|
||||
/**
|
||||
* Maximum number of requests that are allowed to execute in parallel.
|
||||
*/
|
||||
private Integer maxConcurrentRequests;
|
||||
|
||||
/**
|
||||
* Maximum allowed request rate.
|
||||
*/
|
||||
private Integer maxRequestsPerSecond;
|
||||
|
||||
/**
|
||||
* How often the throttler attempts to dequeue requests. Set this high enough that
|
||||
* each attempt will process multiple entries in the queue, but not delay requests
|
||||
* too much.
|
||||
*/
|
||||
private Duration drainInterval;
|
||||
|
||||
public ThrottlerType getType() {
|
||||
return this.type;
|
||||
}
|
||||
|
||||
public void setType(ThrottlerType type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public Integer getMaxQueueSize() {
|
||||
return this.maxQueueSize;
|
||||
}
|
||||
|
||||
public void setMaxQueueSize(int maxQueueSize) {
|
||||
this.maxQueueSize = maxQueueSize;
|
||||
}
|
||||
|
||||
public Integer getMaxConcurrentRequests() {
|
||||
return this.maxConcurrentRequests;
|
||||
}
|
||||
|
||||
public void setMaxConcurrentRequests(int maxConcurrentRequests) {
|
||||
this.maxConcurrentRequests = maxConcurrentRequests;
|
||||
}
|
||||
|
||||
public Integer getMaxRequestsPerSecond() {
|
||||
return this.maxRequestsPerSecond;
|
||||
}
|
||||
|
||||
public void setMaxRequestsPerSecond(int maxRequestsPerSecond) {
|
||||
this.maxRequestsPerSecond = maxRequestsPerSecond;
|
||||
}
|
||||
|
||||
public Duration getDrainInterval() {
|
||||
return this.drainInterval;
|
||||
}
|
||||
|
||||
public void setDrainInterval(Duration drainInterval) {
|
||||
this.drainInterval = drainInterval;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Name of the algorithm used to compress protocol frames.
|
||||
*/
|
||||
public enum Compression {
|
||||
|
||||
/**
|
||||
* Requires 'net.jpountz.lz4:lz4'.
|
||||
*/
|
||||
LZ4,
|
||||
|
||||
/**
|
||||
* Requires org.xerial.snappy:snappy-java.
|
||||
*/
|
||||
SNAPPY,
|
||||
|
||||
/**
|
||||
* No compression.
|
||||
*/
|
||||
NONE
|
||||
|
||||
}
|
||||
|
||||
public enum ThrottlerType {
|
||||
|
||||
/**
|
||||
* Limit the number of requests that can be executed in parallel.
|
||||
*/
|
||||
CONCURRENCY_LIMITING("ConcurrencyLimitingRequestThrottler"),
|
||||
|
||||
/**
|
||||
* Limits the request rate per second.
|
||||
*/
|
||||
RATE_LIMITING("RateLimitingRequestThrottler"),
|
||||
|
||||
/**
|
||||
* No request throttling.
|
||||
*/
|
||||
NONE("PassThroughRequestThrottler");
|
||||
|
||||
private final String type;
|
||||
|
||||
ThrottlerType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public String type() {
|
||||
return this.type;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2023 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.cassandra;
|
||||
|
||||
import com.datastax.oss.driver.api.core.CqlSession;
|
||||
import com.datastax.oss.driver.api.core.CqlSessionBuilder;
|
||||
|
||||
/**
|
||||
* Callback interface that can be implemented by beans wishing to customize the
|
||||
* {@link CqlSession} through a {@link CqlSessionBuilder} whilst retaining default
|
||||
* auto-configuration.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @since 2.3.0
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface CqlSessionBuilderCustomizer {
|
||||
|
||||
/**
|
||||
* Customize the {@link CqlSessionBuilder}.
|
||||
* @param cqlSessionBuilder the builder to customize
|
||||
*/
|
||||
void customize(CqlSessionBuilder cqlSessionBuilder);
|
||||
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2023 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.cassandra;
|
||||
|
||||
import com.datastax.oss.driver.api.core.config.DriverConfigLoader;
|
||||
import com.datastax.oss.driver.api.core.config.ProgrammaticDriverConfigLoaderBuilder;
|
||||
|
||||
/**
|
||||
* Callback interface that can be implemented by beans wishing to customize the
|
||||
* {@link DriverConfigLoader} through a {@link DriverConfigLoaderBuilderCustomizer} whilst
|
||||
* retaining default auto-configuration.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @since 2.3.0
|
||||
*/
|
||||
public interface DriverConfigLoaderBuilderCustomizer {
|
||||
|
||||
/**
|
||||
* Customize the {@linkplain ProgrammaticDriverConfigLoaderBuilder DriverConfigLoader
|
||||
* builder}.
|
||||
* @param builder the builder to customize
|
||||
*/
|
||||
void customize(ProgrammaticDriverConfigLoaderBuilder builder);
|
||||
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2019 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Auto-configuration for Cassandra.
|
||||
*/
|
||||
package org.springframework.boot.autoconfigure.cassandra;
|
||||
@@ -1,66 +0,0 @@
|
||||
/*
|
||||
* 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.codec;
|
||||
|
||||
import org.springframework.boot.autoconfigure.http.codec.HttpCodecsProperties;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.boot.context.properties.DeprecatedConfigurationProperty;
|
||||
import org.springframework.util.unit.DataSize;
|
||||
|
||||
/**
|
||||
* {@link ConfigurationProperties Properties} for reactive codecs.
|
||||
*
|
||||
* @author Brian Clozel
|
||||
* @since 2.2.1
|
||||
* @deprecated since 3.5.0 for removal in 4.0.0 in favor of {@link HttpCodecsProperties}
|
||||
*/
|
||||
@ConfigurationProperties("spring.codec")
|
||||
@Deprecated(since = "3.5.0", forRemoval = true)
|
||||
public class CodecProperties {
|
||||
|
||||
/**
|
||||
* Whether to log form data at DEBUG level, and headers at TRACE level.
|
||||
*/
|
||||
private boolean logRequestDetails;
|
||||
|
||||
/**
|
||||
* Limit on the number of bytes that can be buffered whenever the input stream needs
|
||||
* to be aggregated. This applies only to the auto-configured WebFlux server and
|
||||
* WebClient instances. By default this is not set, in which case individual codec
|
||||
* defaults apply. Most codecs are limited to 256K by default.
|
||||
*/
|
||||
private DataSize maxInMemorySize;
|
||||
|
||||
@DeprecatedConfigurationProperty(since = "3.5.0", replacement = "spring.http.codecs.log-request-details")
|
||||
public boolean isLogRequestDetails() {
|
||||
return this.logRequestDetails;
|
||||
}
|
||||
|
||||
public void setLogRequestDetails(boolean logRequestDetails) {
|
||||
this.logRequestDetails = logRequestDetails;
|
||||
}
|
||||
|
||||
@DeprecatedConfigurationProperty(since = "3.5.0", replacement = "spring.http.codecs.max-in-memory-size")
|
||||
public DataSize getMaxInMemorySize() {
|
||||
return this.maxInMemorySize;
|
||||
}
|
||||
|
||||
public void setMaxInMemorySize(DataSize maxInMemorySize) {
|
||||
this.maxInMemorySize = maxInMemorySize;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2019 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Auto-configuration for reactive codecs.
|
||||
*/
|
||||
package org.springframework.boot.autoconfigure.codec;
|
||||
@@ -1,66 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2024 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.container;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.core.AttributeAccessor;
|
||||
|
||||
/**
|
||||
* Metadata about a container image that can be added to an {@link AttributeAccessor}.
|
||||
* Primarily designed to be attached to {@link BeanDefinition BeanDefinitions} created in
|
||||
* support of Testcontainers or Docker Compose.
|
||||
*
|
||||
* @param imageName the contaimer image name or {@code null} if the image name is not yet
|
||||
* known
|
||||
* @author Phillip Webb
|
||||
* @since 3.4.0
|
||||
*/
|
||||
public record ContainerImageMetadata(String imageName) {
|
||||
|
||||
static final String NAME = ContainerImageMetadata.class.getName();
|
||||
|
||||
/**
|
||||
* Add this container image metadata to the given attributes.
|
||||
* @param attributes the attributes to add the metadata to
|
||||
*/
|
||||
public void addTo(AttributeAccessor attributes) {
|
||||
if (attributes != null) {
|
||||
attributes.setAttribute(NAME, this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return {@code true} if {@link ContainerImageMetadata} has been added to the given
|
||||
* attributes.
|
||||
* @param attributes the attributes to check
|
||||
* @return if metadata is present
|
||||
*/
|
||||
public static boolean isPresent(AttributeAccessor attributes) {
|
||||
return getFrom(attributes) != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return {@link ContainerImageMetadata} from the given attributes or {@code null} if
|
||||
* no metadata has been added.
|
||||
* @param attributes the attributes
|
||||
* @return the metadata or {@code null}
|
||||
*/
|
||||
public static ContainerImageMetadata getFrom(AttributeAccessor attributes) {
|
||||
return (attributes != null) ? (ContainerImageMetadata) attributes.getAttribute(NAME) : null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2024 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Support classes related to auto-configuration involving containers.
|
||||
*/
|
||||
package org.springframework.boot.autoconfigure.container;
|
||||
@@ -1,39 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2023 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.couchbase;
|
||||
|
||||
import com.couchbase.client.java.env.ClusterEnvironment;
|
||||
import com.couchbase.client.java.env.ClusterEnvironment.Builder;
|
||||
|
||||
/**
|
||||
* Callback interface that can be implemented by beans wishing to customize the
|
||||
* {@link ClusterEnvironment} through a {@link Builder ClusterEnvironment.Builder} whilst
|
||||
* retaining default auto-configuration.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @since 2.3.0
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface ClusterEnvironmentBuilderCustomizer {
|
||||
|
||||
/**
|
||||
* Customize the {@link Builder ClusterEnvironment.Builder}.
|
||||
* @param builder the builder to customize
|
||||
*/
|
||||
void customize(ClusterEnvironment.Builder builder);
|
||||
|
||||
}
|
||||
@@ -1,281 +0,0 @@
|
||||
/*
|
||||
* 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.couchbase;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.KeyStore;
|
||||
|
||||
import javax.net.ssl.TrustManagerFactory;
|
||||
|
||||
import com.couchbase.client.core.env.Authenticator;
|
||||
import com.couchbase.client.core.env.CertificateAuthenticator;
|
||||
import com.couchbase.client.core.env.PasswordAuthenticator;
|
||||
import com.couchbase.client.java.Cluster;
|
||||
import com.couchbase.client.java.ClusterOptions;
|
||||
import com.couchbase.client.java.codec.JacksonJsonSerializer;
|
||||
import com.couchbase.client.java.env.ClusterEnvironment;
|
||||
import com.couchbase.client.java.env.ClusterEnvironment.Builder;
|
||||
import com.couchbase.client.java.json.JsonValueModule;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.AnyNestedCondition;
|
||||
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.condition.ConditionalOnSingleCandidate;
|
||||
import org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration.CouchbaseCondition;
|
||||
import org.springframework.boot.autoconfigure.couchbase.CouchbaseProperties.Authentication.Jks;
|
||||
import org.springframework.boot.autoconfigure.couchbase.CouchbaseProperties.Authentication.Pem;
|
||||
import org.springframework.boot.autoconfigure.couchbase.CouchbaseProperties.Ssl;
|
||||
import org.springframework.boot.autoconfigure.couchbase.CouchbaseProperties.Timeouts;
|
||||
import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.boot.io.ApplicationResourceLoader;
|
||||
import org.springframework.boot.ssl.SslBundle;
|
||||
import org.springframework.boot.ssl.SslBundles;
|
||||
import org.springframework.boot.ssl.pem.PemSslStore;
|
||||
import org.springframework.boot.ssl.pem.PemSslStoreDetails;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* {@link EnableAutoConfiguration Auto-configuration} for Couchbase.
|
||||
*
|
||||
* @author Eddú Meléndez
|
||||
* @author Stephane Nicoll
|
||||
* @author Yulin Qin
|
||||
* @author Moritz Halbritter
|
||||
* @author Andy Wilkinson
|
||||
* @author Phillip Webb
|
||||
* @author Scott Frederick
|
||||
* @since 1.4.0
|
||||
*/
|
||||
@AutoConfiguration(after = JacksonAutoConfiguration.class)
|
||||
@ConditionalOnClass(Cluster.class)
|
||||
@Conditional(CouchbaseCondition.class)
|
||||
@EnableConfigurationProperties(CouchbaseProperties.class)
|
||||
public class CouchbaseAutoConfiguration {
|
||||
|
||||
private final ResourceLoader resourceLoader;
|
||||
|
||||
private final CouchbaseProperties properties;
|
||||
|
||||
CouchbaseAutoConfiguration(ResourceLoader resourceLoader, CouchbaseProperties properties) {
|
||||
this.resourceLoader = ApplicationResourceLoader.get(resourceLoader);
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(CouchbaseConnectionDetails.class)
|
||||
PropertiesCouchbaseConnectionDetails couchbaseConnectionDetails(ObjectProvider<SslBundles> sslBundles) {
|
||||
return new PropertiesCouchbaseConnectionDetails(this.properties, sslBundles.getIfAvailable());
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public ClusterEnvironment couchbaseClusterEnvironment(
|
||||
ObjectProvider<ClusterEnvironmentBuilderCustomizer> customizers,
|
||||
CouchbaseConnectionDetails connectionDetails) {
|
||||
Builder builder = initializeEnvironmentBuilder(connectionDetails);
|
||||
customizers.orderedStream().forEach((customizer) -> customizer.customize(builder));
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public Authenticator couchbaseAuthenticator(CouchbaseConnectionDetails connectionDetails) throws IOException {
|
||||
if (connectionDetails.getUsername() != null && connectionDetails.getPassword() != null) {
|
||||
return PasswordAuthenticator.create(connectionDetails.getUsername(), connectionDetails.getPassword());
|
||||
}
|
||||
Pem pem = this.properties.getAuthentication().getPem();
|
||||
if (pem.getCertificates() != null) {
|
||||
PemSslStoreDetails details = new PemSslStoreDetails(null, pem.getCertificates(), pem.getPrivateKey());
|
||||
PemSslStore store = PemSslStore.load(details);
|
||||
return CertificateAuthenticator.fromKey(store.privateKey(), pem.getPrivateKeyPassword(),
|
||||
store.certificates());
|
||||
}
|
||||
Jks jks = this.properties.getAuthentication().getJks();
|
||||
if (jks.getLocation() != null) {
|
||||
Resource resource = this.resourceLoader.getResource(jks.getLocation());
|
||||
String keystorePassword = jks.getPassword();
|
||||
try (InputStream inputStream = resource.getInputStream()) {
|
||||
KeyStore store = KeyStore.getInstance(KeyStore.getDefaultType());
|
||||
store.load(inputStream, (keystorePassword != null) ? keystorePassword.toCharArray() : null);
|
||||
return CertificateAuthenticator.fromKeyStore(store, keystorePassword);
|
||||
}
|
||||
catch (GeneralSecurityException ex) {
|
||||
throw new IllegalStateException("Error reading Couchbase certificate store", ex);
|
||||
}
|
||||
}
|
||||
throw new IllegalStateException("Couchbase authentication requires username and password, or certificates");
|
||||
}
|
||||
|
||||
@Bean(destroyMethod = "disconnect")
|
||||
@ConditionalOnMissingBean
|
||||
public Cluster couchbaseCluster(ClusterEnvironment couchbaseClusterEnvironment, Authenticator authenticator,
|
||||
CouchbaseConnectionDetails connectionDetails) {
|
||||
ClusterOptions options = ClusterOptions.clusterOptions(authenticator).environment(couchbaseClusterEnvironment);
|
||||
return Cluster.connect(connectionDetails.getConnectionString(), options);
|
||||
}
|
||||
|
||||
private ClusterEnvironment.Builder initializeEnvironmentBuilder(CouchbaseConnectionDetails connectionDetails) {
|
||||
ClusterEnvironment.Builder builder = ClusterEnvironment.builder();
|
||||
Timeouts timeouts = this.properties.getEnv().getTimeouts();
|
||||
builder.timeoutConfig((config) -> config.kvTimeout(timeouts.getKeyValue())
|
||||
.analyticsTimeout(timeouts.getAnalytics())
|
||||
.kvDurableTimeout(timeouts.getKeyValueDurable())
|
||||
.queryTimeout(timeouts.getQuery())
|
||||
.viewTimeout(timeouts.getView())
|
||||
.searchTimeout(timeouts.getSearch())
|
||||
.managementTimeout(timeouts.getManagement())
|
||||
.connectTimeout(timeouts.getConnect())
|
||||
.disconnectTimeout(timeouts.getDisconnect()));
|
||||
CouchbaseProperties.Io io = this.properties.getEnv().getIo();
|
||||
builder.ioConfig((config) -> config.maxHttpConnections(io.getMaxEndpoints())
|
||||
.numKvConnections(io.getMinEndpoints())
|
||||
.idleHttpConnectionTimeout(io.getIdleHttpConnectionTimeout()));
|
||||
SslBundle sslBundle = connectionDetails.getSslBundle();
|
||||
if (sslBundle != null) {
|
||||
configureSsl(builder, sslBundle);
|
||||
}
|
||||
return builder;
|
||||
}
|
||||
|
||||
private void configureSsl(Builder builder, SslBundle sslBundle) {
|
||||
Assert.state(!sslBundle.getOptions().isSpecified(), "SSL Options cannot be specified with Couchbase");
|
||||
builder.securityConfig((config) -> {
|
||||
config.enableTls(true);
|
||||
TrustManagerFactory trustManagerFactory = sslBundle.getManagers().getTrustManagerFactory();
|
||||
if (trustManagerFactory != null) {
|
||||
config.trustManagerFactory(trustManagerFactory);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass(ObjectMapper.class)
|
||||
static class JacksonConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnSingleCandidate(ObjectMapper.class)
|
||||
ClusterEnvironmentBuilderCustomizer jacksonClusterEnvironmentBuilderCustomizer(ObjectMapper objectMapper) {
|
||||
return new JacksonClusterEnvironmentBuilderCustomizer(
|
||||
objectMapper.copy().registerModule(new JsonValueModule()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static final class JacksonClusterEnvironmentBuilderCustomizer
|
||||
implements ClusterEnvironmentBuilderCustomizer, Ordered {
|
||||
|
||||
private final ObjectMapper objectMapper;
|
||||
|
||||
private JacksonClusterEnvironmentBuilderCustomizer(ObjectMapper objectMapper) {
|
||||
this.objectMapper = objectMapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void customize(Builder builder) {
|
||||
builder.jsonSerializer(JacksonJsonSerializer.create(this.objectMapper));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Condition that matches when {@code spring.couchbase.connection-string} has been
|
||||
* configured or there is a {@link CouchbaseConnectionDetails} bean.
|
||||
*/
|
||||
static final class CouchbaseCondition extends AnyNestedCondition {
|
||||
|
||||
CouchbaseCondition() {
|
||||
super(ConfigurationPhase.REGISTER_BEAN);
|
||||
}
|
||||
|
||||
@ConditionalOnProperty("spring.couchbase.connection-string")
|
||||
private static final class CouchbaseUrlCondition {
|
||||
|
||||
}
|
||||
|
||||
@ConditionalOnBean(CouchbaseConnectionDetails.class)
|
||||
private static final class CouchbaseConnectionDetailsCondition {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Adapts {@link CouchbaseProperties} to {@link CouchbaseConnectionDetails}.
|
||||
*/
|
||||
static final class PropertiesCouchbaseConnectionDetails implements CouchbaseConnectionDetails {
|
||||
|
||||
private final CouchbaseProperties properties;
|
||||
|
||||
private final SslBundles sslBundles;
|
||||
|
||||
PropertiesCouchbaseConnectionDetails(CouchbaseProperties properties, SslBundles sslBundles) {
|
||||
this.properties = properties;
|
||||
this.sslBundles = sslBundles;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getConnectionString() {
|
||||
return this.properties.getConnectionString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUsername() {
|
||||
return this.properties.getUsername();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPassword() {
|
||||
return this.properties.getPassword();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SslBundle getSslBundle() {
|
||||
Ssl ssl = this.properties.getEnv().getSsl();
|
||||
if (!ssl.getEnabled()) {
|
||||
return null;
|
||||
}
|
||||
if (StringUtils.hasLength(ssl.getBundle())) {
|
||||
Assert.notNull(this.sslBundles, "SSL bundle name has been set but no SSL bundles found in context");
|
||||
return this.sslBundles.getBundle(ssl.getBundle());
|
||||
}
|
||||
return SslBundle.systemDefault();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
/*
|
||||
* 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.couchbase;
|
||||
|
||||
import org.springframework.boot.autoconfigure.service.connection.ConnectionDetails;
|
||||
import org.springframework.boot.ssl.SslBundle;
|
||||
|
||||
/**
|
||||
* Details required to establish a connection to a Couchbase service.
|
||||
*
|
||||
* @author Moritz Halbritter
|
||||
* @author Andy Wilkinson
|
||||
* @author Phillip Webb
|
||||
* @since 3.1.0
|
||||
*/
|
||||
public interface CouchbaseConnectionDetails extends ConnectionDetails {
|
||||
|
||||
/**
|
||||
* Connection string used to locate the Couchbase cluster.
|
||||
* @return the connection string used to locate the Couchbase cluster
|
||||
*/
|
||||
String getConnectionString();
|
||||
|
||||
/**
|
||||
* Cluster username.
|
||||
* @return the cluster username
|
||||
*/
|
||||
String getUsername();
|
||||
|
||||
/**
|
||||
* Cluster password.
|
||||
* @return the cluster password
|
||||
*/
|
||||
String getPassword();
|
||||
|
||||
/**
|
||||
* SSL bundle to use.
|
||||
* @return the SSL bundle to use
|
||||
* @since 3.5.0
|
||||
*/
|
||||
default SslBundle getSslBundle() {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,409 +0,0 @@
|
||||
/*
|
||||
* 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.couchbase;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Configuration properties for Couchbase.
|
||||
*
|
||||
* @author Eddú Meléndez
|
||||
* @author Stephane Nicoll
|
||||
* @author Yulin Qin
|
||||
* @author Brian Clozel
|
||||
* @author Michael Nitschinger
|
||||
* @author Scott Frederick
|
||||
* @since 1.4.0
|
||||
*/
|
||||
@ConfigurationProperties("spring.couchbase")
|
||||
public class CouchbaseProperties {
|
||||
|
||||
/**
|
||||
* Connection string used to locate the Couchbase cluster.
|
||||
*/
|
||||
private String connectionString;
|
||||
|
||||
/**
|
||||
* Cluster username.
|
||||
*/
|
||||
private String username;
|
||||
|
||||
/**
|
||||
* Cluster password.
|
||||
*/
|
||||
private String password;
|
||||
|
||||
private final Authentication authentication = new Authentication();
|
||||
|
||||
private final Env env = new Env();
|
||||
|
||||
public String getConnectionString() {
|
||||
return this.connectionString;
|
||||
}
|
||||
|
||||
public void setConnectionString(String connectionString) {
|
||||
this.connectionString = connectionString;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return this.username;
|
||||
}
|
||||
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return this.password;
|
||||
}
|
||||
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public Authentication getAuthentication() {
|
||||
return this.authentication;
|
||||
}
|
||||
|
||||
public Env getEnv() {
|
||||
return this.env;
|
||||
}
|
||||
|
||||
public static class Authentication {
|
||||
|
||||
private final Pem pem = new Pem();
|
||||
|
||||
private final Jks jks = new Jks();
|
||||
|
||||
public Pem getPem() {
|
||||
return this.pem;
|
||||
}
|
||||
|
||||
public Jks getJks() {
|
||||
return this.jks;
|
||||
}
|
||||
|
||||
public static class Pem {
|
||||
|
||||
/**
|
||||
* PEM-formatted certificates for certificate-based cluster authentication.
|
||||
*/
|
||||
private String certificates;
|
||||
|
||||
/**
|
||||
* PEM-formatted private key for certificate-based cluster authentication.
|
||||
*/
|
||||
private String privateKey;
|
||||
|
||||
/**
|
||||
* Private key password for certificate-based cluster authentication.
|
||||
*/
|
||||
private String privateKeyPassword;
|
||||
|
||||
public String getCertificates() {
|
||||
return this.certificates;
|
||||
}
|
||||
|
||||
public void setCertificates(String certificates) {
|
||||
this.certificates = certificates;
|
||||
}
|
||||
|
||||
public String getPrivateKey() {
|
||||
return this.privateKey;
|
||||
}
|
||||
|
||||
public void setPrivateKey(String privateKey) {
|
||||
this.privateKey = privateKey;
|
||||
}
|
||||
|
||||
public String getPrivateKeyPassword() {
|
||||
return this.privateKeyPassword;
|
||||
}
|
||||
|
||||
public void setPrivateKeyPassword(String privateKeyPassword) {
|
||||
this.privateKeyPassword = privateKeyPassword;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class Jks {
|
||||
|
||||
/**
|
||||
* Java KeyStore location for certificate-based cluster authentication.
|
||||
*/
|
||||
private String location;
|
||||
|
||||
/**
|
||||
* Java KeyStore password for certificate-based cluster authentication.
|
||||
*/
|
||||
private String password;
|
||||
|
||||
/**
|
||||
* Private key password for certificate-based cluster authentication.
|
||||
*/
|
||||
private String privateKeyPassword;
|
||||
|
||||
public String getLocation() {
|
||||
return this.location;
|
||||
}
|
||||
|
||||
public void setLocation(String location) {
|
||||
this.location = location;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return this.password;
|
||||
}
|
||||
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public String getPrivateKeyPassword() {
|
||||
return this.privateKeyPassword;
|
||||
}
|
||||
|
||||
public void setPrivateKeyPassword(String privateKeyPassword) {
|
||||
this.privateKeyPassword = privateKeyPassword;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class Env {
|
||||
|
||||
private final Io io = new Io();
|
||||
|
||||
private final Ssl ssl = new Ssl();
|
||||
|
||||
private final Timeouts timeouts = new Timeouts();
|
||||
|
||||
public Io getIo() {
|
||||
return this.io;
|
||||
}
|
||||
|
||||
public Ssl getSsl() {
|
||||
return this.ssl;
|
||||
}
|
||||
|
||||
public Timeouts getTimeouts() {
|
||||
return this.timeouts;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class Io {
|
||||
|
||||
/**
|
||||
* Minimum number of sockets per node.
|
||||
*/
|
||||
private int minEndpoints = 1;
|
||||
|
||||
/**
|
||||
* Maximum number of sockets per node.
|
||||
*/
|
||||
private int maxEndpoints = 12;
|
||||
|
||||
/**
|
||||
* Length of time an HTTP connection may remain idle before it is closed and
|
||||
* removed from the pool.
|
||||
*/
|
||||
private Duration idleHttpConnectionTimeout = Duration.ofSeconds(1);
|
||||
|
||||
public int getMinEndpoints() {
|
||||
return this.minEndpoints;
|
||||
}
|
||||
|
||||
public void setMinEndpoints(int minEndpoints) {
|
||||
this.minEndpoints = minEndpoints;
|
||||
}
|
||||
|
||||
public int getMaxEndpoints() {
|
||||
return this.maxEndpoints;
|
||||
}
|
||||
|
||||
public void setMaxEndpoints(int maxEndpoints) {
|
||||
this.maxEndpoints = maxEndpoints;
|
||||
}
|
||||
|
||||
public Duration getIdleHttpConnectionTimeout() {
|
||||
return this.idleHttpConnectionTimeout;
|
||||
}
|
||||
|
||||
public void setIdleHttpConnectionTimeout(Duration idleHttpConnectionTimeout) {
|
||||
this.idleHttpConnectionTimeout = idleHttpConnectionTimeout;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class Ssl {
|
||||
|
||||
/**
|
||||
* Whether to enable SSL support. Enabled automatically if a "bundle" is provided
|
||||
* unless specified otherwise.
|
||||
*/
|
||||
private Boolean enabled;
|
||||
|
||||
/**
|
||||
* SSL bundle name.
|
||||
*/
|
||||
private String bundle;
|
||||
|
||||
public Boolean getEnabled() {
|
||||
return (this.enabled != null) ? this.enabled : StringUtils.hasText(this.bundle);
|
||||
}
|
||||
|
||||
public void setEnabled(Boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
public String getBundle() {
|
||||
return this.bundle;
|
||||
}
|
||||
|
||||
public void setBundle(String bundle) {
|
||||
this.bundle = bundle;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class Timeouts {
|
||||
|
||||
/**
|
||||
* Bucket connect timeout.
|
||||
*/
|
||||
private Duration connect = Duration.ofSeconds(10);
|
||||
|
||||
/**
|
||||
* Bucket disconnect timeout.
|
||||
*/
|
||||
private Duration disconnect = Duration.ofSeconds(10);
|
||||
|
||||
/**
|
||||
* Timeout for operations on a specific key-value.
|
||||
*/
|
||||
private Duration keyValue = Duration.ofMillis(2500);
|
||||
|
||||
/**
|
||||
* Timeout for operations on a specific key-value with a durability level.
|
||||
*/
|
||||
private Duration keyValueDurable = Duration.ofSeconds(10);
|
||||
|
||||
/**
|
||||
* N1QL query operations timeout.
|
||||
*/
|
||||
private Duration query = Duration.ofSeconds(75);
|
||||
|
||||
/**
|
||||
* Regular and geospatial view operations timeout.
|
||||
*/
|
||||
private Duration view = Duration.ofSeconds(75);
|
||||
|
||||
/**
|
||||
* Timeout for the search service.
|
||||
*/
|
||||
private Duration search = Duration.ofSeconds(75);
|
||||
|
||||
/**
|
||||
* Timeout for the analytics service.
|
||||
*/
|
||||
private Duration analytics = Duration.ofSeconds(75);
|
||||
|
||||
/**
|
||||
* Timeout for the management operations.
|
||||
*/
|
||||
private Duration management = Duration.ofSeconds(75);
|
||||
|
||||
public Duration getConnect() {
|
||||
return this.connect;
|
||||
}
|
||||
|
||||
public void setConnect(Duration connect) {
|
||||
this.connect = connect;
|
||||
}
|
||||
|
||||
public Duration getDisconnect() {
|
||||
return this.disconnect;
|
||||
}
|
||||
|
||||
public void setDisconnect(Duration disconnect) {
|
||||
this.disconnect = disconnect;
|
||||
}
|
||||
|
||||
public Duration getKeyValue() {
|
||||
return this.keyValue;
|
||||
}
|
||||
|
||||
public void setKeyValue(Duration keyValue) {
|
||||
this.keyValue = keyValue;
|
||||
}
|
||||
|
||||
public Duration getKeyValueDurable() {
|
||||
return this.keyValueDurable;
|
||||
}
|
||||
|
||||
public void setKeyValueDurable(Duration keyValueDurable) {
|
||||
this.keyValueDurable = keyValueDurable;
|
||||
}
|
||||
|
||||
public Duration getQuery() {
|
||||
return this.query;
|
||||
}
|
||||
|
||||
public void setQuery(Duration query) {
|
||||
this.query = query;
|
||||
}
|
||||
|
||||
public Duration getView() {
|
||||
return this.view;
|
||||
}
|
||||
|
||||
public void setView(Duration view) {
|
||||
this.view = view;
|
||||
}
|
||||
|
||||
public Duration getSearch() {
|
||||
return this.search;
|
||||
}
|
||||
|
||||
public void setSearch(Duration search) {
|
||||
this.search = search;
|
||||
}
|
||||
|
||||
public Duration getAnalytics() {
|
||||
return this.analytics;
|
||||
}
|
||||
|
||||
public void setAnalytics(Duration analytics) {
|
||||
this.analytics = analytics;
|
||||
}
|
||||
|
||||
public Duration getManagement() {
|
||||
return this.management;
|
||||
}
|
||||
|
||||
public void setManagement(Duration management) {
|
||||
this.management = management;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2019 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Auto-configuration for Couchbase.
|
||||
*/
|
||||
package org.springframework.boot.autoconfigure.couchbase;
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user