文章目录
手写一个@Autowired注解实现自动注入
众所周知,@Autowired
是 Spring
框架中的一个注解,用于自动装配(auto-wiring
)bean
。当你在一个 Spring
管理的 bean
中使用@Autowired
注解时,Spring
容器会在创建该 bean 的过程中自动寻找匹配的 bean
,并将其注入到被注解的字段、构造函数或者 setter 方法中。
我相信大家都用过@Autowired
,但是不少人对其实现原理和如何实现代码了知甚少。基于此,我们今天一起来手动实现一个@Autowired
注解。
@Autowired注解的作用
在开始之前,我们先来一起回顾一下,@Autowired
注解的主要作用。
- 自动注入依赖:通过
@Autowired
,你可以告诉Spring
容器,你需要某个类型的 bean,容器会自动找到合适的 bean 并注入到你的类中,无需手动查找和创建实例。 - 类型安全:
@Autowired
支持类型检查,这意味着如果容器中没有找到匹配的 bean,或者有多个同类型的bean
,Spring
将会抛出异常,从而帮助你确保依赖注入的正确性。 - 支持多种注入方式:
@Autowired
可以用于注入字段、setter
方法或者构造函数。这提供了灵活的配置选项,可以根据实际情况选择最适合的注入方式。 - 条件注入:通过结合使用
@Autowired
和其他注解(如@Qualifier
、@Primary
等),可以实现条件化的bean
注入,例如指定注入特定名称的bean或者在多个同类型bean
中选择一个优先级更高的bean
。 - 简化配置:使用
@Autowired
可以减少配置文件中的 bean 定义,使得代码更加简洁,提高了开发效率。
下面看一个简单的例子,假设你有一个UserService
类,它依赖于一个UserRepository
类的实例:
@Service
public class UserService {
private final UserRepository userRepository;
@Autowired
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
// ... 其他方法
}
在上面的代码中,UserService
类有一个构造函数,它接受一个UserRepository
类型的参数。通过在参数上使用@Autowired
注解,Spring
容器会在创建UserService
的实例时自动注入一个UserRepository
的实例。
@Autowired的实现原理
@Autowired
注解的实现原理涉及到Spring
框架的多个核心组件和过程。下面我们来简单的总结一下@Autowired
的基本实现原理。
- 注解处理:当
Spring
应用程序启动时,它会扫描类路径上的所有类,寻找带有@Autowired
注解的字段、构造函数和setter
方法。Spring
使用BeanPostProcessor
(特别是AutowiredAnnotationBeanPostProcessor
)来处理这些注解。 - 元数据收集:在处理
@Autowired
注解时,Spring
会收集相关的元数据,例如需要注入的bean
的类型或名称。如果使用了@Qualifier
注解,Spring
还会收集指定的 bean 名称。 - 依赖查找:一旦
Spring
识别出需要自动装配的依赖项,它会在应用程序上下文中查找匹配的bean
。Spring
会根据类型(或者类型和名称)来寻找合适的候选者。 - 候选者匹配:如果有多个同类型的 bean 可以作为依赖项,
Spring
会根据@Qualifier
注解或者@Primary
注解来选择一个合适的bean
。如果没有明确的选择,Spring
会抛出一个异常。 - 依赖注入:找到匹配的
bean
后,Spring
会在适当的时机(例如在bean
的构造函数中或者在setter
方法上调用)将依赖项注入到目标对象中。如果是字段注入,Spring
会使用反射来设置字段的值。 - 生命周期管理:一旦依赖项被注入,
Spring
容器会管理这些bean
的生命周期,包括创建、初始化、使用和销毁。这意味着Spring
会自动处理bean
的依赖关系,确保它们在使用时是可用的。 - 异常处理:如果在容器中找不到匹配的
bean
,或者存在多个候选者但没有明确的选择,Spring
会抛出NoSuchBeanDefinitionException
或AmbiguousBeanDefinitionException
异常,从而通知开发者存在配置问题。
手写一个@MyAutowired注解
根据上面的原理,我们来实现一个简单的@MyAutowired
注解,使其满足@Autowired
注解的一部分能力。
定义@MyAutowired注解
首先,我们定义@MyAutowired
注解,它将包含必要的元数据,并标记在需要自动注入的字段、构造函数或方法上。
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.METHOD})
public @interface MyAutowired {
// 可以添加@Qualifier支持
String value() default "";
}
创建注解处理器
接下来,我们需要创建一个BeanPostProcessor
的实现,它会在 Spring
容器启动时处理@MyAutowired
注解。
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.stereotype.Component;
import java.lang.reflect.Field;
import java.util.Map;
@Component
public class MyAutowiredAnnotationBeanPostProcessor implements BeanPostProcessor {
private final BeanDefinitionRegistry registry;
public MyAutowiredAnnotationBeanPostProcessor(BeanDefinitionRegistry registry) {
this.registry = registry;
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
Class<?> clazz = bean.getClass();
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
if (field.isAnnotationPresent(MyAutowired.class)) {
field.setAccessible(true);
MyAutowired autowired = field.getAnnotation(MyAutowired.class);
String beanNameToInject = autowired.value();
// 根据beanNameToInject获取bean,这里需要自定义查找逻辑
Object beanToInject = getBeanFromRegistry(beanNameToInject, field.getType());
if (beanToInject != null) {
field.set(bean, beanToInject);
}
}
}
return bean;
}
private Object getBeanFromRegistry(String beanName, Class<?> requiredType) {
// 自定义查找bean的逻辑,这里简化处理,直接使用类型查找
Map<String, Object> beansOfType = registry.getBeansOfType(requiredType);
if (!beansOfType.isEmpty()) {
return beansOfType.values().iterator().next();
}
return null;
}
}
集成自定义处理器
接下来,我们需要确保自定义的BeanPostProcessor
被 Spring
容器识别并使用。
import org.springframework.context.annotation.Configuration;
@Configuration
public class MyAutowiredConfig {
// 注册自定义的BeanPostProcessor
public MyAutowiredAnnotationBeanPostProcessor myAutowiredAnnotationBeanPostProcessor(BeanDefinitionRegistry registry) {
return new MyAutowiredAnnotationBeanPostProcessor(registry);
}
}
这个实现是非常简化的,也是仿写@Autowired
的,并借助 Spring
做了偷懒处理。它也没有处理多个候选 bean
的情况,也没有处理构造函数和方法的注入。在实际应用中,可能需要更复杂的逻辑来处理这些情况,并且需要确保自定义的注解处理器在 Spring
容器启动时被注册。
本文中的示例提供了一个基本的框架,大家可以根据实际需求进一步扩展和完善它。在实现过程中,需要大家深入了解 Spring
的工作机制,包括 bean
的生命周期、bean
的定义和注册过程,以及反射和注解的处理等。
总结
手动实现一个类似 Spring
框架中 @Autowired
注解的功能,涉及到多个步骤和对 Spring
核心机制的理解。下面是按照文章内容整理的详细总结:
@Autowired 主要功能
- 自动注入依赖:在不显式指定的情况下,
Spring
容器能自动查找并注入所需的bean
实例。 - 类型安全:确保注入的
bean
类型正确,否则抛出异常。 - 支持多种注入方式:字段、构造函数、
setter
方法。 - 条件注入:结合其他注解如
@Qualifier
和@Primary
进行更精确的注入控制。 - 简化配置:减少 XML 或其他配置文件中的冗余,提高开发效率。
@Autowired 实现原理
- 注解处理:
Spring
使用BeanPostProcessor
(特别是AutowiredAnnotationBeanPostProcessor
)处理@Autowired
注解。 - 元数据收集:收集被注解元素的类型和名称信息。
- 依赖查找:在上下文中寻找匹配的
bean
。 - 候选者匹配:根据
@Qualifier
或@Primary
选择具体bean
。 - 依赖注入:通过反射或调用
setter
方法注入bean
。 - 生命周期管理:
Spring
容器管理bean
的整个生命周期。 - 异常处理:当找不到匹配
bean
或存在多个候选者时抛出异常。
手写 @MyAutowired 注解
- 定义注解:使用
@Retention
和@Target
指定其运行时可见性和可应用于哪些元素。 - 创建处理器:实现
BeanPostProcessor
接口,重写postProcessBeforeInitialization
方法处理注解。 - 集成处理器:通过配置类注册自定义的
BeanPostProcessor
实现。
注意事项
- 实现中未处理多个候选
bean
的情况。 - 没有处理构造函数和方法的注入。
- 需要深入了解
Spring
的工作原理,包括bean
的生命周期、定义与注册,以及反射和注解处理。
通过上述步骤,可以构建一个简化的 @MyAutowired
实现,但要达到与 @Autowired
相同的功能和灵活性,还需要深入理解和扩展上述基础实现。
更多手写系列教程参考:《知识星球》
标签:Autowired,Spring,MyAutowired,bean,注解,复刻,注入 From: https://blog.csdn.net/weixin_68020300/article/details/140526978