15 Practical Spring Framework Tips for Developers
This article presents fifteen useful Spring techniques—including bean retrieval, event handling, custom interceptors, retry mechanisms, global exception handling, startup initialization, bean lifecycle methods, resource cleanup, dynamic configuration injection, conditional bean registration, caching, transaction management, bean loading order, AOP aspects, and conditional bean creation—each illustrated with clear Java code examples.
1. Retrieve Spring Bean Instances
Implement ApplicationContextAware or BeanFactoryAware to obtain beans from the Spring container, typically by overriding setApplicationContext or setBeanFactory .
@Service
public class TianLuoService implements ApplicationContextAware {
private ApplicationContext context;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
context = applicationContext;
}
public void friedTianLuo() {
TianLuo tianluo = (TianLuo) context.getBean("tianluo");
tianluo.fried();
}
} @Service
public class TianLuoService implements BeanFactoryAware {
private BeanFactory beanFactory;
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
public void friedTianLuo() {
TianLuo tianluo = (TianLuo) beanFactory.getBean("tianluo");
tianluo.fried();
}
}2. Spring Observer Pattern
Define a custom event extending ApplicationEvent and a listener implementing ApplicationListener<MessageEvent> . Publish the event via ApplicationEventPublisher when needed.
public class MessageEvent extends ApplicationEvent {
public MessageEvent(Object source) { super(source); }
} @Component
public class MessageListener implements ApplicationListener
{
@Override
public void onApplicationEvent(MessageEvent event) {
System.out.println("User registration succeeded: " + event.getSource());
}
} @RestController
public class UserController implements ApplicationContextAware {
@Autowired private UserService userService;
@Autowired private ApplicationEventPublisher publisher;
@RequestMapping("springListenRegister")
public String springListenRegister(UserParam param) {
userService.addUser(param);
publisher.publishEvent(new MessageEvent("666"));
return "SUCCESS";
}
}3. Custom Interceptor
Implement HandlerInterceptor to intercept requests, then register it via WebMvcConfigurer .
@Component
public class CustomInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
System.out.println("Request URL: " + request.getRequestURL());
System.out.println("Request Method: " + request.getMethod());
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView mv) {
System.out.println("Response Status: " + response.getStatus());
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
System.out.println("Request Completed");
}
} @Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired private CustomInterceptor customInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(customInterceptor).addPathPatterns("/**");
}
}4. @Retryable for Automatic Retries
Use @Retryable to retry a method on specified exceptions, configuring attempts and back‑off policy.
@Retryable(value = {IOException.class}, maxAttempts = 5, backoff = @Backoff(delay = 1000))
public void processFile() throws IOException {
// simulated file processing that may throw IOException
}5. Global Exception Handling with @RestControllerAdvice
Centralize exception handling by annotating a class with @RestControllerAdvice and defining @ExceptionHandler methods.
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(ArithmeticException.class)
public ResponseEntity
handleArithmetic(ArithmeticException ex) {
return new ResponseEntity<>("Error: Division by zero is not allowed!", HttpStatus.BAD_REQUEST);
}
@ExceptionHandler(IllegalArgumentException.class)
public ResponseEntity
handleIllegalArg(IllegalArgumentException ex) {
return new ResponseEntity<>("Error: " + ex.getMessage(), HttpStatus.BAD_REQUEST);
}
@ExceptionHandler(Exception.class)
public ResponseEntity
handleOther(Exception ex) {
return new ResponseEntity<>("Internal server error: " + ex.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
}
}6. Startup Parameter Initialization & Cache Warm‑up
Implement CommandLineRunner or ApplicationRunner to execute code when the application starts.
@Component
public class CachePreloader implements CommandLineRunner {
@Override
public void run(String... args) {
System.out.println("Preloading cache...");
// cache loading logic here
}
}7. Common Bean Initialization Methods
Use @PostConstruct , implement InitializingBean , or specify initMethod in @Bean definitions.
@Component
public class MyBean {
@PostConstruct
public void init() { System.out.println("Bean initialized via @PostConstruct"); }
} @Component
public class MyBean implements InitializingBean {
@Override
public void afterPropertiesSet() { System.out.println("Bean initialized via InitializingBean"); }
} @Configuration
public class AppConfig {
@Bean(initMethod = "init")
public MyBean myBean() { return new MyBean(); }
}
public class MyBean { public void init() { System.out.println("Bean initialized via initMethod"); } }8. Actions Before Container Shutdown
Implement DisposableBean or annotate a method with @PreDestroy to release resources.
@Component
public class MyResource implements DisposableBean {
@Override
public void destroy() { System.out.println("Resource released during shutdown"); }
} @Component
public class MyResource {
@PreDestroy
public void cleanup() { System.out.println("Resource released using @PreDestroy"); }
}9. Dynamic Configuration Injection with @Value
Inject properties from application.properties or application.yml into bean fields using @Value .
# application.properties
app.name=MySpringApp
app.version=1.0.0
app.description=This is a simple Spring application. @Component
public class AppConfig {
@Value("${app.name}") private String appName;
@Value("${app.version}") private String appVersion;
}10. Dynamic Bean Injection
Use @Autowired with @Qualifier or @Resource to inject specific beans.
@Component
public class ServiceA { public void execute() { System.out.println("ServiceA executed"); } }
@Component
public class ServiceB { public void execute() { System.out.println("ServiceB executed"); } }
@Component
public class ClientService {
private final ServiceA serviceA;
@Autowired
public ClientService(@Qualifier("serviceA") ServiceA serviceA) { this.serviceA = serviceA; }
public void doSomething() { serviceA.execute(); }
} @Component
public class MyService {
@Resource(name = "myBean") private MyBean myBean;
public void doSomething() { myBean.execute(); }
}11. Local Caching with @Cacheable
Configure a cache manager (e.g., Caffeine) and annotate methods with @Cacheable to store results.
@Configuration
@EnableCaching
public class CacheConfig {
@Bean
public CacheManager cacheManager() {
CaffeineCacheManager cm = new CaffeineCacheManager("book");
cm.setCaffeine(caffeineCacheBuilder());
return cm;
}
Caffeine
caffeineCacheBuilder() {
return Caffeine.newBuilder().maximumSize(500).expireAfterWrite(10, TimeUnit.MINUTES);
}
} @Cacheable("book")
public BookVO queryBookById(Integer bookId) {
BookPO po = bookRepository.queryBookById(bookId);
BookVO vo = new BookVO();
BeanUtils.copyProperties(po, vo);
log.info("Query book: {}", bookId);
return vo;
}12. Transaction Management
Programmatic transactions use TransactionTemplate ; declarative transactions use @Transactional .
@Service
public class UserService {
@Autowired private UserRepository repo;
@Autowired private PlatformTransactionManager tm;
public void createUserWithProgrammingStyle(User user) {
TransactionTemplate tt = new TransactionTemplate(tm);
tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
tt.execute(status -> { repo.save(user); return null; });
}
@Transactional
public void createUserWithDeclarativeStyle(User user) { repo.save(user); }
}13. Specifying Bean Loading Order
Use @DependsOn to declare dependencies or @Order / Ordered to set explicit order.
@Component
@DependsOn("beanB")
public class BeanA { }
@Component
public class BeanB { } @Component
@Order(1)
public class BeanE { }
@Component
@Order(2)
public class BeanF { }14. Aspect‑Oriented Programming with @Aspect
Define an aspect class with @Before and @After advices to log method execution.
@Aspect
@Component
public class LoggingAspect {
@Before("execution(* com.example.demo.service.MyService.performTask(..))")
public void logBefore() { System.out.println("Before executing performTask()"); }
@After("execution(* com.example.demo.service.MyService.performTask(..))")
public void logAfter() { System.out.println("After executing performTask()"); }
}15. Conditional Bean Registration with @Conditional
Apply @Conditional on @Bean methods to load beans only when custom conditions are met.
@Configuration
public class ServiceConfig {
@Bean
@Conditional(DatabaseServiceCondition.class)
public DatabaseService databaseService() { return new DatabaseService(); }
@Bean
@Conditional(MessageServiceCondition.class)
public MessageService messageService() { return new MessageService(); }
}IT Services Circle
Delivering cutting-edge internet insights and practical learning resources. We're a passionate and principled IT media platform.
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.