Migrating Spring to Spring Boot
How to migrate from Spring to Spring Boot.
As more and more applications move towards platform-as-a-service(PAAS), many companies are looking to migrate from Spring MVC to Spring Boot.
Migrating from Spring MVC to Spring Boot involves quite a few changes affecting the entire application.
In this article I will explain my experience on migrating Spring MVC to Spring Boot in my current company and the issues I faced doing the same.
1. POM Changes
First thing to do, is the POM changes. We need to add the spring starter maven artifact and other spring related artifacts.
- Below Spring Starter artifact needs to be added.
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.4.RELEASE</version>
</parent>
Remove the Spring MVC related dependencies and based on your requirements add below dependencies.
- If it’s a REST API application, replace it with below dependency,
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
- If there is a log4J dependency in your previous Spring MVC application, add below dependency,
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
<dependency>
- If Spring security features are needed or present in old Spring MVC project, replace it with below dependency,
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
- If hibernate was used, replace it with below maven dependency,
<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>
- If there was a SOAP service dependency, replace it with below dependency,
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web-services</artifactId>
</dependency>
- If there was a quartz dependency, replace it with below dependency,
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
2. Spring Initializer
Next, we need to create a new class at the root of the project. This class should extend SpringBootServletInitializer
.
Also this class should be annotated with @SpringBootApplication
. Example of this class is as shown below,
@SpringBootApplication
@ComponentScan("com.test")
public class TestRestInitializer extends SpringBootServletInitializer{
public static void main(String[] args) {
SpringApplication.run(TestRestInitializer .class, args);
}
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
return builder.sources(TestRestInitializer.class);
}
}
Usually this class is placed at project root. But if we don’t want to place this class at project root, we can make use of @ComponentScan
and specify the package that we want Spring Boot to initialize.
3. Application YAML
Spring Boot allows us to define configuration details in a single file called application.yml
or application.properties
file. In my case I created application.yml
file.
The application.yaml
file needs to be added in project resources
folder. As mentioned before, in this file we define configurations.
If in our previous Spring MVC project we had a custom configuration class , we replace it with application.yaml
. This application.yaml
will take care of configurations in Spring Boot.
To read data from application.yaml
. We can use below mentioned methods,
-
Using
Environment
class,for example, Consider the below
application.yml
file,app: : MyApp
To read these values in a class use below code,
@Component public class TestClass { private final Environment env; public TestClass(Environment env) { System.out.println(env.getProperty("app.name")); } }
-
Using
@Value
. We can use@Value
annotation to read dat fromapplication.yml
file. Here we are readingname
variable fromapplication.yml
.@Value("${app.name}") private String name;
-
Using
@ConfigurationProperties
We can use
@ConfigurationProperties
to read data fromapplication.yml
. Declare a class with@ConfigurationProperties
annotation.Consider the
application.yml
. Here we have define a custom variable calledapp
app: : MyApp 1
Then declare Configuration Property class as below. Using the getter methods we can fetch the values from application.yml
.
@ConfigurationProperties("app")
public class AppConfiguration{
private String name;
private int id;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}
As we can see the variable name should kept similar or same as the ones defined in the application.yml
file. This allows Spring Boot to set the values for these variables names (Also declare set methods as well).
We can access these variable using the get Method. Example of same is as shown below
@Component
public class TestClass{
@Autowired
private AppConfiguration appConfiguration;
public TestClass{
System.out.println(appConfiguration.getName());
}
}
3. DataSource
vs application.yaml
In Spring Boot we can define our DB configurations in application.yml
instead of defining it as a DataSource
and referring it from external tomcat config file. Spring Boot comes with embedded tomcat and we can use the same by following the below steps,
-
Remove
Datasource
from codeRemove class with annotation
@EnableTransactionManagement
. An example for the same is as shown below,@Configuration @EnableTransactionManagement @ComponentScan({ "com.test.configuration" }) public class JPAConfiguration { @Bean public LocalContainerEntityManagerFactoryBean entityManagerFactory() { LocalContainerEntityManagerFactoryBean entityManager = new LocalContainerEntityManagerFactoryBean(); entityManager.setDataSource(dataSource()); entityManager.setPackagesToScan(new String[] {"com.test.entity" }); entityManager.setJpaVendorAdapter(new HibernateJpaVendorAdapter()); entityManager.setJpaProperties(hibernateProperties()); return entityManager; } @Bean @Primary public JpaTransactionManager transactionManager() { JpaTransactionManager jpaTxManager = new JpaTransactionManager(entityManagerFactory().getObject()); return jpaTxManager ; } @Bean public AnnotationTransactionAspect annotationTransactionAspect() { AnnotationTransactionAspect aspectjTx = AnnotationTransactionAspect.aspectOf(); aspectjTx.setTransactionManager(transactionManager()); return aspectjTx; } @Bean(destroyMethod="") public DataSource dataSource() { DataSource dataSource = null; JndiTemplate jndi = new JndiTemplate(); try { dataSource = (DataSource) jndi.lookup("java:comp/env/test.datasource"); } catch (NamingException e) { } return dataSource; } private Properties hibernateProperties() { Properties properties = new Properties(); properties.put("hibernate.dialect", "org.hibernate.dialect.Oracle8iDialect"); properties.put("hibernate.cache.provider_class", "org.hibernate.cache.NoCacheProvider"); properties.put("hibernate.current_session_context_class","thread"); properties.put("hibernate.show_sql", "false"); return properties; } }
-
And replace it with below mentioned YAML, substituting it with your configurations.
spring: datasource: er-class-oracle: jdbc: driver: OracleDriver jdbc:oracle:thin:@test-test-test.test.exampleonline.net:1234/qwer name: testUser word: testPassword jpa: base-platform: org.hibernate.dialect.Oracle12cDialect -sql: true rnate: ddl-auto: none
``
In above configuration, we have defined the DB URL, username, password and DB dialect. Also I’ve added configuration to display the SQL statements executed by Hibernate.
4. Swagger Changes
For swagger to work in Spring Boot we need to do below changes,
-
Migrate below dependencies
<dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> <version>${springfox.version}</version> </dependency> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger-ui</artifactId> <version>${springfox.version}</version> </dependency>
-
If Sprint Security is used, we need add below mentioned swagger URLs in exception list. Without these, Spring Boot Swagger URL won’t be able to open.
"/configuration/ui" , "/configuration/security" , "/swagger-resources" , "/v2/api-docs" , "/cot/v1/serviceParameters"), "/swagger-ui.html" , "/webjars/springfox-swagger-ui"
5. Change Transactional Annotation
If JPA is used in Spring MVC , then @Transactional
annotation might be used. While migrating from Spring to Spring Boot we need to replace Transactional
import statements everywhere in the application.
Change import statement
javax.transaction.Transactional;
to
import org.springframework.transaction.annotation.Transactional;
Issues
1. JPA Mixed strategy Issues
In Spring Boot, parameterized and numerical parameters cannot be used in same statement.
For example
"select TEST1 FROM TEST WHERE TEST.TEST_ID=? AND TEXT.TEXT_NAME =:testName"
This HQL statement needs to be changed to,
"select TEST1 FROM TEST WHERE TEST.TEST_ID=:testId AND TEXT.TEXT_NAME =:testName"
We can’t use different JPA strategies in Spring Boot.
2. @Lazy
annotation changes
For some entities we might get a cyclic error for some beans. To resolve this we would need to initialize the bean only when its actually required. To do this, mark these beans as @Lazy
.
These are the main steps and challenges I faced when I migrated an application from Spring MVC to Spring Boot.
The number features of Spring MVC you have in your project, the more challenges you will face. Please comment below if there any any other issues other the once mentioned that you found while migrating from Spring to Spring Boot.