Gradle is a powerful and flexible build automation system that uses a Groovy-based DSL (Domain Specific Language) or Kotlin-based DSL for defining build tasks. It was designed to overcome the shortcomings of Apache Ant and Apache Maven, and it is widely adopted in the Java community, as well as in Android app development.
Here’s a breakdown of Gradle’s key features and how it works:
build.gradle
.gradlew
on UNIX-like systems or gradlew.bat
on Windows). This is a small script that can download and install the correct version of Gradle for a project, ensuring consistent builds across different environments.How does it work?
Gradle is a versatile tool that can be used not only for Java projects but also for C++, Python, and more. It has integrations with many IDEs (like IntelliJ IDEA and Android Studio) and CI/CD tools, making it a popular choice for modern development environments.
How to run tests using gradle?
in maven -> mvn test
gradle test or ./gradlew test
How to compile java project using gradle?
in maven -> mvn compile
gradle compileJava or ./gradlew compileJava
How to package a springboot project using gradle?
in maven -> mvn package
gradle jar or ./gradlew jar
How to skip tests using gradle?
in maven -> mvn install -DskipTests
gradle assemble -x test or ./gradlew assemble -x test
How to list dependencies using gradle?
in maven -> mvn dependency:list
gradle dependencies or ./gradlew dependencies
Including a dependency in a Gradle project with Spring Boot typically involves adding the dependency to the build.gradle
file. Here’s a step-by-step process:
Ensure You Have the Spring Boot Gradle Plugin:
First, make sure your build.gradle
file applies the Spring Boot Gradle plugin and has the Spring Boot dependencies’ BOM (Bill Of Materials):
plugins { id 'org.springframework.boot' version '2.5.4' // Use the appropriate version id 'io.spring.dependency-management' version '1.0.11.RELEASE' // Again, ensure the version matches your needs id 'java' }
Include the Spring Boot Repositories (if not already added):
Spring Boot dependencies are available in the Maven Central repository, but if you’re using Spring Milestone or Snapshot releases, you might also need the Spring repositories:
repositories { mavenCentral() // For milestone releases maven { url 'https://repo.spring.io/milestone' } // For snapshots maven { url 'https://repo.spring.io/snapshot' } }
Add Your Dependency:
Let’s say you want to include Spring Web to create a web application. You would add:
dependencies { implementation 'org.springframework.boot:spring-boot-starter-web' // ... your other dependencies }
Note:
implementation
is a configuration indicating that the dependency is required for compiling the source code of the module and is also required at runtime.'group:artifact:version'
, but when using the Spring Boot BOM, you often don’t need to specify the version since it’s managed by Spring Boot’s dependency management.
Refresh Your Dependencies:
If you’re using an IDE like IntelliJ IDEA or Eclipse, you might need to refresh your project to download the new dependencies. For command-line builds, the next time you run a Gradle task like ./gradlew bootRun
, the dependencies will be fetched automatically.
Additional Tip:
To view all the managed versions and dependencies provided by Spring Boot, you can check the spring-boot-dependencies
BOM in the Maven Central repository. It’s a useful reference when you want to know the default versions for various libraries that Spring Boot manages.
Remember, the versions and dependencies might vary based on the specific version of Spring Boot you’re using, so always refer to the official Spring Boot documentation or the Spring Initializr website for accurate information.
In a standard application without dependency injection, components and services often create or look up their dependencies. This creates tight coupling between components and makes them harder to test or reuse. With DI, components declare their dependencies (typically via constructor arguments, properties, or annotations), and a container or framework (like Spring) provides those dependencies. This helps in:
@Service public class OrderService { private final UserRepository userRepository; @Autowired public OrderService(UserRepository userRepository) { this.userRepository = userRepository; } // Other methods }
Note: In modern Spring versions, if a class has a single constructor, the @Autowired
annotation can be omitted, and Spring will use that constructor by default.
@Service public class OrderService { private UserRepository userRepository; @Autowired public void setUserRepository(UserRepository userRepository) { this.userRepository = userRepository; } // Other methods }
@Service public class OrderService { @Autowired private UserRepository userRepository; // Other methods }
@Qualifier
annotation.
@Service public class OrderService { private final DataSource dataSource; @Autowired public OrderService(@Qualifier("mainDataSource") DataSource dataSource) { this.dataSource = dataSource; } // Other methods }
Car
) object that creates its own engine (Engine
) instance.
public class Engine { public void start() { // Start engine } } public class Car { private Engine engine; public Car() { this.engine = new Engine(); } }
In the example above, the Car
class is tightly coupled to a specific Engine
. This makes it challenging to replace Engine
with a different implementation or to mock the engine during testing.
public class Car { private Engine engine; public Car(Engine engine) { this.engine = engine; } }
Here, the Car
doesn’t create its Engine
. Instead, it’s supplied with an engine. This makes it possible to provide different engine implementations or mock engines for testing.
<!-- Spring XML Configuration --> <bean id="engine" class="com.example.Engine" /> <bean id="car" class="com.example.Car"> <constructor-arg ref="engine"/> </bean>
@Component public class Engine { @PostConstruct public void initialize() { // Initialization code } @PreDestroy public void cleanup() { // Cleanup code } }
In essence, IoC flips the traditional flow of control. Instead of objects controlling their own dependencies, a container or framework takes on the responsibility. This inversion leads to software that’s more modular, easier to test, and more resilient to change.
Here, the initialize
method is called after the Engine
bean is created, and cleanup
is called before it’s destroyed.
The IoC container receives metadata from XML files, annotations, or Java configuration classes, and then uses this metadata to create and manage the lifecycle of the beans. The main tasks of the IoC container are:
There are two primary types of IoC containers in Spring:
BeanFactory
. It provides additional features such as event propagation, declarative mechanisms to create a bean, integration with AOP (Aspect-Oriented Programming), and more. In most Spring-based applications (including Spring Boot apps), ApplicationContext
is used more often than BeanFactory
.Spring Boot simplifies the use of the IoC container by eliminating most of the boilerplate configuration. With features like auto-configuration and component scanning, Spring Boot makes it easier to create, wire, and manage beans with minimal explicit configuration.
@Component public class HelloWorld { public String sayHello() { return "Hello, World!"; } }
@Service public class MessageService { private final HelloWorld helloWorld; @Autowired public MessageService(HelloWorld helloWorld) { this.helloWorld = helloWorld; } public void showMessage() { System.out.println(helloWorld.sayHello()); } }
@SpringBootApplication public class MyApp { public static void main(String[] args) { ApplicationContext context = SpringApplication.run(MyApp.class, args); MessageService messageService = context.getBean(MessageService.class); messageService.showMessage(); } }
@SpringBootApplication
annotation?@Configuration
, @EnableAutoConfiguration
, and @ComponentScan
.banner.txt
file in the src/main/resources
directory or setting a banner.location
property.@Value
annotation or by injecting the Environment
object.application.properties
and application.yml
:
src/main/resources
).application-dev.properties
for a dev
profile).application.properties
application.properties
or application.yml
in the jar (lowest precedence).SPRING_DATASOURCE_URL
would map to the spring.datasource.url
property in the application.@Value
Annotation:
@Value("${property.name}")
annotation.
@Value("${custom.property}") private String customProperty;
@Value
annotation, you can bind properties to POJOs annotated with @ConfigurationProperties
. This method is type-safe and offers additional benefits like validation and code-completion in IDEs.
@ConfigurationProperties(prefix="custom") public class CustomProperties { private String property; // getters and setters }
${another.property}
).spring.datasource.url
, spring.datasource-url
, SPRING_DATASOURCE_URL
, and spring.datasource_url
would all match the spring.datasource.url
property.spring.profiles.active
property (e.g., in application.properties
or as a command-line argument).SPRING_PROFILES_ACTIVE
environment variable.SpringApplication.setAdditionalProfiles(...)
method programmatically.application-dev.properties
will only be applied when the dev
profile is active.application-dev.yml
.@Profile
annotation:
@Profile("dev") @Bean public DataSource dataSource() { return new EmbeddedDatabaseBuilder().build(); }
cloud
profile that’s used for any cloud provider and a aws
profile that’s specific to AWS. You can activate both profiles simultaneously.default
profile will be used.@Profile("!prod") @Bean public DataSource dataSource() { // This bean will be created when the 'prod' profile is NOT active }
java -jar myapp.jar --spring.profiles.active=prod
spring.profiles.active
property./health
, /info
, /metrics
, /env
.@EntityScan
?SpringApplication.run()
method.server.*
properties (e.g., server.port
).@RepositoryRestResource
?spring-boot-starter-aop
.application.properties
or application.yml
.@RestController
vs @Controller
.@RestController
is a shorthand for @Controller
+ @ResponseBody
.@EnableTransactionManagement
and by using @Transactional
on methods.@ControllerAdvice
and @ExceptionHandler
.spring-boot-starter-test
with utilities like MockMvc
.spring-boot-maven-plugin
.@ComponentScan(excludeFilters = @Filter)
.application.properties
?spring.config.location
property.server.port
in application.properties
.@Conditional
It indicates a component is only eligible for registration when a specific condition matches.@SpringBootTest
?SpringApplication
and loads all registered beans.@SpringBootTest
is an annotation provided by Spring Boot that is used for integration testing. It helps to bootstrap the entire container (depending on the provided configuration), so you can test the application in scenarios close to the actual use.Features of @SpringBootTest
:
Examples of using @SpringBootTest
:
@SpringBootTest class MyApplicationTests { @Test void contextLoads() { } }
This test ensures that the application context loads without any issues.
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) class MyWebApplicationTests { @Autowired TestRestTemplate restTemplate; @Test void testHomeEndpoint() { String response = restTemplate.getForObject("/", String.class); assertEquals("Hello World", response); } }
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK) class MyWebMockTest { @Autowired MockMvc mockMvc; @Test void testEndpoint() throws Exception { mockMvc.perform(MockMvcRequestBuilders.get("/")) .andExpect(status().isOk()) .andExpect(content().string("Hello World")); } }
@SpringBootTest(properties = {"custom.property=value"}) class PropertyOverrideTest { //... }
@ActiveProfiles
: To activate certain profiles during testing, you can combine it with @ActiveProfiles
:
@SpringBootTest @ActiveProfiles("test") class MyProfileTest { //... }
The @SpringBootTest
annotation simplifies integration testing for Spring Boot applications by setting up and tearing down the application context and providing various utilities and configurations specific to the testing phase.
35. How can you serve static content in Spring Boot?
/public
, /resources
, /static
, or /META-INF/resources
directories.By default, Spring Boot serves static content from the following locations inside your project:
/META-INF/resources/
/resources/
/static/
/public/
For instance, if you place an index.html
file inside the src/main/resources/static/
directory of your Spring Boot application, you can access it by visiting http://localhost:8080/index.html
after starting your application.
If you want to customize the static content locations, you can do so by configuring the spring.resources.static-locations
property. For example, to serve static content from a custom-dir
directory:
spring.resources.static-locations=classpath:/custom-dir/
36. Describe the hierarchy of application.properties
in Spring Boot.
@TestPropertySource
, @SpringBootTest.properties
, and inside the JAR are examples of levels.
In Spring Boot, the application.properties
(or its YAML counterpart, application.yml
) file is the primary means for configuring application settings. Spring Boot provides a flexible system of looking for this configuration file in various locations and offers a hierarchy that determines the order of precedence for reading these configurations.
Here’s the hierarchy for application.properties
locations, starting from the highest precedence:
java -jar app.jar --server.port=8081
SPRING_APPLICATION_JSON
:
SPRING_APPLICATION_JSON
environment variable.-D
argument, e.g., java -Dserver.port=8081 -jar app.jar
server.port
can be sourced from an environment variable named SERVER_PORT
.application.properties
or application.yml
located in the same directory from which the application is run../config
sub-directory of the directory from which the application is run.application.properties
or application.yml
at the root of the classpath, typically inside the src/main/resources
directory./config
package or directory inside the jar.application.properties
or application.yml
located in the classpath root.SpringApplication.setDefaultProperties
.Profile-specific properties:
Along with the above, Spring Boot allows for profile-specific property files. These are named like application-{profile}.properties
or application-{profile}.yml
. Profile-specific property files have precedence over the default application.properties
or application.yml
but are ordered by the same precedence rules mentioned above.
For example, if a dev
profile is active, application-dev.properties
outside the jar will override the application.properties
outside the jar, but both will be overridden by any value passed as a command-line argument.
Conclusion: The hierarchy and the ability to source configurations from various locations allow for a high degree of flexibility. You can have default settings packaged within your application and override them for different environments using external files or even command-line arguments. This makes it easier to manage configurations across different deployment scenarios without changing the packaged application.
37. What is a Spring Boot Fat JAR?
38. What are the main advantages of using Spring Boot?
39. How do you enable debug logging in Spring Boot?
logging.level.root=DEBUG
in application.properties
.40. Explain the importance of the pom.xml
file in Spring Boot.
41. What’s the purpose of @EnableAutoConfiguration
?
42. How does Spring Boot simplify database connectivity?
spring-boot-starter-data-jpa
.application.properties
or application.yml
files.spring.datasource.url
, spring.datasource.username
, and spring.datasource.password
, you can configure a data source without any manual bean definitions.
spring.datasource.url=jdbc:mysql://localhost:3306/mydb spring.datasource.username=root spring.datasource.password=secret
spring.datasource.hikari.maximum-pool-size=10
EntityManager
.CrudRepository
or JpaRepository
and Spring Boot automatically provides the implementation at runtime, enabling CRUD operations on entities without writing the boilerplate code.schema.sql
and data.sql
) and run them at startup to initialize the database.schema.sql
in the src/main/resources
directory, Spring Boot will execute it on startup.schema.sql
:application-{profile}.properties
files can be used for different environments. This means you can have separate configurations for development, staging, and production, making it easy to switch between databases based on the active profile.JdbcTemplate
, making it easier to interact with relational databases without managing connections and exceptions manually.
@Autowired JdbcTemplate jdbcTemplate; public int getCountOfBooks() { return jdbcTemplate.queryForObject("SELECT COUNT(*) FROM book", Integer.class); }
DataAccessException
, making it easier to handle database-related errors in a consistent way.In essence, Spring Boot removes much of the boilerplate code traditionally associated with setting up and managing database connections in a Spring application. This allows developers to focus on their domain logic rather than the intricacies of database setup and connectivity.43. What is the importance of @Repository
in Spring Boot?
44. How can you specify the active profile while running a Spring Boot application?
--spring.profiles.active=myprofile
during startup.45. How can you secure a Spring Boot application?
spring-boot-starter-security
and @EnableWebSecurity
.First and foremost, you’ll need to add the Spring Security starter to your pom.xml
(if using Maven):
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency>
By merely including the above dependency, Spring Boot will set up basic authentication for all routes with a default user named “user” and a generated password that’s displayed in the console on startup.
Example: Accessing any endpoint without authentication will return a 401 Unauthorized
. Use the provided username and password in the request header or when prompted by the browser to authenticate.
You can configure user details and their roles in memory or retrieve them from a database.
Example – In-memory Authentication:
@Configuration public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.inMemoryAuthentication() .withUser("admin").password("{noop}admin123").roles("ADMIN") .and() .withUser("user").password("{noop}user123").roles("USER"); } }
You can specify which routes or endpoints are accessible by which roles.
@Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers("/admin/**").hasRole("ADMIN") .antMatchers("/user/**").hasAnyRole("ADMIN", "USER") .antMatchers("/").permitAll() .and().formLogin(); }
46. What is a CommandLineRunner
in Spring Boot?
47. Describe the structure of a typical Spring Boot project.
src/main/java
and resources in src/main/resources
.48. How can you customize the Jackson ObjectMapper in Spring Boot?
@Bean
of type ObjectMapper
in a configuration class.49. What are the benefits of using the Spring Boot DevTools?
50. What is spring-boot-starter-parent
?
Spring framework has a retry project that is very useful when you have a business logic failure that you want to be able to retry to complete.
<dependency> <groupId>org.springframework.retry</groupId> <artifactId>spring-retry</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency>
@Configuration @EnableRetry public class GlobalConfig { }
@Service @Slf4j public class UserServiceImp implements UserService { @Retryable(value = {RuntimeException.class}, maxAttempts = 3, backoff = @Backoff(delay = 2000)) @Override public boolean sendEmail(User user) throws RuntimeException { log.info("send email"); if (true) { throw new RuntimeException("error"); } return false; } @Recover @Override public boolean recover(RuntimeException e, User user) { log.info("recover"); return true; } }
Project Lombok is a java library that automatically plugs into your editor and build tools, spicing up your java.
Never write another getter or equals method again, with one annotation your class has a fully featured builder, Automate your logging variables, and much more.
Java can get too verbose for things you have to do such as generating getter and setter methods. These things often bring no real value to the business side of your applications. This is what lombok is for. Lombok is here to help you generate boilerplate code and you focus on business logic. The way it works is by plugging into your build process and autogenerating Java bytecode into your .class files as per a number of project annotations you introduce in your code.
Install Lombok on your computer
<dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency>
Use Lombok in your project
import java.io.Serializable; import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.UUID; import java.util.stream.Collectors; import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.EnumType; import javax.persistence.Enumerated; import javax.persistence.FetchType; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.Index; import javax.persistence.JoinColumn; import javax.persistence.JoinTable; import javax.persistence.Lob; import javax.persistence.ManyToMany; import javax.persistence.OneToOne; import javax.persistence.PrePersist; import javax.persistence.PreUpdate; import javax.persistence.Table; import javax.persistence.Temporal; import javax.persistence.TemporalType; import javax.validation.constraints.NotEmpty; import org.hibernate.annotations.CreationTimestamp; import org.hibernate.annotations.ResultCheckStyle; import org.hibernate.annotations.SQLDelete; import org.hibernate.annotations.Type; import org.hibernate.annotations.UpdateTimestamp; import org.hibernate.annotations.Where; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude.Include; import com.social.api.address.Address; import com.social.api.user.role.Role; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; import lombok.ToString; @Setter @Getter @ToString @AllArgsConstructor @NoArgsConstructor @JsonInclude(value = Include.NON_NULL) public class User implements Serializable { private static final long serialVersionUID = 1L; private Long id; private String firstName; private String lastName; private String email; private String password; private String phoneNumber; private Date dateOfBirth; private String aboutMe; private String profileImageUrl; private String coverImageUrl; private Date passwordExpirationDate; private Integer invalidPasswordCounter = 0; }
Create auth server and resource server
Create auth client that consumes resource from a third party like Google or Github