Start splitting up spring-boot-autoconfigure

This commit is contained in:
Andy Wilkinson
2025-03-06 11:44:37 +00:00
committed by Phillip Webb
parent 349f296d26
commit 710b1d80eb
1293 changed files with 3877 additions and 3616 deletions

View File

@@ -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;
}
};
}
}
}

View File

@@ -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");
}
}
}

View File

@@ -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");
});
}
}

View File

@@ -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();
}
}
}

View File

@@ -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 {
}
}

View File

@@ -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 {
}
}

View File

@@ -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 {
}
}

View File

@@ -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 {
}
}

View File

@@ -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();
});
}
}

View File

@@ -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();
}
});
}
}

View File

@@ -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();
});
}
}

View File

@@ -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);
});
}
}
}

View File

@@ -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());
}
};
}
}
}
}

View File

@@ -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");
}
}
}

View File

@@ -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);
};
}
}

View File

@@ -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"));
}
}
}

View File

@@ -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");
}
}
}

View File

@@ -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);
}
}
}

View File

@@ -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-----

View File

@@ -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-----

View File

@@ -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-----

View File

@@ -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-----

View File

@@ -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-----

View File

@@ -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-----

View File

@@ -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

View File

@@ -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
*/

View File

@@ -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);
}

View File

@@ -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());
}
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}

View File

@@ -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);
}
}

View File

@@ -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);
}

View File

@@ -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;
}
}

View File

@@ -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 {
}
}

View File

@@ -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);
}
}
}

View File

@@ -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) {
}
}

View File

@@ -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);
}
}
}

View File

@@ -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
}
}

View File

@@ -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();
}
}

View File

@@ -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);
}
}
}

View File

@@ -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();
}
}

View File

@@ -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);
}

View File

@@ -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;
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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;

View File

@@ -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);
}
};
}
}
}

View File

@@ -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;

View File

@@ -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");
}
}
}

View File

@@ -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);
}

View File

@@ -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 {
}

View File

@@ -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());
}
}

View File

@@ -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;
}
}
}

View File

@@ -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 {
}

View File

@@ -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 {
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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;

View File

@@ -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);
}

View File

@@ -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;
};
}
}

View File

@@ -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;
}
}
}

View File

@@ -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"));
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}
}

View File

@@ -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
}

View File

@@ -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);
}
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}
}
}

View File

@@ -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();
}
}

View File

@@ -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"));
}
}
}

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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();
}
}

View File

@@ -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;
}
}

View File

@@ -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);
}

View File

@@ -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);
}
}

View File

@@ -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;

View File

@@ -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;
}
}
}
}

View File

@@ -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) {
}
}

View File

@@ -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;
}
}
}

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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;

View File

@@ -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;
}
}

View File

@@ -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;

View File

@@ -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;
}
}

View File

@@ -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;

View File

@@ -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);
}

View File

@@ -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();
}
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}
}

View File

@@ -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