Spring Boot 3 Essentials: Lifecycle, Bean Creation, Validation & More
This article presents a comprehensive collection of over 50 Spring Boot 3 practical examples, covering core topics such as the Lifecycle and SmartLifecycle interfaces, custom FactoryBean implementations, graceful shutdown in non‑web environments, resource injection, parameter validation, and type conversion techniques.
Spring Boot 3 Practical Cases Collection – more than 50 curated articles that demonstrate advanced usage of Spring Boot features.
1. Lifecycle Interface
The Lifecycle interface defines start/stop lifecycle control methods. It allows beans or the container (usually the ApplicationContext ) to implement start and stop operations.
<code>public interface Lifecycle {
// executed before the Spring container starts
void start();
// executed when the Spring container is shutting down
void stop();
// indicates whether the component is currently running
boolean isRunning();
}</code>Note: The standard org.springframework.context.Lifecycle is a simple contract for explicit start/stop notifications and does not trigger automatic start on context refresh. For finer control, implement org.springframework.context.SmartLifecycle .
Example implementation:
<code>public class PackLifecycle implements SmartLifecycle {
private volatile boolean running;
@Override
public void start() {
this.running = true;
System.out.println("lifecycle start ... ");
}
@Override
public void stop() {
this.running = false;
System.out.println("lifecycle stop ... ");
}
@Override
public boolean isRunning() {
return running;
}
}</code>2. FactoryBean Interface
Implement FactoryBean when you need full control over bean instantiation.
T getObject() : returns the created object instance (may be shared).
boolean isSingleton() : true if the factory returns a singleton.
Class<?> getObjectType() : returns the type of object produced.
Example:
<code>public class User {}
@Component("user")
public class UserFactoryBean implements FactoryBean<User> {
@Override
public User getObject() throws Exception {
return new User();
}
@Override
public Class<?> getObjectType() {
return User.class;
}
}
</code>Injecting the produced User bean:
<code>@Resource
private User user;</code>Accessing the factory itself (note the leading & in the bean name):
<code>try (GenericApplicationContext context = new GenericApplicationContext()) {
System.out.println(context.getBean("&user"));
}</code>3. Graceful Shutdown in Non‑Web Environments
Register a JVM shutdown hook to ensure proper bean destruction:
<code>public class User implements DisposableBean {
@Override
public void destroy() throws Exception {
System.out.println("User Object destroy...");
}
}
public static void main(String[] args) {
GenericApplicationContext context = new GenericApplicationContext();
context.registerBean(User.class);
// Starts a thread that invokes onClose, allowing lifecycle methods to run
context.registerShutdownHook();
context.refresh();
}
// Console output (if registerShutdownHook is called):
// User Object destroy...</code>In Spring Boot, registerShutdownHook() is invoked automatically.
4. Resource Injection
Inject resources directly with @Value :
<code>@Value("${pack.images:file:///d:/images/1.png}")
private Resource res;
@GetMapping("/res0")
public void res0(HttpServletResponse response) throws Exception {
response.setContentType("image/png");
StreamUtils.copy(res.getInputStream(), response.getOutputStream());
}</code>Inject an array of resources:
<code>@Component
public class PackResource {
private final Resource[] templates;
public PackResource(@Value("${pack.templates.path}") Resource[] templates) {
this.templates = templates;
}
}
</code>Configuration example:
<code>pack:
templates:
path: classpath*:com/pack/templates/*.ftl</code>Implement ResourceLoaderAware when you only need the ResourceLoader interface:
<code>@Component
public class PackResourceLoader implements ResourceLoaderAware {
@Override
public void setResourceLoader(ResourceLoader resourceLoader) {
Resource resource = resourceLoader.getResource("classpath:com/pack/templates/1.txt");
System.out.println(StreamUtils.copyToString(resource.getInputStream(), StandardCharsets.UTF_8));
}
}
</code>5. Parameter Validation
Typical usage in a controller method:
<code>@PostMapping("")
public Object save(@Validated @RequestBody User user, BindingResult errors) {
// TODO
}
</code>In any managed bean, inject Validator and invoke it manually:
<code>private final Validator validator;
public UserService(Validator validator) {
this.validator = validator;
}
public void save(User user) {
Errors errors = new BeanPropertyBindingResult(user, "user");
validator.validate(user, errors);
if (errors.hasErrors()) {
// handle errors
}
}
</code>When not using Spring Boot, register a LocalValidatorFactoryBean manually:
<code>@Bean
public LocalValidatorFactoryBean validator() {
return new LocalValidatorFactoryBean();
}
</code>6. Type Conversion
Use ConversionService for explicit type conversion, which is auto‑configured in Spring Boot and can be injected into any bean.
<code>private final ConversionService conversionService;
public PackComponent(ConversionService conversionService) {
this.conversionService = conversionService;
}
public Object convert(Object source, Class<?> targetType) {
if (source == null || targetType == null) {
throw new IllegalArgumentException("Source or target type cannot be null");
}
return conversionService.convert(source, targetType);
}
</code>These six sections provide a solid foundation for mastering Spring Boot 3 advanced features.
Spring Full-Stack Practical Cases
Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.