书接上文
前面我们分析了Spring时如何找到某个目标类的所有注入点这一个核心逻辑,但还没又对核心注入方法inject
进行详细分析,下面我们就来详细分析Spring拿到所有的注入点之后,是如何实现注入的逻辑的。首先我们回到inject
方法。
public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
//获得注入点集合
Collection<InjectedElement> checkedElements = this.checkedElements;
//创建一个要迭代的注入点集合 elementsToIterate。如果 checkedElements 不为空,则使用它,否则使用 injectedElements。
Collection<InjectedElement> elementsToIterate =
(checkedElements != null ? checkedElements : this.injectedElements);
if (!elementsToIterate.isEmpty()) {
// 遍历每个注入点进行依赖注入
for (InjectedElement element : elementsToIterate) {
element.inject(target, beanName, pvs);
}
}
}
上面代码最核心的就是遍历InjectionMetadata中的this.checkedElements,也就是注入点集合。然后针对不同的element类型会调用不同的注入方法(在注册注入点时已经说到了这两种类型,分别是AutowiredFieldElement和AutowiredMethodElement)。具体实现注入的逻辑是调用的这段代码element.inject(target, beanName, pvs);
。然后对于不同的注入类型(属性注入和方法注入,它们是有不同的实现类的)
首先我们看字段注入的inject
源码:
//PropertyValues 对象,封装了要应用到目标对象的属性值
@Override
protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
//将成员对象强制转换为字段对象,表示要进行注入的字段
Field field = (Field) this.member;
//生名一个变量用于存储要注入的值
Object value;
//检查是否启用了缓存。如果启用了缓存,会尝试从缓存中获取已解析的字段值。如果缓存中不存在,会捕获 NoSuchBeanDefinitionException 异常,然后重新解析字段值。
if (this.cached) {
// 对于原型Bean,第一次创建的时候,也找注入点,然后进行注入,此时cached为false,注入完了之后cached为true
// 第二次创建的时候,先找注入点(此时会拿到缓存好的注入点),也就是AutowiredFieldElement对象,此时cache为true,也就进到此处了
// 注入点内并没有缓存被注入的具体Bean对象,而是beanName,这样就能保证注入到不同的原型Bean对象
try {
//尝试从缓存中获取已解析的字段值。如果缓存中存在,则使用该值。否则,会重新调用 resolveFieldValue 方法解析字段值。
value = resolvedCachedArgument(beanName, this.cachedFieldValue);
}
catch (NoSuchBeanDefinitionException ex) {
//如果没有启用缓存,或者缓存中没有有效的值,将调用 resolveFieldValue 方法从 BeanFactory 中解析字段值。
value = resolveFieldValue(field, bean, beanName);
}
}
else {
// 根据filed从BeanFactory中查到的匹配的Bean对象
value = resolveFieldValue(field, bean, beanName);
}
// 反射给filed赋值
if (value != null) {
ReflectionUtils.makeAccessible(field);
field.set(bean, value);
}
}
这段代码主要处理了字段注入的逻辑,包括缓存的使用、字段值的解析和反射赋值。这是 Spring 框架实现自动装配的一部分,确保依赖关系得到正确地建立。当我们缓存中没有我们要注入的有效值,或者是压根就没有缓存时,会调用 resolveFieldValue(field, bean, beanName);
从BeanFactory中解析字段。
@Nullable
private Object resolveFieldValue(Field field, Object bean, @Nullable String beanName) {
//创建一个 DependencyDescriptor 对象,该对象包含有关要注入的字段的信息。设置字段所属的类以及是否为必需的标志
DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
//设置要注入对象的类
desc.setContainingClass(bean.getClass());
//初始化用于存储自动装配的Bean名称的集合 autowiredBeanNames,检查 beanFactory 是否为null,并获取 TypeConverter 对象。
Set<String> autowiredBeanNames = new LinkedHashSet<>(1);
Assert.state(beanFactory != null, "No BeanFactory available");
//获得类型转换器
TypeConverter typeConverter = beanFactory.getTypeConverter();
//要注入的值
Object value;
try {
//使用 beanFactory 的 resolveDependency 方法解析字段值。如果解析失败,抛出 UnsatisfiedDependencyException 异常,其中包含相关的信息,如字段信息、目标Bean名称和异常原因。
value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
}
catch (BeansException ex) {
throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
}
synchronized (this) {
if (!this.cached) {
Object cachedFieldValue = null;
if (value != null || this.required) {
cachedFieldValue = desc;
// 注册一下beanName依赖了autowiredBeanNames,
registerDependentBeans(beanName, autowiredBeanNames);
if (autowiredBeanNames.size() == 1) {
String autowiredBeanName = autowiredBeanNames.iterator().next();
if (beanFactory.containsBean(autowiredBeanName) &&
beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {
// 构造一个ShortcutDependencyDescriptor作为缓存,保存了当前filed所匹配的autowiredBeanName,而不是对应的bean对象(考虑原型bean)
cachedFieldValue = new ShortcutDependencyDescriptor(
desc, autowiredBeanName, field.getType());
}
}
}
this.cachedFieldValue = cachedFieldValue;
this.cached = true;
}
}
return value;
}
}
上面代码主要是解析字段的值和处理自动装配的逻辑。首先它调用了beanFactory.resolveDependency
来解析字段值。
@Override
@Nullable
/**
descriptor:要解析的依赖项的描述符
requestingBeanName: 请求解析依赖项的 Bean 的名称(可能为null)
autowiredBeanNames: 自动装配的Bean名称的集合(可能为null)。
typeConverter: 用于类型转换的 TypeConverter 对象(可能为null)
**/
public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
// 用来获取方法入参名字的
descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());
// 所需要的类型是Optional
if (Optional.class == descriptor.getDependencyType()) {
return createOptionalDependency(descriptor, requestingBeanName);
}
// 所需要的的类型是ObjectFactory,或ObjectProvider
else if (ObjectFactory.class == descriptor.getDependencyType() ||
ObjectProvider.class == descriptor.getDependencyType()) {
//如果所需的类型是 ObjectFactory 或 ObjectProvider,则创建一个 DependencyObjectProvider 对象
return new DependencyObjectProvider(descriptor, requestingBeanName);
}
//如果所需的类型是 javax.inject.Provider,则使用 Jsr330Factory 创建一个 Provider 类型的依赖。
else if (javaxInjectProviderClass == descriptor.getDependencyType()) {
return new Jsr330Factory().createDependencyProvider(descriptor, requestingBeanName);
}
else {
// 在属性或set方法上使用了@Lazy注解,那么则构造一个代理对象并返回,真正使用该代理对象时才进行类型筛选Bean
Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(
descriptor, requestingBeanName);
if (result == null) {
// descriptor表示某个属性或某个set方法
// requestingBeanName表示正在进行依赖注入的Bean
result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
}
return result;
}
}
首先我们来看下面这句代码:
if (Optional.class == descriptor.getDependencyType()) {
return createOptionalDependency(descriptor, requestingBeanName);
}
它处理了Optional类的依赖,这种方式不常用,下面我用案例演示一下:
@Component
public class OrderService {
}
@Component
public class UserService {
private final Optional<OrderService> orderService;
@Autowired
public UserService(Optional<OrderService> orderService) {
this.orderService = orderService;
}
public void performUserOperation() {
if (orderService.isPresent()) {
OrderService userRepo = orderService.get();
// 执行基于UserRepository的操作
System.out.println("UserRepository存在,可以执行操作");
} else {
// 没有UserRepository的情况下的处理逻辑
System.out.println("没有UserRepository,无法执行操作");
}
}
}
public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
UserService userService = (UserService) applicationContext.getBean("userService");
userService.performUserOperation();
}
}
最后我们可以测试Test,若去掉OrderService
签名的@Component注解
,结果如下:
加上注解就是:
Optional 是 Java 8 引入的一个类,用于解决可能存在空值(null)的情况。它的设计目的是通过封装可能为null的值,强制对值进行显示的空值检查,从而避免空指针异常。以下是 Optional 类的主要作用:
下面是一个简单的例子,演示了 Optional 的基本用法:
public static void main(String[] args) {
// 创建一个包含非空值的Optional
Optional<String> nonEmptyOptional = Optional.of("Hello, World!");
// 创建一个空的Optional
Optional<String> emptyOptional = Optional.empty();
// 判断Optional是否包含值
System.out.println("Non-empty Optional: " + nonEmptyOptional.isPresent());
System.out.println("Empty Optional: " + emptyOptional.isPresent());
// 获取Optional中的值,如果值为空,提供默认值
String value = nonEmptyOptional.orElse("Default Value");
System.out.println("Value: " + value);
// 如果值存在,则执行某个操作
nonEmptyOptional.ifPresent(val -> System.out.println("Length: " + val.length()));
// 使用map转换Optional中的值
Optional<Integer> lengthOptional = nonEmptyOptional.map(String::length);
lengthOptional.ifPresent(len -> System.out.println("Length using map: " + len));
}
处理完Optinal类型的依赖后,回到resolveDependency
函数。继续处理其它集中依赖,最后如果不是上面介绍的集中特殊依赖关系,则调用bject result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(descriptor, requestingBeanName);
代码段的目的是在实际进行依赖项解析之前,检查是否需要懒加载。如果需要懒加载,会通过调用 getLazyResolutionProxyIfNecessary
方法获取懒加载的代理对象,然后将该代理对象用作最终的依赖项。
在 Spring 中,懒加载是一种策略,用于延迟对象的实际创建和初始化,直到第一次被真正需要时。这有助于提高性能,特别是在应用程序启动时,不会立即创建所有可能不会被使用的 Bean。懒加载通常通过代理对象来实现,代理对象会在真正需要时触发目标 Bean 的创建和初始化。这在大型应用程序中可以显著减少启动时间。
上面代码的逻辑主要是首先处理了几种特殊类型的依赖,然后判断所依赖的对象是否是懒加载,如果是懒加载我们就会返回所依赖对象的代理对象返回(只有当我们真正使用到这个对象时,才会加载该对象),如果不是懒加载对象,就调用doResolveDependency
开始真正解析要注入的bean。
@Nullable
/*
descriptor: 要解析的依赖项的描述符。
beanName: 当前正在进行依赖注入的 Bean 的名称(可能为null)。
autowiredBeanNames: 自动装配的Bean名称的集合(可能为null)。
typeConverter: 用于类型转换的 TypeConverter 对象(可能为null)。
*/
public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
//在进行依赖项解析之前,通过调用 setCurrentInjectionPoint 方法设置当前的注入点,以便后续的解析可以获取到相关的上下文信息
InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);
try {
// 如果当前descriptor之前做过依赖注入了,则可以直接取shortcut了,相当于缓存,尝试获取缓存的快捷方式,如果存在的话直接返回。这是为了提高性能,避免重复解析相同的依赖项。
Object shortcut = descriptor.resolveShortcut(this);
if (shortcut != null) {
//如果shortcut不为空,直接返回即可
return shortcut;
}
//获取依赖项的类型
Class<?> type = descriptor.getDependencyType();
// 获取@Value所指定的值
Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
if (value != null) {
if (value instanceof String) {
// 占位符填充(${})
String strVal = resolveEmbeddedValue((String) value);
BeanDefinition bd = (beanName != null && containsBean(beanName) ?
getMergedBeanDefinition(beanName) : null);
// 解析Spring表达式(#{})
value = evaluateBeanDefinitionString(strVal, bd);
}
// 将value转化为descriptor所对应的类型
TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
try {
return converter.convertIfNecessary(value, type, descriptor.getTypeDescriptor());
}
catch (UnsupportedOperationException ex) {
// A custom TypeConverter which does not support TypeDescriptor resolution...
return (descriptor.getField() != null ?
converter.convertIfNecessary(value, type, descriptor.getField()) :
converter.convertIfNecessary(value, type, descriptor.getMethodParameter()));
}
}
// 如果descriptor所对应的类型是数组、Map这些,就将descriptor对应的类型所匹配的所有bean方法,不用进一步做筛选了
Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
if (multipleBeans != null) {
return multipleBeans;
}
// 找到所有Bean,key是beanName, value有可能是bean对象,有可能是beanClass
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
if (matchingBeans.isEmpty()) {
// required为true,抛异常
if (isRequired(descriptor)) {
raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
}
return null;
}
String autowiredBeanName;
Object instanceCandidate;
if (matchingBeans.size() > 1) {
// 根据类型找到了多个Bean,进一步筛选出某一个, @Primary-->优先级最高--->name
autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
if (autowiredBeanName == null) {
if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {
return descriptor.resolveNotUnique(descriptor.getResolvableType(), matchingBeans);
}
else {
return null;
}
}
instanceCandidate = matchingBeans.get(autowiredBeanName);
}
else {
// We have exactly one match.
Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();
autowiredBeanName = entry.getKey();
instanceCandidate = entry.getValue();
}
// 记录匹配过的beanName
if (autowiredBeanNames != null) {
autowiredBeanNames.add(autowiredBeanName);
}
// 有可能筛选出来的是某个bean的类型,此处就进行实例化,调用getBean
if (instanceCandidate instanceof Class) {
instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
}
Object result = instanceCandidate;
if (result instanceof NullBean) {
if (isRequired(descriptor)) {
raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
}
result = null;
}
if (!ClassUtils.isAssignableValue(type, result)) {
throw new BeanNotOfRequiredTypeException(autowiredBeanName, type, instanceCandidate.getClass());
}
return result;
}
finally {
ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint);
}
}
上面代码涵盖了对不同情况的处理,包括通过注解、类型、名称等方式进行 Bean 的筛选和解析。同时,支持了类型转换、@Value 注解、Spring 表达式的解析等功能,以满足复杂的依赖项解析需求。
首先处理了@Value
注解,调用的是Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
。
@Override
@Nullable
public Object getSuggestedValue(DependencyDescriptor descriptor) {
//从 DependencyDescriptor 中获取注解(annotations),并通过 findValue 方法寻找与注解相关联的值。
Object value = findValue(descriptor.getAnnotations());
if (value == null) {
MethodParameter methodParam = descriptor.getMethodParameter();
if (methodParam != null) {
value = findValue(methodParam.getMethodAnnotations());
}
}
return value;
}
整个方法的目的是根据依赖项的描述符,尝试从相关的注解中获取建议值。这可以用于处理一些特殊情况,例如通过注解指定的默认值等。在 Spring 中,@Value 注解就是一个常见的用例,通过它可以在字段或方法参数上指定默认值。(其实这里就会获得我们在@Value
中写入的值)。@Value
的使用方法有多种,下面介绍一下:
@Value("${property.name}")
private String propertyName;
上述代码将 ${property.name} 中的配置值注入到 propertyName 字段中。这是 @Value 最基本的用法,通常用于注入简单的属性值。
@Value("#{systemProperties['java.home']}")
private String javaHome;
使用 SpEL 表达式,可以在 @Value 中执行更复杂的逻辑。上述例子中,通过 SpEL 表达式获取 Java 安装的主目录。
@Value("${property.with.default:default-value}")
private String propertyWithDefault;
如果配置中不存在 property.with.default,则 propertyWithDefault 将被注入为默认值 “default-value”。
@Value("${list.values}")
private List<String> listValues;
@Value("${array.values}")
private String[] arrayValues;
如果配置中的值是逗号分隔的,@Value 注解可以直接注入到 List 或数组中。
@Value("${MY_ENV_VARIABLE}")
private String myEnvVariable;
@Value("classpath:config/application.properties")
private Resource configFile;
然后继续回到doResolveDependency
方法。
//判断@Value注解是否指定了默认值
if (value != null) {
//如果值的类型是String(一般情况下都是String)
if (value instanceof String) {
// 占位符填充(${})
//resolveEmbeddedValue 方法会尝试解析这个占位符,替换成实际的属性值。
String strVal = resolveEmbeddedValue((String) value);
BeanDefinition bd = (beanName != null && containsBean(beanName) ?
getMergedBeanDefinition(beanName) : null);
// 解析Spring表达式(#{})
value = evaluateBeanDefinitionString(strVal, bd);
}
// 将value转化为descriptor所对应的类型
TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
try {
return converter.convertIfNecessary(value, type, descriptor.getTypeDescriptor());
}
catch (UnsupportedOperationException ex) {
// A custom TypeConverter which does not support TypeDescriptor resolution...
return (descriptor.getField() != null ?
converter.convertIfNecessary(value, type, descriptor.getField()) :
converter.convertIfNecessary(value, type, descriptor.getMethodParameter()));
}
}
上面代码首先如果value是String类型它会首先处理占位符#{}
和${}
填充,假设有一个Spring Bean的配置如下:
@Configuration
public class AppConfig {
@Value("${app.message}")
private String appMessage;
@Bean
public MyBean myBean() {
return new MyBean(appMessage);
}
}
在这个配置中,MyBean 类的实例化依赖于一个名为 app.message 的属性值。这个属性值从Spring的Enviroment中获取(Environment 接口是一个核心接口,用于表示应用程序运行环境的抽象。它提供了一种方式来访问应用程序配置的属性以及配置文件中的属性值,或者是操作系统相关配置。Environment 接口的实现类通常是 StandardEnvironment 或其子类。)
继续回到doResolveDependency
,处理完@Value的占位符的信息,下面就可以开始类型转换了,主要目的是将Value值转换为我们所需要注入的属性类型值。处理完Value注解后,就开始处理数组和Map类型了。
// 如果descriptor所对应的类型是数组、Map这些,就将descriptor对应的类型所匹配的所有bean方法,不用进一步做筛选了
Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
if (multipleBeans != null) {
return multipleBeans;
}
如果依赖项的类型是数组、Map等,直接解析所有匹配的 Bean ,不进行进一步筛选。调用 resolveMultipleBeans
函数。
@Nullable
private Object resolveMultipleBeans(DependencyDescriptor descriptor, @Nullable String beanName,
@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) {
//获取依赖项的类型
Class<?> type = descriptor.getDependencyType();
//如果依赖项的类型是 Stream,则会找到所有与类型匹配的 Bean,构造成一个 Stream 对象,并进行排序(如果有序)。这种情况下,返回的是 Stream 对象。
if (descriptor instanceof StreamDependencyDescriptor) {
// 找到type所匹配的所有bean
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
if (autowiredBeanNames != null) {
autowiredBeanNames.addAll(matchingBeans.keySet());
}
// 构造成一个stream
Stream<Object> stream = matchingBeans.keySet().stream()
.map(name -> descriptor.resolveCandidate(name, type, this))
.filter(bean -> !(bean instanceof NullBean));
// 排序
if (((StreamDependencyDescriptor) descriptor).isOrdered()) {
stream = stream.sorted(adaptOrderComparator(matchingBeans));
}
return stream;
}
//如果依赖项的类型是数组,首先获取数组元素的类型,然后找到所有与数组元素类型匹配的 Bean。最后,将匹配到的 Bean 转化为数组,并进行排序(如果有序)。
else if (type.isArray()) {
// 获取数组元素的类型
Class<?> componentType = type.getComponentType();
//获取依赖项的 ResolvableType,它提供了类型解析的功能
ResolvableType resolvableType = descriptor.getResolvableType();
//解析数组类型,返回其实际的类。如果数组元素的类型不是泛型,将与 type 相同;否则,将是泛型参数的实际类型
Class<?> resolvedArrayType = resolvableType.resolve(type);
//如果解析后的数组类型不等于原始类型,说明数组类型是泛型数组,此时获取泛型参数的实际类型
if (resolvedArrayType != type) {
componentType = resolvableType.getComponentType().resolve();
}
//如果数组元素的类型为 null,则返回 null
if (componentType == null) {
return null;
}
// 根据数组元素类型找到所匹配的所有Bean
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, componentType,
new MultiElementDescriptor(descriptor));
//如果没有匹配的 Bean,则返回 null
if (matchingBeans.isEmpty()) {
return null;
}
//将匹配到的 Bean 的名称添加到自动装配的 Bean 名称集合中。
if (autowiredBeanNames != null) {
autowiredBeanNames.addAll(matchingBeans.keySet());
}
//获取类型转换器,用于将值转换为期望的类型
TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
//将匹配到的 Bean 的值转换为数组类型
Object result = converter.convertIfNecessary(matchingBeans.values(), resolvedArrayType);
//如果转换后的结果是数组,且存在比较器,则对数组进行排序
if (result instanceof Object[]) {
Comparator<Object> comparator = adaptDependencyComparator(matchingBeans);
if (comparator != null) {
Arrays.sort((Object[]) result, comparator);
}
}
//返回处理后的结果,即匹配到的 Bean 的数组
return result;
}
//如果依赖项的类型是集合(实现了 Collection 接口),则获取集合元素的类型,找到所有与集合元素类型匹配的 Bean。最后,将匹配到的 Bean 转化为集合,并进行排序(如果有序)。
else if (Collection.class.isAssignableFrom(type) && type.isInterface()) {
Class<?> elementType = descriptor.getResolvableType().asCollection().resolveGeneric();
if (elementType == null) {
return null;
}
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, elementType,
new MultiElementDescriptor(descriptor));
if (matchingBeans.isEmpty()) {
return null;
}
if (autowiredBeanNames != null) {
autowiredBeanNames.addAll(matchingBeans.keySet());
}
TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
Object result = converter.convertIfNecessary(matchingBeans.values(), type);
if (result instanceof List) {
if (((List<?>) result).size() > 1) {
Comparator<Object> comparator = adaptDependencyComparator(matchingBeans);
if (comparator != null) {
((List<?>) result).sort(comparator);
}
}
}
return result;
}
//如果依赖项的类型是 Map,则获取 Map 的键和值的类型,如果键的类型不是 String,返回 null。然后,找到所有与值的类型匹配的 Bean,最后返回匹配到的 Bean 的 Map。
else if (Map.class == type) {
ResolvableType mapType = descriptor.getResolvableType().asMap();
Class<?> keyType = mapType.resolveGeneric(0);
// 如果Map的key不是String
if (String.class != keyType) {
return null;
}
Class<?> valueType = mapType.resolveGeneric(1);
if (valueType == null) {
return null;
}
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, valueType,
new MultiElementDescriptor(descriptor));
if (matchingBeans.isEmpty()) {
return null;
}
if (autowiredBeanNames != null) {
autowiredBeanNames.addAll(matchingBeans.keySet());
}
return matchingBeans;
}
//对于其他类型的依赖项,返回 null,表示当前方法无法处理。
else {
return null;
}
}
上面代码首先判断类型是否是Stream类型,下面介绍一下Stream类型的使用方法:
public interface Animal {
String getName();
}
public class Dog implements Animal {
private String name;
public Dog(String name) {
this.name = name;
}
@Override
public String getName() {
return name;
}
}
public class Cat implements Animal {
private String name;
public Cat(String name) {
this.name = name;
}
@Override
public String getName() {
return name;
}
}
@ComponentScan("com.zhouyu")
@EnableScheduling
@PropertySource("classpath:spring.properties")
public class AppConfig {
@Bean
public Animal dog() {
return new Dog("Buddy");
}
@Bean
public Animal cat() {
return new Cat("Whiskers");
}
}
@Component
public class AnimalService {
@Autowired
private List<Animal> animals; // 注入 Animal 类型的集合
public void printAnimalNames() {
animals.stream().map(Animal::getName).forEach(System.out::println);
}
}
public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
AnimalService animalService = applicationContext.getBean(AnimalService.class);
animalService.printAnimalNames();
}
}
这样,通过 Stream 类型的依赖项,可以方便地处理一系列匹配的 Bean。解析完Stream类型后下面开始处理数组元素类型。下面演示一下Spring中数组类型注入的情况:
@Component
public class Box {
private String content;
public Box(){
}
public Box(String content) {
this.content = content;
}
public String getContent() {
return content;
}
}
@Component
public class BoxService {
@Autowired
private List<Box> stringBoxes;
public BoxService(List<Box> stringBoxes) {
this.stringBoxes = stringBoxes;
}
public void printStringBoxes() {
for (Box box : stringBoxes) {
System.out.println(box.getContent());
}
}
}
@ComponentScan("com.zhouyu")
@EnableScheduling
@PropertySource("classpath:spring.properties")
public class AppConfig {
@Bean
public Box boxA() {
return new Box("A");
}
@Bean
public Box boxB() {
return new Box("B");
}
@Bean
public Box boxC() {
return new Box("C");
}
}
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
// 获取 BoxService bean
BoxService boxService = (BoxService) applicationContext.getBean("boxService");
boxService.printStringBoxes();
// 关闭 ApplicationContext
applicationContext.close();
}
处理完数组类型的注入,这个注入过程会按照数组类型找到容器中所有的符号类型要求的bean,然后放入到数组中,下面接着处理Map类型的注入。
//这是一个条件语句,判断依赖项的类型是否为 Map
else if (Map.class == type) {
//获取依赖项的 ResolvableType,然后通过 asMap() 方法将其转换为 Map 类型的 ResolvableType。
ResolvableType mapType = descriptor.getResolvableType().asMap();
//通过 mapType 获取 Map 的键的泛型类型。
Class<?> keyType = mapType.resolveGeneric(0);
// 如果Map的key不是String, 检查键的类型是否为 String,如果不是,则返回 null。这里的逻辑是,如果 Map 的键类型不是 String,则当前方法无法处理,直接返回 null。
if (String.class != keyType) {
return null;
}
//获取 Map 的值的泛型类型。
Class<?> valueType = mapType.resolveGeneric(1);
//检查值的类型是否为 null,如果是,则返回 null。这里的逻辑是,如果 Map 的值的类型无法解析,也返回 null。
if (valueType == null) {
return null;
}
//调用 findAutowireCandidates 方法,该方法根据指定的 beanName、值的类型 valueType 和 MultiElementDescriptor(表示多元素的描述符)找到匹配的bean
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, valueType,
new MultiElementDescriptor(descriptor));
// 如果找到的匹配 bean 的集合为空,也返回 null。
if (matchingBeans.isEmpty()) {
return null;
}
//如果传入的 autowiredBeanNames 不为 null,将匹配到的 bean 的名称添加到 autowiredBeanNames 集合中。
if (autowiredBeanNames != null) {
autowiredBeanNames.addAll(matchingBeans.keySet());
}
return matchingBeans;
}
上面是Map类型注入的情况,下面给出一个案例分析Map类型注入在Spring中是如何使用的。稍微修改一下前面的代码:
@Component
public class BoxService {
@Autowired
private Map<String,Box> stringBoxes;
public BoxService(Map<String,Box> stringBoxes) {
this.stringBoxes = stringBoxes;
}
public void printStringBoxes() {
for (String mybox : stringBoxes.keySet()) {
System.out.println(stringBoxes.get(mybox).getContent());
}
}
}
@Component
public class BoxService {
@Autowired
private Map<String,Object> stringBoxes;
public BoxService(Map<String,Object> stringBoxes) {
this.stringBoxes = stringBoxes;
}
public void printStringBoxes() {
for (String mybox : stringBoxes.keySet()) {
System.out.println(stringBoxes.get(mybox));
}
}
}
这种形式我们会获取容器中的所有bean
到此所有的类型都解析完了,发现上面几种类型在解析时都调用了findAutowireCandidates函数。
protected Map<String, Object> findAutowireCandidates(
@Nullable String beanName, Class<?> requiredType, DependencyDescriptor descriptor) {
// 从BeanFactory中找出和requiredType所匹配的beanName,仅仅是beanName,这些bean不一定经过了实例化,只有到最终确定某个Bean了,如果这个Bean还没有实例化才会真正进行实例化
String[] candidateNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this, requiredType, true, descriptor.isEager());
Map<String, Object> result = CollectionUtils.newLinkedHashMap(candidateNames.length);
// 根据类型从resolvableDependencies中匹配Bean,resolvableDependencies中存放的是类型:Bean对象,比如BeanFactory.class:BeanFactory对象,在Spring启动时设置
for (Map.Entry<Class<?>, Object> classObjectEntry : this.resolvableDependencies.entrySet()) {
//获取class对象
Class<?> autowiringType = classObjectEntry.getKey();
//判断是否与当前所需要的class类型匹配
if (autowiringType.isAssignableFrom(requiredType)) {
Object autowiringValue = classObjectEntry.getValue();
autowiringValue = AutowireUtils.resolveAutowiringValue(autowiringValue, requiredType);
if (requiredType.isInstance(autowiringValue)) {
result.put(ObjectUtils.identityToString(autowiringValue), autowiringValue);
break;
}
}
}
for (String candidate : candidateNames) {
// 如果不是自己,则判断该candidate到底能不能用来进行自动注入
if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, descriptor)) {
addCandidateEntry(result, candidate, descriptor, requiredType);
}
}
// 为空要么是真的没有匹配的,要么是匹配的自己
if (result.isEmpty()) {
// 需要匹配的类型是不是Map、数组之类的
boolean multiple = indicatesMultipleBeans(requiredType);
// Consider fallback matches if the first pass failed to find anything...
DependencyDescriptor fallbackDescriptor = descriptor.forFallbackMatch();
for (String candidate : candidateNames) {
if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, fallbackDescriptor) &&
(!multiple || getAutowireCandidateResolver().hasQualifier(descriptor))) {
addCandidateEntry(result, candidate, descriptor, requiredType);
}
}
// 匹配的是自己,被自己添加到result中
if (result.isEmpty() && !multiple) {
// Consider self references as a final pass...
// but in the case of a dependency collection, not the very same bean itself.
for (String candidate : candidateNames) {
if (isSelfReference(beanName, candidate) &&
(!(descriptor instanceof MultiElementDescriptor) || !beanName.equals(candidate)) &&
isAutowireCandidate(candidate, fallbackDescriptor)) {
addCandidateEntry(result, candidate, descriptor, requiredType);
}
}
}
}
return result;
}
上面代码首先是获取指定类型所有bean的名字String[] candidateNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this, requiredType, true, descriptor.isEager());
public static String[] beanNamesForTypeIncludingAncestors(
ListableBeanFactory lbf, Class<?> type, boolean includeNonSingletons, boolean allowEagerInit) {
Assert.notNull(lbf, "ListableBeanFactory must not be null");
// 从本容器中找
String[] result = lbf.getBeanNamesForType(type, includeNonSingletons, allowEagerInit);
// 从父容器找并放入result
if (lbf instanceof HierarchicalBeanFactory) {
HierarchicalBeanFactory hbf = (HierarchicalBeanFactory) lbf;
if (hbf.getParentBeanFactory() instanceof ListableBeanFactory) {
String[] parentResult = beanNamesForTypeIncludingAncestors(
(ListableBeanFactory) hbf.getParentBeanFactory(), type, includeNonSingletons, allowEagerInit);
result = mergeNamesWithParent(result, parentResult, hbf);
}
}
return result;
}
上面代码的逻辑就是根据类型在本工厂和父工厂中找,如果都找到了然后合并两个结果并返回,那么bean 工厂是怎么根据类型来找名字的lbf.getBeanNamesForType
//includeNonSingletons表示是否包括原型bean
@Override
public String[] getBeanNamesForType(@Nullable Class<?> type, boolean includeNonSingletons, boolean allowEagerInit) {
// 如果没有冻结,就根据类型去BeanFactory找,如果冻结了,可能就跳过这个if然后去缓存中去拿了
if (!isConfigurationFrozen() || type == null || !allowEagerInit) {
return doGetBeanNamesForType(ResolvableType.forRawClass(type), includeNonSingletons, allowEagerInit);
}
// 把当前类型所匹配的beanName缓存起来(includeNonSingletons来判断具体保持到哪个集合)
Map<Class<?>, String[]> cache =
(includeNonSingletons ? this.allBeanNamesByType : this.singletonBeanNamesByType);
String[] resolvedBeanNames = cache.get(type);
if (resolvedBeanNames != null) {
return resolvedBeanNames;
}
resolvedBeanNames = doGetBeanNamesForType(ResolvableType.forRawClass(type), includeNonSingletons, true);
if (ClassUtils.isCacheSafe(type, getBeanClassLoader())) {
cache.put(type, resolvedBeanNames);
}
return resolvedBeanNames;
}
然后上面代码最终调用的是doGetBeanNamesForType
来找的
private String[] doGetBeanNamesForType(ResolvableType type, boolean includeNonSingletons, boolean allowEagerInit) {
List<String> result = new ArrayList<>();
// Check all bean definitions.
// 遍历所有的BeanDefinitions的name
for (String beanName : this.beanDefinitionNames) {
// Only consider bean as eligible if the bean name is not defined as alias for some other bean.
if (!isAlias(beanName)) {
try {
//根据名字拿到对应的BeanDefinition
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
// Only check bean definition if it is complete.
// 判断mbd允不允许获取对应类型
// 首先mdb不能是抽象的,然后allowEagerInit为true,则直接去推测mdb的类型,并进行匹配
// 如果allowEagerInit为false,那就继续判断,如果mdb还没有加载类并且是懒加载的并且不允许提前加载类,那mbd不能用来进行匹配(因为不允许提前加载类,只能在此mdb自己去创建bean对象时才能去创建类)
// 如果allowEagerInit为false,并且mbd已经加载类了,或者是非懒加载的,或者允许提前加载类,并且不用必须提前初始化才能获取类型,那么就可以去进行匹配了
// 这个条件有点复杂,但是如果只考虑大部分流程,则可以忽略这个判断,因为allowEagerInit传进来的基本上都是true
if (!mbd.isAbstract() && (allowEagerInit ||
(mbd.hasBeanClass() || !mbd.isLazyInit() || isAllowEagerClassLoading()) &&
!requiresEagerInitForType(mbd.getFactoryBeanName()))) {
boolean isFactoryBean = isFactoryBean(beanName, mbd);
BeanDefinitionHolder dbd = mbd.getDecoratedDefinition();
boolean matchFound = false;
boolean allowFactoryBeanInit = (allowEagerInit || containsSingleton(beanName));
boolean isNonLazyDecorated = (dbd != null && !mbd.isLazyInit());
// 当前BeanDefinition不是FactoryBean,就是普通Bean
if (!isFactoryBean) {
// 在筛选Bean时,如果仅仅只包括单例,但是beanName对应的又不是单例,则忽略
if (includeNonSingletons || isSingleton(beanName, mbd, dbd)) {
matchFound = isTypeMatch(beanName, type, allowFactoryBeanInit);
}
}
else {
if (includeNonSingletons || isNonLazyDecorated ||
(allowFactoryBeanInit && isSingleton(beanName, mbd, dbd))) {
matchFound = isTypeMatch(beanName, type, allowFactoryBeanInit);
}
if (!matchFound) {
// In case of FactoryBean, try to match FactoryBean instance itself next.
beanName = FACTORY_BEAN_PREFIX + beanName;
matchFound = isTypeMatch(beanName, type, allowFactoryBeanInit);
}
}
if (matchFound) {
result.add(beanName);
}
}
}
catch (CannotLoadBeanClassException | BeanDefinitionStoreException ex) {
if (allowEagerInit) {
throw ex;
}
// Probably a placeholder: let's ignore it for type matching purposes.
LogMessage message = (ex instanceof CannotLoadBeanClassException ?
LogMessage.format("Ignoring bean class loading failure for bean '%s'", beanName) :
LogMessage.format("Ignoring unresolvable metadata in bean definition '%s'", beanName));
logger.trace(message, ex);
// Register exception, in case the bean was accidentally unresolvable.
onSuppressedException(ex);
}
catch (NoSuchBeanDefinitionException ex) {
// Bean definition got removed while we were iterating -> ignore.
}
}
}
// Check manually registered singletons too.
for (String beanName : this.manualSingletonNames) {
try {
// In case of FactoryBean, match object created by FactoryBean.
if (isFactoryBean(beanName)) {
if ((includeNonSingletons || isSingleton(beanName)) && isTypeMatch(beanName, type)) {
result.add(beanName);
// Match found for this bean: do not match FactoryBean itself anymore.
continue;
}
// In case of FactoryBean, try to match FactoryBean itself next.
beanName = FACTORY_BEAN_PREFIX + beanName;
}
// Match raw bean instance (might be raw FactoryBean).
if (isTypeMatch(beanName, type)) {
result.add(beanName);
}
}
catch (NoSuchBeanDefinitionException ex) {
// Shouldn't happen - probably a result of circular reference resolution...
logger.trace(LogMessage.format(
"Failed to check manually registered singleton with name '%s'", beanName), ex);
}
}
return StringUtils.toStringArray(result);
}
上面代码核心逻辑就是遍历所有的beanname,然后调用isTypeMatch方法判断指定的bean是否和你需要的类型匹配。 isTypeMatch的主要思路是它首先从单例池中获取指定名称的bean比较类型,如果单例池中没有获取到,那就获取beanDefitniiton加载然后对比。然后返回匹配到的bean的beanname。回到findAutowireCandidates方法
protected Map<String, Object> findAutowireCandidates(
@Nullable String beanName, Class<?> requiredType, DependencyDescriptor descriptor) {
// 从BeanFactory中找出和requiredType所匹配的beanName,仅仅是beanName,这些bean不一定经过了实例化,只有到最终确定某个Bean了,如果这个Bean还没有实例化才会真正进行实例化
String[] candidateNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this, requiredType, true, descriptor.isEager());
Map<String, Object> result = CollectionUtils.newLinkedHashMap(candidateNames.length);
// 根据类型从resolvableDependencies中匹配Bean,resolvableDependencies中存放的是类型:Bean对象,比如BeanFactory.class:BeanFactory对象,在Spring启动时设置
for (Map.Entry<Class<?>, Object> classObjectEntry : this.resolvableDependencies.entrySet()) {
//获取class对象
Class<?> autowiringType = classObjectEntry.getKey();
//判断是否与当前所需要的class类型匹配
if (autowiringType.isAssignableFrom(requiredType)) {
Object autowiringValue = classObjectEntry.getValue();
autowiringValue = AutowireUtils.resolveAutowiringValue(autowiringValue, requiredType);
if (requiredType.isInstance(autowiringValue)) {
result.put(ObjectUtils.identityToString(autowiringValue), autowiringValue);
break;
}
}
}
//遍历bean的名称
for (String candidate : candidateNames) {
// 如果不是自己,则判断该candidate到底能不能用来进行自动注入
if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, descriptor)) {
addCandidateEntry(result, candidate, descriptor, requiredType);
}
}
// 为空要么是真的没有匹配的,要么是匹配的自己
if (result.isEmpty()) {
// 需要匹配的类型是不是Map、数组之类的
boolean multiple = indicatesMultipleBeans(requiredType);
// Consider fallback matches if the first pass failed to find anything...
DependencyDescriptor fallbackDescriptor = descriptor.forFallbackMatch();
for (String candidate : candidateNames) {
if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, fallbackDescriptor) &&
(!multiple || getAutowireCandidateResolver().hasQualifier(descriptor))) {
addCandidateEntry(result, candidate, descriptor, requiredType);
}
}
// 匹配的是自己,被自己添加到result中
if (result.isEmpty() && !multiple) {
// Consider self references as a final pass...
// but in the case of a dependency collection, not the very same bean itself.
for (String candidate : candidateNames) {
if (isSelfReference(beanName, candidate) &&
(!(descriptor instanceof MultiElementDescriptor) || !beanName.equals(candidate)) &&
isAutowireCandidate(candidate, fallbackDescriptor)) {
addCandidateEntry(result, candidate, descriptor, requiredType);
}
}
}
}
return result;
}
找到所有匹配的Beanname后,后面代码就会对beanname进行遍历,首先过滤掉自己作为匹配对象的bean,然后调用isAutowireCandidate
判断其它匹配的bean是否可以进行依赖注入。例如下面bean利用autowireCandidate = false
表示不能进行依赖注入的。
public class AppConfig {
@Bean(autowireCandidate = false)
public OrderService orderService(){
return new OrderService();
}
}
到这里数组、Map就解析完了,回到doResolveDependency
方法继续执行后面逻辑。
Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
if (multipleBeans != null) {
//数组类型
return multipleBeans;
}
//解析普通类型
// 找到所有Bean,key是beanName, value有可能是bean对象,有可能是beanClass(这里还是调用findAutowireCandidates),这里用map集合是因为按照类型可能会解析到多个bean
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
//如果解析到为空,直接抛出异常并返回空
if (matchingBeans.isEmpty()) {
// required为true,抛异常
if (isRequired(descriptor)) {
raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
}
return null;
}
//注入的bean的beanname
String autowiredBeanName;
Object instanceCandidate;
//如果匹配到多个bean按照类型
if (matchingBeans.size() > 1) {
// 根据类型找到了多个Bean,进一步筛选出某一个, @Primary-->优先级最高--->name
autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
if (autowiredBeanName == null) {
if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {
return descriptor.resolveNotUnique(descriptor.getResolvableType(), matchingBeans);
}
else {
return null;
}
}
instanceCandidate = matchingBeans.get(autowiredBeanName);
}
else {
// 如果只有一个匹配,直接选取该 Bean
// We have exactly one match.
Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();
autowiredBeanName = entry.getKey();
instanceCandidate = entry.getValue();
}
// 记录匹配过的beanName
if (autowiredBeanNames != null) {
autowiredBeanNames.add(autowiredBeanName);
}
// 有可能筛选出来的是某个bean的类型,此处就进行实例化,调用getBean
if (instanceCandidate instanceof Class) {
instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
}
//将最终的实例赋给 result
Object result = instanceCandidate;
//如果结果是 NullBean,并且该依赖项是必需的,抛出异常。对于空值,spring底层将其定义为NullBean
if (result instanceof NullBean) {
if (isRequired(descriptor)) {
raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
}
result = null;
}
//类型不匹配
if (!ClassUtils.isAssignableValue(type, result)) {
throw new BeanNotOfRequiredTypeException(autowiredBeanName, type, instanceCandidate.getClass());
}
//返回解析得到的依赖项。
return result;
}
finally {
//在 try 块的最后,恢复之前设置的注入点,确保状态正确
ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint);
}
}