Hot questions for Spring Boot

Hot questions for Spring Boot

Question:

How do I configure the TCP/IP port listened on by a Spring Boot application, so it does not use the default port of 8080.


Answer:

As said in docs either set server.port as system property using command line option to jvm -Dserver.port=8090 or add application.properties in /src/main/resources/ with

server.port=8090

For random port use

server.port=0

Question:

I want to log SQL statements in a file. I have the following properties in application.properties

spring.datasource.url=...
spring.datasource.username=user
spring.datasource.password=1234
spring.datasource.driver-class-name=net.sourceforge.jtds.jdbc.Driver

spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true

security.ignored=true
security.basic.enabled=false

logging.level.org.springframework.web=INFO
logging.level.org.hibernate=INFO
logging.file=c:/temp/my-log/app.log

When I run my application

cmd>mvn spring-boot:run

I can see sql statements in the console but they don't appear in a file app.log. The file contains only basic logs from spring.

What should I do to see sql statements in the log file?


Answer:

try using this in your properties file:

logging.level.org.hibernate.SQL=DEBUG
logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE

Question:

This is very simple question, but I cannot find information. (Maybe my knowledge about Java frameworks is severely lacking)

How can I set the logging level with application.properties? And logging file location, etc?


Answer:

Update: Starting with Spring Boot v1.2.0.RELEASE, the settings in application.properties or application.yml do apply. See the Log Levels section of the reference guide.

logging.level.org.springframework.web: DEBUG
logging.level.org.hibernate: ERROR

For earlier versions of Spring Boot you cannot. You simply have to use the normal configuration for your logging framework (log4j, logback) for that. Add the appropriate config file (log4j.xml or logback.xml) to the src/main/resources directory and configure to your liking.

You can enable debug logging by specifying --debug when starting the application from the command-line.

Spring Boot provides also a nice starting point for logback to configure some defaults, coloring etc. the base.xml file which you can simply include in your logback.xml file. (This is also recommended from the default logback.xml in Spring Boot.

<include resource="org/springframework/boot/logging/logback/base.xml"/>     

Question:

I want to access values provided in application.properties, e.g.:

logging.level.org.springframework.web: DEBUG
logging.level.org.hibernate: ERROR
logging.file=${HOME}/application.log

userBucket.path=${HOME}/bucket

I want to access userBucket.path in my main program in a Spring Boot application.


Answer:

You can use the @Value annotation and access the property in whichever Spring bean you're using

@Value("${userBucket.path}")
private String userBucketPath;

The Externalized Configuration section of the Spring Boot docs, explains all the details that you might need.

Question:

When I created a Spring Boot application I could see mvnw and mvnw.cmd files in the root of the project. What is the purpose of these two files?


Answer:

These files are from Maven wrapper. It works similarly to the Gradle wrapper.

This allows you to run the Maven project without having Maven installed and present on the path. It downloads the correct Maven version if it's not found (as far as I know by default in your user home directory).

The mvnw file is for Linux (bash) and the mvnw.cmd is for the Windows environment.


To create or update all necessary Maven Wrapper files execute the following command:

mvn -N io.takari:maven:wrapper

To use a different version of maven you can specify the version as follows:

mvn -N io.takari:maven:wrapper -Dmaven=3.3.3

Both commands require maven on PATH (add the path to maven bin to Path on System Variables) if you already have mvnw in your project you can use ./mvnw instead of mvn in the commands.

Question:

I am trying run a spring-boot application which uses hibernate via spring-jpa, but i am getting this error:

Caused by: org.hibernate.HibernateException: Access to DialectResolutionInfo cannot be null when 'hibernate.dialect' not set
        at org.hibernate.engine.jdbc.dialect.internal.DialectFactoryImpl.determineDialect(DialectFactoryImpl.java:104)
        at org.hibernate.engine.jdbc.dialect.internal.DialectFactoryImpl.buildDialect(DialectFactoryImpl.java:71)
        at org.hibernate.engine.jdbc.internal.JdbcServicesImpl.configure(JdbcServicesImpl.java:205)
        at org.hibernate.boot.registry.internal.StandardServiceRegistryImpl.configureService(StandardServiceRegistryImpl.java:111)
        at org.hibernate.service.internal.AbstractServiceRegistryImpl.initializeService(AbstractServiceRegistryImpl.java:234)
        at org.hibernate.service.internal.AbstractServiceRegistryImpl.getService(AbstractServiceRegistryImpl.java:206)
        at org.hibernate.cfg.Configuration.buildTypeRegistrations(Configuration.java:1885)
        at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1843)
        at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl$4.perform(EntityManagerFactoryBuilderImpl.java:850)
        at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl$4.perform(EntityManagerFactoryBuilderImpl.java:843)
        at org.hibernate.boot.registry.classloading.internal.ClassLoaderServiceImpl.withTccl(ClassLoaderServiceImpl.java:398)
        at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:842)
        at org.hibernate.jpa.HibernatePersistenceProvider.createContainerEntityManagerFactory(HibernatePersistenceProvider.java:152)
        at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:336)
        at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:318)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1613)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1550)
        ... 21 more

my pom.xml file is this:

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.1.8.RELEASE</version>
</parent>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.security</groupId>
        <artifactId>spring-security-web</artifactId>
       </dependency>
    <dependency>
        <groupId>org.springframework.security</groupId>
        <artifactId>spring-security-config</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.security</groupId>
        <artifactId>spring-security-taglibs</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    <dependency>
        <groupId>commons-dbcp</groupId>
        <artifactId>commons-dbcp</artifactId>
    </dependency>
</dependencies>

my hibernate configuration is that (the dialect configuration is in the last method from this class):

@Configuration
@EnableTransactionManagement
@ComponentScan({ "com.spring.app" })
public class HibernateConfig {

   @Bean
   public LocalSessionFactoryBean sessionFactory() {
      LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();

      sessionFactory.setDataSource(restDataSource());
      sessionFactory.setPackagesToScan(new String[] { "com.spring.app.model" });
      sessionFactory.setHibernateProperties(hibernateProperties());

      return sessionFactory;
   }

   @Bean
   public DataSource restDataSource() {
      BasicDataSource dataSource = new BasicDataSource();

      dataSource.setDriverClassName("org.postgresql.Driver");
      dataSource.setUrl("jdbc:postgresql://localhost:5432/teste?charSet=LATIN1");
      dataSource.setUsername("klebermo");
      dataSource.setPassword("123");

      return dataSource;
   }

   @Bean
   @Autowired
   public HibernateTransactionManager transactionManager(SessionFactory sessionFactory) {
      HibernateTransactionManager txManager = new HibernateTransactionManager();
      txManager.setSessionFactory(sessionFactory);
      return txManager;
   }

   @Bean
   public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {
      return new PersistenceExceptionTranslationPostProcessor();
   }

   Properties hibernateProperties() {
      return new Properties() {
         /**
         * 
         */
        private static final long serialVersionUID = 1L;

        {
            setProperty("hibernate.hbm2ddl.auto", "create");
            setProperty("hibernate.show_sql", "false");
            setProperty("hibernate.dialect", "org.hibernate.dialect.PostgreSQLDialect");
         }
      };
   }
}

what I am doing wrong here?


Answer:

First remove all of your configuration Spring Boot will start it for you. If you really need a SessionFactory instead of an EntityManagerFactory add a HibernateJpaSessionFactoryBean.

Make sure you have an application.properties in your classpath and add the following properties.

spring.datasource.driverClassName=org.postgresql.Driver
spring.datasource.url=jdbc:postgresql://localhost:5432/teste?charSet=LATIN1
spring.datasource.username=klebermo
spring.datasource.password=123

spring.jpa.database-platform=org.hibernate.dialect.PostgreSQLDialect
spring.jpa.show-sql=false
spring.jpa.hibernate.ddl-auto=create

If you really need access to a SessionFactory and that is basically for the same datasource, then you can do the following (which is also docmented here although for XML, not JavaConfig).

@Configuration        
public class HibernateConfig {

    @Bean
    public HibernateJpaSessionFactoryBean sessionFactory(EntityManagerFactory emf) {
         HibernateJpaSessionFactoryBean factory = new HibernateJpaSessionFactoryBean();
         factory.setEntityManagerFactory(emf);
         return factory;
    }
}

That way you have both an EntityManagerFactory and a SessionFactory.

Assuming you have a class with a main method with @EnableAutoConfiguration you don't need the @EnableTransactionManagement annotation, as that will be enabled by Spring Boot for you. A basic application class in the com.spring.app package should be enough.

@Configuration
@EnableAutoConfiguration
@ComponentScan
public class Application {


    public static void main(String[] args) throws Exception {
        SpringApplication.run(Application.class, args);
    }

} 

Something like that should be enough to have all your classes (including entities and Spring Data based repositories) detected.

I would also suggest removing the commons-dbcp dependency as that would allow Spring Boot to configure the faster and more robust HikariCP implementation.

Question:

How to configure nicely Spring Boot application packaged as executable jar as a Service in linux system? Is this recommended approach, or should I convert this app to war and install into Tomcat?

Currently I can run Spring boot application from screen session, what is nice, but requires manual start after server reboot.

What I'm looking for is general advice/direction or sample init.d script, if my approach with executable jar is proper.


Answer:

The following works for springboot 1.3 and above:

As init.d service

The executable jar has the usual start, stop, restart, and status commands. It will also set up a PID file in the usual /var/run directory and logging in the usual /var/log directory by default.

You just need to symlink your jar into /etc/init.d like so

sudo link -s /var/myapp/myapp.jar /etc/init.d/myapp

OR

sudo ln -s ~/myproject/build/libs/myapp-1.0.jar /etc/init.d/myapp_servicename

After that you can do the usual

/etc/init.d/myapp start

Then setup a link in whichever runlevel you want the app to start/stop in on boot if so desired.


As a systemd service

To run a Spring Boot application installed in var/myapp you can add the following script in /etc/systemd/system/myapp.service:

[Unit]
Description=myapp
After=syslog.target

[Service]
ExecStart=/var/myapp/myapp.jar

[Install]
WantedBy=multi-user.target

NB: in case you are using this method, do not forget to make the jar file itself executable (with chmod +x) otherwise it will fail with error "Permission denied".

Reference

http://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/html/deployment-install.html#deployment-service

Question:

I am new to Spring and Spring Boot. How can I configure and use two data sources?

For example here is what I have for the first data source:

application.properties

#first db
spring.datasource.url = [url]
spring.datasource.username = [username]
spring.datasource.password = [password]
spring.datasource.driverClassName = oracle.jdbc.OracleDriver

#second db ...

Application class

@SpringBootApplication
public class SampleApplication
{
    public static void main(String[] args) {
        SpringApplication.run(SampleApplication.class, args);
    }
}

How do I modify application.properties to add another data source? How do I autowire it to be used by a different repository?


Answer:

Here you go

#first db
spring.datasource.url = [url]
spring.datasource.username = [username]
spring.datasource.password = [password]
spring.datasource.driverClassName = oracle.jdbc.OracleDriver

#second db ...
spring.secondDatasource.url = [url]
spring.secondDatasource.username = [username]
spring.secondDatasource.password = [password]
spring.secondDatasource.driverClassName = oracle.jdbc.OracleDriver


@Bean
@Primary
@ConfigurationProperties(prefix="spring.datasource")
public DataSource primaryDataSource() {
    return DataSourceBuilder.create().build();
}

@Bean
@ConfigurationProperties(prefix="spring.secondDatasource")
public DataSource secondaryDataSource() {
    return DataSourceBuilder.create().build();
}

Question:

I want to run code after my spring-boot app starts to monitor a directory for changes.

I have tried running a new thread but the @Autowired services have not been set at that point.

I have been able to find ApplicationPreparedEvent, which fires before the @Autowired annotations are set. Ideally I would like the event to fire once the application is ready to process http requests.

Is there a better event to use, or a better way of running code after the application is live in spring-boot?


Answer:

It is as simple as this:

@EventListener(ApplicationReadyEvent.class)
public void doSomethingAfterStartup() {
    System.out.println("hello world, I have just started up");
}

Tested on version 1.5.1.RELEASE

Question:

I have a Spring-Boot application where the default properties are set in an application.properties file in the classpath (src/main/resources/application.properties).

I would like to override some default settings in my JUnit test with properties declared in a test.properties file (src/test/resources/test.properties)

I usualy have a dedicated Config Class for my Junit Tests, e.g.

package foo.bar.test;

import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

@Configuration
@Import(CoreConfig.class)
@EnableAutoConfiguration
public class TestConfig {

}

I first thought that using @PropertySource("classpath:test.properties") in the TestConfig class would do the trick, but these properties will not overwrite the application.properties settings (see Spring-Boot Reference Doc - 23. Externalized Configuration).

Then I tried to use -Dspring.config.location=classpath:test.properties when invoking the test. That was successful - but I don't want to set this system property for each test execution. Thus I put it in the code

@Configuration
@Import(CoreConfig.class)
@EnableAutoConfiguration
public class TestConfig {

  static {
    System.setProperty("spring.config.location", "classpath:test.properties");
  }

}

which unfortunatly was again not successful.

There must be a simple solution on how to override application.properties settings in JUnit tests with test.properties that I must have overlooked.


Answer:

You can use @TestPropertySource to override values in application.properties. From its javadoc:

test property sources can be used to selectively override properties defined in system and application property sources

For example:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = ExampleApplication.class)
@TestPropertySource(locations="classpath:test.properties")
public class ExampleApplicationTests {

}

Question:

Execution default of goal 
org.springframework.boot:spring-boot-maven-plugin:1.0.1.RELEASE:repackage 
failed: 
Unable to find a single main class from the following candidates

My project has more than one class with a main method. How do I tell the Spring Boot Maven plugin which of the classes it should use as the main class?


Answer:

Add your start class in your pom:

<properties>
    <!-- The main class to start by executing java -jar -->
    <start-class>com.mycorp.starter.HelloWorldApplication</start-class>
</properties>

or

<build>
<plugins>
    <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>             
        <configuration>    
            <mainClass>com.mycorp.starter.HelloWorldApplication</mainClass>
        </configuration>
    </plugin>
</plugins>
</build>