Introduction
Annotation-driven development has revolutionized Java development by providing a declarative way to configure and manage application components. In this article, I'll explore how to implement annotation support in a Spring-like framework, based on my miniSpring project's implementation.
Core Components
The annotation support implementation consists of several key components:
src/com/yaruyng/ ├── beans/factory/annotation/ │ ├── AutowiredAnnotationBeanPostProcessor.java │ └── Autowired.java └── web/ ├── RequestMapping.java └── method/
Annotation Processing Infrastructure
1. The Autowired Annotation
The @Autowired annotation is the foundation for dependency injection:
@Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface Autowired { }
Key features:
- Field-level annotation
- Runtime retention
- Simple and focused purpose
2. The AutowiredAnnotationBeanPostProcessor
The processor handle @Autowired annotation processing
public class AutowiredAnnotationBeanPostProcessor implements BeanPostProcessor { private BeanFactory beanFactory; @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { Object result = bean; Class<?> clazz = bean.getClass(); Field[] fields = clazz.getDeclaredFields(); if(fields != null) { for (Field field : fields) { boolean isAutowired = field.isAnnotationPresent(Autowired.class); if(isAutowired) { String fieldName = field.getName(); Object autowiredObj = this.getBeanFactory().getBean(fieldName); try { field.setAccessible(true); field.set(bean, autowiredObj); System.out.println("autowire " + fieldName + " for bean " + beanName); } catch (IllegalArgumentException | IllegalAccessException e) { e.printStackTrace(); } } } } return result; } }
Features:
- Field-level dependency injection
- Reflection-based processing
- Integration with bean lifecycle
Web Annotations
1. RequestMapping Annotation
The @RequestMapping annotation handles URL mapping:
@Target(value = {ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) public @interface RequestMapping { String value() default ""; }
Usage example
@Controller public class UserController { @RequestMapping("/users") public List<User> getUsers() { // Implementation } }
Annotation Processing Flow
1.Bean Post-Processing
The annotation processing happens during bean initialization:
public Object postProcessBeforeInitialization(Object bean, String beanName) { // 1. Get bean class Class<?> clazz = bean.getClass(); // 2. Get declared fields Field[] fields = clazz.getDeclaredFields(); // 3. Process each field for (Field field : fields) { // 4. Check for annotations if (field.isAnnotationPresent(Autowired.class)) { // 5. Get dependency Object dependency = getBeanFactory().getBean(field.getName()); // 6. Inject dependency field.setAccessible(true); field.set(bean, dependency); } } return bean; }
2.Request Mapping Processing
The request mapping processing happens during request handling:
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { // 1. Get handler method HandlerMethod handlerMethod = handlerMapping.getHandler(request); // 2. Execute handler ModelAndView mv = handlerAdapter.handle(request, response, handlerMethod); // 3. Render view render(request, response, mv); }
Implementation Details
1.Field Injection
private void injectDependency(Field field, Object bean, String beanName) { try { // 1. Get dependency name String fieldName = field.getName(); // 2. Get dependency from container Object dependency = getBeanFactory().getBean(fieldName); // 3. Make field accessible field.setAccessible(true); // 4. Set dependency field.set(bean, dependency); System.out.println("autowire " + fieldName + " for bean " + beanName); } catch (Exception e) { e.printStackTrace(); } }
2. Request Mapping Resolution
public HandlerMethod getHandler(HttpServletRequest request) { String requestURI = request.getRequestURI(); String method = request.getMethod(); // Find matching handler method for (HandlerMethod handler : handlerMethods) { RequestMapping mapping = handler.getMethodAnnotation(RequestMapping.class); if (mapping != null && mapping.value().equals(requestURI)) { return handler; } } return null; }
Usage Example
1.Dependency Injection
@Service public class UserService { @Autowired private UserRepository userRepository; @Autowired private EmailService emailService; public void createUser(User user) { userRepository.save(user); emailService.sendWelcomeEmail(user); } }
2.Request Mapping
@Controller @RequestMapping("/api/users") public class UserController { @Autowired private UserService userService; @RequestMapping("/{id}") public User getUser(@PathVariable Long id) { return userService.findById(id); } }
Key Features
1.Dependency Injection
- Field-level injection
- Constructor injection support
- Circular dependency handling ### 2.Request Mapping
- URL pattern matching
- HTTP method support
- Path variable handling ### 3. Annotation Processing
- Runtime processing
- Reflection-based implementation
- Extensible design
Best Practices
1.Annotation Design
- Clear and focused purpose
- Runtime retention when needed
- Proper target specification ### 2.Processing Implementation
- Efficient reflection usage
- Proper exception handling
- Resource cleanup ### 3.Integration
- Clean integration with IoC
- Proper lifecycle management
- Performance optimization
Common Challenges and Solutions
1.Circular Dependencies
- Lazy initialization
- Constructor injection
- Dependency resolution ### 2.Performance
- Annotation caching
- Reflection optimization
- Resource management ### 3.Error Handling
- Clear error messages
- Proper exception propagation
- Recovery mechanisms
Conclusion
Implementing annotation support provides:
- Declarative configuration
- Clean and maintainable code
- Flexible dependency management
- Simplified request handling
Key takeaways:
- Understanding annotation processing
- Dependency injection patterns
- Request mapping mechanisms
- Performance optimization techniques
This implementation demonstrates how to create a robust annotation-driven framework while maintaining simplicity and flexibility.
Top comments (0)