Spring Boot
Spring Boot
Autowiring in spring
Autowiring is a powerful feature in the Spring framework that automatically
injects dependencies into beans. It simplifies configuration and reduces
boilerplate code, making Spring applications more concise and maintainable.
Autowiring can’t be used to inject primitive and string values. It works with
reference only.
Benefits:
Reduced boilerplate code – Eliminates the need for manual setter
injection.
Improved maintainability – Makes code cleaner and easier to
understand.
Increased flexibility – Allows for automatic dependency injection based
on various criteria.
Reduced errors – Helps prevent typos and configuration mistakes.
Types of autowiring:
byName – Injects the bean with the same name as the property to be
autowired.
public class MyClass {
@Autowired
private MyDependency dependency;
}
byType – Injects the bean with the same type as the property to be
autowired.
public class MyClass {
@Autowired
private MyDependency dependency;
}
@Autowired
Student(Address address) {
this.address =
address;
}
}
Setter injection
class Student {
Address address;
@Autowired
void setaddress(Address address)
{
this.address = address;
}
}
@Autowired
@Qualifier("secondaryDataSource")
private DataSource secondaryDataSource;
}
@Bean
@Primary
public DataSource primaryDataSource() {
// ... configure primary data source
}
@Bean
public DataSource secondaryDataSource() {
// ... configure secondary data source
}
}
@Bean
public MyService myService() {
return new MyService();
}
@Bean
public MyRepository myRepository(MyDataSource dataSource) {
return new MyRepository(dataSource);
}
@Bean
public MyDataSource myDataSource() {
// Configure and return MyDataSource instance
}
}
@Bean
@Lazy
public MyExpensiveService myExpensiveService() {
// ... configure and return MyExpensiveService instance
}
}
// ...
}
@Component
@Scope("prototype") // Create a new instance for each request
public class MyBean {
// ...
}
Context Configuration Annotations
@Profile – Provides a powerful way to manage different configurations
and bean definitions for distinct environments. Controls which bean are
registered in the application context based on the active profile(s).
Enables you to create tailored configurations for different
environments. Common uses – environment specific configurations,
disabling bean for certain environments, testing different
configurations.
CONFIGURATION CLASS:
@Configuration
public class AppConfig {
@Bean
@Profile("dev")
public DataSource devDataSource() {
// Create development DataSource
}
@Bean
@Profile("prod")
public DataSource prodDataSource() {
// Create production DataSource
}
}
APPLICATION.PROPERTIES FILE
# Common configuration for all environments
APPLICATION-DEV.PROPERTIES FILE
spring.profiles.active=dev
# Development-specific configuration
APPLICATION-PROD.PROPERTIES FILE
spring.profiles.active=prod
# Production-specific configuration
@Import
@ImportResource
@PropertySource, etc.
Spring Web Annotations: Spring annotations present in the
org.springframework.web.bind.annotation package are commonly known as
Spring Web annotations. Some of the annotations that are available in this
category are:
@RequestMapping – The @RequestMapping annotation is a
cornerstone for defining how incoming HTTP requests are mapped to
specific controller methods. Specifies the URL patterns and HTTP
method(s) that a controller method should handle. Routes requests to
appropriate controllers based on URL patterns and HTTP methods.
Supports various URL patterns and method restrictions for fine-grained
control.
@RestController
@RequestMapping("/api/users")
public class UserController {
@GetMapping("/users/{userId}")
public User getUser(@PathVariable int userId) {
// ...
if (userNotFound) {
throw new UserNotFoundException();
}
// ...
}
@ExceptionHandler(UserNotFoundException.class)
public ResponseEntity<ErrorResponse>
handleUserNotFound(UserNotFoundException ex) {
return new ResponseEntity<>(new ErrorResponse("User
not found"), HttpStatus.NOT_FOUND);
}
}
@ResponseStatus(HttpStatus.CREATED)
@PostMapping("/users")
public User createUser(@RequestBody User user) {
// ...
} // Will return 201
@Async
public void someLongRunningMethod() {
// Perform long-running task asynchronously
}
}
@Async
public void someLongRunningMethod() {
// Perform long-running task in a separate thread
}
}
@Scheduled – Marks method as scheduled tasks, ensuring their
automatic execution based on specified scheduling expressions.
Automates tasks for periodic execution, specific time-based events, or
delayed execution, streamlining background processes.
@SpringBootApplication
@EnableScheduling
public class MyApplication {
@Scheduled(fixedRate = 5000) // Execute every 5 seconds
public void scheduledTask() {
// Perform scheduled task
}
@Scheduled(cron = "0 0 12 * * ?") // Execute daily at noon
public void dailyTask() {
// Perform daily task
}
}
@Transactional
public User createUser(User user) {
// Create user record
user = userRepository.save(user);
// Send welcome email
emailService.sendWelcomeEmail(user);
// If any operation fails, the entire transaction
will be rolled back
return user;
}
}
@Id – Marks a field with an entity class as the primary key, unique
identifying each entity instance in the database. Spring Data relies on
@Id to correctly perform entity persistence, retrieval, and operations.
Spring Data supports various ID generation strategies – Auto-
generation, Manual assignment, or Custom strategies. @Id is used to
define foreign keys in entity relationships, mapping associations
between entities. Employ @EmbeddedId or @IdClass for entities with
composite primary keys.
@Transient – Marks a field within an entity class to be ignored by
Spring Data’s persistence mechanism. Fields annotated with
@Transient won’t be persisted to or retrieved from the database. Fields
that can be computed from other persisted data, fields used for internal
calculations or temporary data that don’t need permanent storage or
fields, fields containing sensitive information that shouldn’t be stored in
the database, and fields representing data managed externally, not
directly persisted by Spring Data.
@Entity
public class User {
@Id
private Long id;
@Transient
private String transientField; // Not persisted
}
Direct SQL Interaction: JDBC requires you to write and execute SQL
statements directly to interact with the database.
Manual Data Handling: You need to manually manage result sets,
convert data types, and map them to Java objects.
More Control: JDBC gives you granular control over database
interactions and query optimization, but at the cost of more code and
potential complexity.
Key Differences:
Abstraction Level: ORMs provide a higher level of abstraction, while
JDBC requires direct SQL interaction.
Object-Orientation: ORMs align with object-oriented programming
principles, while JDBC is more procedural.
Productivity: ORMs can streamline development and reduce
boilerplate code, especially for complex data models.
Performance: ORMs may have some overhead compared to
optimized JDBC, but they can also offer performance benefits through
caching and efficient query generation.
When to Choose:
ORM:
When working with complex data models and relationships.
When prioritizing development speed and maintainability.
When using a well-established ORM with a proven track record.
JDBC:
When needing maximum control over database interactions and
performance tuning.
When working with legacy systems or databases with limited ORM
support.
When having stringent performance requirements that might not be
met by an ORM.
@OneToMany(mappedBy = "book")
private List<Page> pages;
}
@Entity
public class Page {
@Id
private Long id;
// ... other fields
@ManyToOne
@JoinColumn(name = "book_id")
private Book book;
}
Navigation and Cascading:
Navigation: You can navigate between related entities using object
references: Book book = bookRepository.findById(1L); List<Page>
pages = book.getPages();
Cascading Operations: Spring Data JPA supports cascading
operations (e.g., saving, deleting) across related entities:
@OneToMany(cascade = CascadeType.ALL) private List<Page>
pages;
How do you handle lazy loading and eager loading of relationships in
Spring Data?
Lazy Loading:
Default Behavior: Relationships are loaded only when accessed using
getter methods or explicitly fetching them through methods like fetch().
Benefits: Reduces initial load time by fetching related data only when
needed, especially for large datasets.
Drawbacks: Can cause additional queries and performance overhead
when accessing relationships later.
Eager Loading:
Fetching Strategies: Override the default behavior using
FetchType.EAGER in relationship annotations like @OneToMany or
@ManyToOne.
Benefits: Pre-fetches related data alongside the main entity, eliminating
subsequent queries and potentially improving performance for
frequently accessed relationships.
Drawbacks: Increases initial load time and memory consumption due to
larger data retrieved.
Application.properties file:
All the application configurations are stored in application.properties or
application.yaml file as key-value pair.
Properties can be changes using the file:
Core properties
Cache properties
Mail properties
JSON properties
Data properties
Transaction properties
Data migration properties
Integration properties
Web properties
Templating properties
Server properties
Security properties
RSocket properties
Actuator properties
Devtools properties
Testing properties
@ControllerAdvice – It is used in Spring to define global controllers’ advice –
components that are applied to the entire application rather than a specific
controller. It’s often used for handling exceptions globally, providing model
attributes to all controllers, and more.