Spring Boot Starter-Web tries to connect to Mongo at startup - java

I am experiencing some problems using Spring Boot and MongoDB external driver. I can't use the project Spring Data MongoDB, because I need to use the ufficial async driver given by Mongo. However, I need to use Spring Boot, because the module I am developing is part of a bigger project using this library.
Here is my pom.xml file.
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>tx-view</artifactId>
<version>1.0-SNAPSHOT</version>
<!-- omissis -->
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongodb-driver-async</artifactId>
<version>${mongodb.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>com.spotify</groupId>
<artifactId>docker-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
In detail, I am using Spring Boot 1.4.1 and Mongo Async Driver 3.2.2.
Here is my application.
#SpringBootApplication(exclude = {MongoAutoConfiguration.class, MongoDataAutoConfiguration.class})
public class TxViewApplication {
public static void main(String[] args) {
SpringApplication.run(TxViewApplication.class, args);
}
#Value("${mongo.uri}")
private String mongoUri;
#Bean
public MongoClient mongoClient() {
return MongoClients.create(mongoUri);
}
}
It follows the only (empty) test I have at the moment.
#SpringBootTest
#RunWith(SpringRunner.class)
public class ApplicationTest {
#Test
public void loadContext() throws Exception {}
}
I have no other code in this project. When I run the test, I have the following error:
2016-11-22 15:43:58.597 INFO 4572 --- [null'}-db:27017] org.mongodb.driver.cluster : Exception in monitor thread while connecting to server db:27017
com.mongodb.MongoException: java.io.IOException: Il computer remoto ha rifiutato la connessione di rete.
at com.mongodb.connection.InternalStreamConnection.open(InternalStreamConnection.java:125) ~[mongodb-driver-core-3.2.2.jar:na]
at com.mongodb.connection.DefaultServerMonitor$ServerMonitorRunnable.run(DefaultServerMonitor.java:128) ~[mongodb-driver-core-3.2.2.jar:na]
at java.lang.Thread.run(Thread.java:745) [na:1.8.0_101]
Caused by: java.io.IOException: Il computer remoto ha rifiutato la connessione di rete.
at sun.nio.ch.Iocp.translateErrorToIOException(Iocp.java:309) ~[na:1.8.0_101]
at sun.nio.ch.Iocp.access$700(Iocp.java:46) ~[na:1.8.0_101]
at sun.nio.ch.Iocp$EventHandlerTask.run(Iocp.java:399) ~[na:1.8.0_101]
at sun.nio.ch.AsynchronousChannelGroupImpl$1.run(AsynchronousChannelGroupImpl.java:112) ~[na:1.8.0_101]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) ~[na:1.8.0_101]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) ~[na:1.8.0_101]
... 1 common frames omitted
As you can see, I have properly inserted the exclude clause in the SpringBootApplication annotation in order to stop Spring Boot to try handle its own the connection to Mongo, as suggested in Mongo tries to connect automatically to port 27017(localhost).
I have also noticed that I started to have the error after the addition to the pom.xml of the dependency to spring-boot-starter-web.
How can I inhibit Spring Boot to try to connect automatically to Mongo at startup? The same problem is present with the synchronous version of MongoDB driver.
--- EDIT ---
I have also try to build a wrapper around the async.MongoClient object, in this way:
public class MongoWrapper {
private final MongoClient mongo;
public MongoWrapper() {
mongo = MongoClients.create();
}
public MongoClient getMongo() {
return mongo;
}
}
The configuration was changed accordingly.
#Bean
public MongoWrapper mongo() {
return new MongoWrapper();
}
Unfortunately, nothing had changed. Spring Boot seems to intercept the MongoClient object also in this way :(
Thanks a lot.

You have a MongoClient bean in your own configuration which does not make any sense to me if you've excluded the auto-configuration.
I've commented out the #Bean definition in your own config and no attempt to connect to Mongo is performed now. I am not sure I answer to your question and you're probably looking for something else but if you don't want to use mongo, don't define a MongoClient in your own config!

This helped us to disable async java driver of MongoDB to use default configuration:
#EnableAutoConfiguration(exclude = {MongoReactiveAutoConfiguration.class})

Related

How do I delay Spring JPA auto-configuration until a bean has run?

I have a Spring application that's trying to connect to a database. In order to connect, an SSH tunnel must first be established (using Jsch). How do I delay HibernateJpaAutoConfiguration until after the bean that's establishing the Jsch SSH session has returned? Currently the application is failing to start because the tunnel hasn't been opened yet. When I try to exclude this autoconfiguration class, and then instantiate it explicitly predicated on the session bean already having been created, I get the following error:
Caused by: java.lang.IllegalArgumentException: At least one JPA metamodel must be present!
I don't understand why I suddenly have to provide this myself when, if I rely on the auto-configuration, I don't have to provide it. If someone can show me a way to achieve this, that would be great.
POM:
...
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!-- Spring data JPA, default tomcat pool, exclude it -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<exclusions>
<exclusion>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-jdbc</artifactId>
</exclusion>
</exclusions>
</dependency>
...
Main application:
#SpringBootApplication(exclude = HibernateJpaAutoConfiguration.class)
public class Application {
public static void main(String... args) {
SpringApplication.run(Application.class, args);
}
#Configuration
static class SshTunnelConfiguration {
#Bean
public com.jcraft.jsch.Session sshTunnel() {
...
}
}
#Configuration
#ConditionalOnBean(com.jcraft.jsch.Session.class)
static class DelayedJpaConfiguration extends HibernateJpaAutoConfiguration {
public JpaConfiguration(DataSource dataSource, JpaProperties jpaProperties, ObjectProvider<JtaTransactionManager> jtaTransactionManager, ObjectProvider<TransactionManagerCustomizers> transactionManagerCustomizers) {
super(dataSource, jpaProperties, jtaTransactionManager, transactionManagerCustomizers);
}
}
}
You would have to implement your own data source (by extending the one you use) and implementing the InitializingBean interface and in the 'afterPropertiesSet' method initialize your jsch tunnel.
Please refer to this: Spring Data JPA with ssh tunnel to a remote MySQL server

Spring boot default connection pool tomcat properties not working

We are using spring boot 1.5.9.RELEASE. We have spring-boot-starter-data-jpa and mysql-connector-java in our maven dependency to connect to MySQL db. We have not configured any connection pool. According to the documentation since we are using spring-boot-starter-data-jpa tomcat connection pool is used as default connection pool. But when we try setting connection pool properties as spring.datasource.tomcat.* it is not working. But the same is working when spring.datasource.* format is used.
i.e spring.datasource.max-active=50 is working where as spring.datasource.tomcat.max-active=50 is not working. I confirmed this by printing Datasource in main class for which I'm getting org.apache.tomcat.jdbc.pool.DataSource#<objecthash>{key1=value1; key2=value2; ....} as output.
Why is this happening? Is it because we are using mysql-connector-java it's not reading tomcat connection pool properties? if that's the case then when I print Datasource how am I getting org.apache.tomcat.jdbc.pool.DataSource#a1f72f5 as data source with configured values? Or did I miss out something from the documentation? or JPA is not working properly?
pom.xml:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.9.RELEASE</version>
<relativePath />
</parent>
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
</dependencies>
Mainclass.java
import javax.sql.DataSource;
#SpringBootApplication
public class MainClass implements CommandLineRunner {
#Autowired
DataSource dataSource;
public static void main(String[] args) {
SpringApplication.run(MainClassChild.class, args);
}
#Override
public void run(String... args) throws Exception {
System.out.println("DATASOURCE = " + dataSource);
}
}
Application.properties
spring.datasource.url=jdbc:mysql://1.2.3.4/dbname?useSSL=false
spring.datasource.username=username
spring.datasource.password=password
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
#Working
spring.datasource.max-active=30
spring.datasource.max-idle=20
spring.datasource.min-idle=10
#Not Working
spring.datasource.tomcat.max-active=30
spring.datasource.tomcat.max-idle=20
spring.datasource.tomcat.min-idle=10
Note: We autowire jdbctemplate and use it in DAO.

Spring Boot throws ClassNotFoundException with maven dependency for another project

I have Spring Boot project with simple EnvironmentPostProcessor implementation:
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.env.EnvironmentPostProcessor;
import org.springframework.core.env.ConfigurableEnvironment;
public class DevProfilerResolverEnvironmentPostProcessor implements EnvironmentPostProcessor {
#Override
public void postProcessEnvironment(ConfigurableEnvironment configurableEnvironment, SpringApplication springApplication) {
if (configurableEnvironment.getActiveProfiles().length == 0) {
if (System.getenv().get("OS").contains("Windows")) {
configurableEnvironment.addActiveProfile("DEV");
}
}
}
}
Also, I registered this class to sprig.factories:
org.springframework.boot.env.EnvironmentPostProcessor = com.example.demo.DevProfilerResolverEnvironmentPostProcessor
Now structure looks like:
Snippet from pom file:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>demo</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.4.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
I executed with Maven:
mvn install
Now I want to use this EnvironmentPostProcessor implementation on another spring boot project. Thus I added it to dependency section for the new project:
<dependency>
<groupId>com.example</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
And I wrote simple service usage:
#Service
#Profile("DEV")
public class DeveloperService {
#Scheduled(cron = "1/1 * * * * ?")
public void doWork() {
System.out.println("Developers.... ");
}
}
and enabled scheduling for main class:
#SpringBootApplication
#EnableScheduling
public class LvivBootApplication {
public static void main(String[] args) {
SpringApplication.run(LvivBootApplication.class, args);
}
}
However, I got following exception after main execution:
14:56:09.822 [main] ERROR org.springframework.boot.SpringApplication - Application startup failed
java.lang.IllegalArgumentException: Unable to instantiate factory class: org.springframework.boot.env.EnvironmentPostProcessor
Caused by: java.lang.ClassNotFoundException: com.example.demo.DevProfilerResolverEnvironmentPostProcessor
at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
and dependency is added to the new project:
I am running it exactly on Windows environment.
The idea is when OS is Windows add DEV profile for the first project.
Second has service which prints to console dummy info when the profile is DEV and scheduled this printing for every second.
I can't find what is missed at this example?
SOLUTION:
For making from first project library jar pom should be fixed like following:
<!--<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<executable>true</executable>
</configuration>
</plugin>
</plugins>
</build>-->
Or simple to eliminate this plugin from pom file.
Your first jar is not a library jar. It's a repackaged boot jar, created by the spring boot plugin, containing the first spring boot application and all its dependencies, intended to be executed, and not to be used as a library.
If you want to use that as a library, you need to use the non-repackaged jar file, containing only the classes and resources of the project.
It's quite bizarre to have an application depend on another application, though. You should create a library project, only containing common common classes and resources, and use that as a dependency to your two spring boot applications.
I am posting because I had a similar error in similar circumstances - I searched for hours and the solution was very easy. I am using Eclipse for debugging - Eclipse doesn't use the produced jar from Maven build - it uses its own set of build paths with, as far as i understood, exploded classes etc.
My Maven project, the one that produced a JAR that I was including into my main project POM, didn't declare in any way some kind of dependency to the main project, e.g. via a common parent or whatever.
Eclipse seems to not understand that one of the dependencies I was using in the POM was a result of another local project - somehow, although the file (jar-with-dependencies) was in the Maven cache alright, it wasn't picking it up to copy to its own aforementioned set of classpath directories.
I needed to explicitly add it (my library project) into the main project via Project -> Properties -> Java Build Path -> Projects - adding it to the list titled "Required projects on the build path:"

JAX-RS does not work with Spring Boot 1.4.1

I am trying to develop a simple JAX-RS based web service using Spring Boot version 1.4.1.RELEASE. However getting this exception -
java.lang.IllegalStateException: No generator was provided and there is no default generator registered
at org.glassfish.hk2.internal.ServiceLocatorFactoryImpl.internalCreate(ServiceLocatorFactoryImpl.java:308) ~[hk2-api-2.5.0-b05.jar:na]
at org.glassfish.hk2.internal.ServiceLocatorFactoryImpl.create(ServiceLocatorFactoryImpl.java:268) ~[hk2-api-2.5.0-b05.jar:na]
at org.glassfish.jersey.internal.inject.Injections._createLocator(Injections.java:138) ~[jersey-common-2.23.2.jar:na]
at org.glassfish.jersey.internal.inject.Injections.createLocator(Injections.java:123) ~[jersey-common-2.23.2.jar:na]
at org.glassfish.jersey.server.ApplicationHandler.<init>(ApplicationHandler.java:330) ~[jersey-server-2.23.2.jar:na]
at org.glassfish.jersey.servlet.WebComponent.<init>(WebComponent.java:392) ~[jersey-container-servlet-core-2.23.2.jar:na]
at org.glassfish.jersey.servlet.ServletContainer.init(ServletContainer.java:177) ~[jersey-container-servlet-core-2.23.2.jar:na]
at org.glassfish.jersey.servlet.ServletContainer.init(ServletContainer.java:369) ~[jersey-container-servlet-core-2.23.2.jar:na]
Here are my program details -
Dependencies included in POM.xml -
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jersey</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
And here is JerseyConfig file -
package com.test.main;
import org.glassfish.jersey.server.ResourceConfig;
import org.springframework.stereotype.Component;
import com.test.resources.TutorialResource;
#Component
public class JerseyConfig extends ResourceConfig{
public JerseyConfig() {
register(TutorialResource.class);
packages("com.test.resources");
}
}
Important: Looks like this issue is not present in most recent versions of Spring Boot. However the content of this answer can still be used as a guide when you want to create an application with Spring Boot and Jersey.
The layout of the JAR has changed in Spring Boot 1.4.1
The layout of executable jars has changed in Spring Boot 1.4.1: application’s dependencies are now packaged in BOOT-INF/lib rather than lib, and application’s own classes are now packaged in BOOT-INF/classes rather than the root of the jar. And it affects Jersey:
Jersey classpath scanning limitations
The change to the layout of executable jars means that a limitation in Jersey’s classpath scanning now affects executable jar files as well as executable war files. To work around the problem, classes that you wish to be scanned by Jersey should be packaged in a jar and included as a dependency in BOOT-INF/lib. The Spring Boot launcher should then be configured to unpack those jars on start up so that Jersey can scan their contents.
I've found that registering classes instead of packages works. See below the steps to create an application with Spring Boot and Jersey.
Creating a web application with Spring Boot and Jersey
Ensure your pom.xml file declares spring-boot-starter-parent as the parent project:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.4.1.RELEASE</version>
</parent>
You also need the following dependencies:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jersey</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
And the Spring Boot Maven plugin:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
For example purposes, create a Jersey resource class annotated with #Path and define a resource method to handle GET requests, producing text/plain:
#Path("/greetings")
public class GreetingResource {
#GET
#Produces(MediaType.TEXT_PLAIN)
public Response getGreeting() {
return Response.ok("Hello, World!").build();
}
}
Then create a class that extends ResourceConfig or Application to register the Jersey resources and annotated it with #ApplicationPath. Registering classes instead of registering packages works with Spring Boot 1.4.1:
#Component
#ApplicationPath("api")
public class JerseyConfig extends ResourceConfig {
#PostConstruct
private void init() {
registerClasses(GreetingResource.class);
}
}
And finally create a Spring Boot class to execute the application:
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
If you want to test this web service, you can use the JAX-RS Client API:
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class GreetingResourceTest {
#LocalServerPort
private int port;
private URI uri;
#Before
public void setUp() throws Exception {
this.uri = new URI("http://localhost:" + port);
}
#Test
public void testGreeting() {
Client client = ClientBuilder.newClient();
Response response = client.target(uri).path("api").path("greetings")
.request(MediaType.TEXT_PLAIN).get();
String entity = response.readEntity(String.class);
assertEquals("Hello, World!", entity);
}
}
To compile and run the application, follow these steps:
Open a command line window or terminal.
Navigate to the root directory of the project, where the pom.xml resides.
Compile the project: mvn clean compile.
Package the application: mvn package.
Look in the target directory. You should see a file with the following or a similar name: spring-jersey-1.0-SNAPSHOT.jar.
Change into the target directory.
Execute the JAR: java -jar spring-jersey-1.0-SNAPSHOT.jar.
The application should be available at http://localhost:8080/api/greetings.
Note 1: Have a look at the Spring Boot documentation. There's a section dedicated to Jersey.
Note 2: When producing JSON, ensure you have a JSON provider registered. ResourceConfig should take care of that though (just ensure that the dependencies are on the classpath).
Although Jersey cannot scan your classes inside the new version of the fat boot jar, you can achieve the same effect using Spring classpath scanning facilities. This way you can scan a package similarly to ResourceConfig.packages():
ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false);
scanner.addIncludeFilter(new AnnotationTypeFilter(Provider.class));
scanner.addIncludeFilter(new AnnotationTypeFilter(Path.class));
config.registerClasses(scanner.findCandidateComponents("your.package.to.scan").stream()
.map(beanDefinition -> ClassUtils.resolveClassName(beanDefinition.getBeanClassName(), config.getClassLoader()))
.collect(Collectors.toSet()));
Note: please have a look at the source of org.glassfish.jersey.server.internal.scanning.AnnotationAcceptingListener. This is the stock solution and you can see that it does the same: it scans for classes annotated with #Path or #Provider (but doesn't manage to find anything because of the broken scanning mechanism).
Update:
I had a custom config which didn't extend ResourceConfig but returned an instance of it as a bean.
If you look at the official Spring example, you can insert the code above into the JerseyConfig() constructor (instead of the two register(...) calls). The only difference is that instead of calling config.registerClasses(...) you simply call registerClasses(...) in the constructor.
I think you should annotate your JerseyConfig with #Configuration and not #Component.

Embedded tomcat fails to start when upgraded from Spring Boot 1.3.3 -> 1.3.5

Spring Boot application fails to launch after upgrade from 1.3.3 to 1.3.5.
Spring is unable to start embedded container (Tomcat 8) and following error message is displayed:
org.springframework.context.ApplicationContextException: Unable to start embedded container; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'embeddedServletContainerFactory': Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [wad.config.HttpsConfiguration$1]: No default constructor found; nested exception is java.lang.NoSuchMethodException: wad.config.HttpsConfiguration$1.()
Basically this error message says it can't create the embeddedServletContainerFactory, but it's not clear to me what [wad.config.HttpsConfiguration$1] refers to. The Java configuration class itself is in package wad.config and named HttpsConfiguration.
I tried to add empty constructor to my HttpsConfiguration.java but it didn't help.
Here are the relevant parts of my POM:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.3.5.RELEASE</version>
<relativePath/>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<type>jar</type>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
...
</dependencies>
My Application class:
#EntityScan(
basePackageClasses = {Application.class, Jsr310JpaConverters.class}
)
#SpringBootApplication
#Import({DevProfile.class})
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
And here is my configuration for port redirect from 8080 -> 8443 (configurable via application.properties):
#Configuration
public class HttpsConfiguration {
#Value("${server.port}")
private int httpsPort;
#Value("${server.port.http}")
private int httpPort;
#Bean
public EmbeddedServletContainerFactory servletContainer() {
TomcatEmbeddedServletContainerFactory tomcat = new TomcatEmbeddedServletContainerFactory() {
#Override
protected void postProcessContext(Context context) {
SecurityConstraint securityConstraint = new SecurityConstraint();
securityConstraint.setUserConstraint("CONFIDENTIAL");
SecurityCollection collection = new SecurityCollection();
collection.addPattern("/*");
securityConstraint.addCollection(collection);
context.addConstraint(securityConstraint);
}
};
tomcat.addAdditionalTomcatConnectors(initiateHttpConnector());
return tomcat;
}
// redirect from (http) port to (https) if https is enabled.
private Connector initiateHttpConnector() {
Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
connector.setScheme("http");
connector.setPort(httpPort);
connector.setSecure(false);
connector.setRedirectPort(httpsPort);
return connector;
}
application.properties config:
...
#Actuator port
management.port = 9001
#HTTPS port
server.port=8443
#HTTP port
server.port.http=8080
#Enable SSL
server.ssl.enabled=true
...
Update:
Issue can be reproduced with Spring Boot 1.3.5 project configured with the above POM, application.properties and HttpSecurity & Application classes.
The usage of spring-boot-starter-actuator dependency together with management.port
being defined in application.properties causes starting the embedded tomcat container to fail.
Removing the management.port property definition from application.properties makes the application to start up again.
It is worth noting that while removing the property fixed the issue it's not clear why.
The solution this problem can be found here:
https://github.com/spring-projects/spring-boot/issues/6193
and creating a separate class extending TomcatEmbeddedServletContainerFactory and in that class have a public constructor that class super. The class extending TomcatEmbeddedServletContainerFactory can't be an inner class, it must be in it's own file and public in the package, otherwise the error will not go away.

Categories

Resources