Spring Core: IoC & Dependency Injection
Spring: IoC & Dependency Injection Spring's IoC (Inversion of Control) container manages object creation and lifecycle. Beans are objects managed by Spring. Dep…
Spring: IoC & Dependency Injection
Spring's IoC (Inversion of Control) container manages object creation and lifecycle. Beans are objects managed by Spring. Dependency Injection wires dependencies automatically — you declare what you need, Spring provides it.
Bean Annotations
// @Component and its specializations
@Component // generic Spring-managed bean
@Service // business logic layer (semantic alias of @Component)
@Repository // data access layer — also translates SQL exceptions
@Controller // MVC web controller
@RestController // @Controller + @ResponseBody on all methods
// Configuration class — defines beans explicitly
@Configuration
public class AppConfig {
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder(12);
}
@Bean
@Primary // preferred when multiple implementations exist
public DataSource primaryDataSource() {
return DataSourceBuilder.create()
.url("jdbc:postgresql://localhost/mydb")
.build();
}
}Dependency Injection
// Constructor injection — RECOMMENDED
@Service
public class UserService {
private final UserRepository userRepository;
private final EmailService emailService;
// Spring automatically injects — @Autowired optional since Spring 4.3
public UserService(UserRepository userRepository, EmailService emailService) {
this.userRepository = userRepository;
this.emailService = emailService;
}
}
// Field injection — discouraged (hard to test, hides dependencies)
@Autowired
private UserRepository userRepository; // avoid this
// Qualifier — when multiple beans implement the same interface
@Service
public class NotificationService {
public NotificationService(
@Qualifier("emailNotifier") Notifier emailNotifier,
@Qualifier("smsNotifier") Notifier smsNotifier) { }
}
// Optional injection
@Autowired(required = false)
private MetricsService metricsService; // null if not in contextBean Scopes & Lifecycle
// Scopes
@Scope("singleton") // default — one instance per container
@Scope("prototype") // new instance every time injected
@Scope("request") // one per HTTP request (web apps)
@Scope("session") // one per HTTP session (web apps)
// Lifecycle callbacks
@Component
public class CacheManager {
@PostConstruct // called after DI is complete
public void init() {
loadCache();
}
@PreDestroy // called before bean is removed from context
public void cleanup() {
flushCache();
}
}
// Conditional beans
@Bean
@ConditionalOnProperty(name = "feature.email", havingValue = "true")
public EmailService emailService() { return new SmtpEmailService(); }
@Bean
@Profile("development")
public DataSource h2DataSource() { return new EmbeddedDatabaseBuilder().build(); }
@Bean
@Profile("production")
public DataSource postgresDataSource() { /* ... */ }ApplicationContext & Events
// Access context directly (use sparingly — prefer constructor injection)
@Component
public class BeanFactory implements ApplicationContextAware {
private ApplicationContext context;
@Override
public void setApplicationContext(ApplicationContext ctx) {
this.context = ctx;
}
public <T> T getBean(Class<T> type) { return context.getBean(type); }
}
// Application events — decoupled communication
// Publish
@Service
public class UserService {
private final ApplicationEventPublisher eventPublisher;
public void createUser(User user) {
userRepository.save(user);
eventPublisher.publishEvent(new UserCreatedEvent(this, user));
}
}
// Listen
@Component
public class WelcomeEmailListener {
@EventListener
@Async // handle in separate thread
public void onUserCreated(UserCreatedEvent event) {
emailService.sendWelcome(event.getUser());
}
}