Spring自动装配实现原理
Java中使用注解的情况主要在SpringMVC(SpringBoot等),注解实际上相当于一种标记语言,它允许你在运动时动态地对拥有标签的成员进行操作。
注意:spring框架默认不支持自动装配,要想使用自动装配需要更改spring配置文件中标签的autowire属性
自动配置有六个值可以选,分别代表不同含义:
byName
从spring环境中获取环境对象时,目标对象中的属性会根据名称在整个Spring环境中查找标签的id属性值。如果有相同的,那么获取这个对象,实现关联。
整个Spring环境:表示所有的Spring配置文件中查找,那么id不能有重复的
byType
从Spring环境中获取目标对象时,目标对象的属性会根据类型在spring环境中查找标签的class属性值。如果有相同的,获取这个对象,实现关联
缺点:如果存在多个相同类型的bean对象,会出错;如果属性为单一类型的数据,那么查找到多个关联对象会发生错误;如果属性为数组或者集合(泛型)类型,那么查找到多个关联对象不会发生异常。
constructor -> 使用构造方法完成对象注入,其实也是根据构造参数类型进行对象查找,相当于使用byType的方式
autodetect -> 自动选择:如果对象没有无参数的构造方法,那么自动选择constructor的自动装配方法进行构造注入。如果对象含有无参数的构造方法,那么自动选择byType的自动装配方式进行setter注入
no -> 不支持自动装配
default -> 表示默认采用上一级标签的自动装配的取值。如果存在多个配置文件的话,那么每一个配置文件的自动装配方式都是独立的
SpringBoot声明周期流程图
bean自身方法的声明周期
分为四步:
//执行此段代码,spring容器的bean执行实例化、属性赋值、初始化 ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); //关闭容器,执行销毁 classPathXmlApplicationContext.close();
-
实例化
-
读取Spring配置文件
-
通过反射进行bean的实例化(通过BeanFactory实例化)
-
-
属性赋值
-
解析自动装配(byName、byType、constructor、default)DI的体现
-
循环依赖
-
-
初始化
-
调用XXXAware回调方法
-
调用初始化声明周期回调(三种)
-
如果bean实现aop创建动态代理
-
-
销毁
-
在Spring容器关闭时进行调用
-
调用初始化生命周期回调
-
下图展示了bean装载到spring应用上下文的一个典型的声明周期过程
@Autowired注解的自动装配过程
结论:
@Autowired是在bean属性赋值的阶段进行装配,通过bean的后置处理器进行解析
-
在创建一个spring上下文的时候在构造函数中 注册AutowireAnnotationBeanPostProcessor
-
在Bean的创建的过程中进行创建
-
在实例化后预解析(解析@Autowired标注的属性、方法,比如:把属性的类型、名称、属性所在的类..元数据缓存)
-
在属性赋值阶段真正的注入(拿着上一步的缓存的元数据去ioc容器进行查找,并且返回注入)
-
首先根据解析的元数据拿到类型去容器中查找
-
如果查找结果刚好为一个,就将该bean装配给@Autowired指定的数据;
-
如果查询的结果不止一个,那么@Autowired会根据名称来查找
-
如果上述查找为空,那么就会抛出异常
-
-
-
大致流程图为下:
@Autowired字段注入源码分析
/* ......源码注解过多,只贴一部分有用的 * <h3>Not supported in {@code BeanPostProcessor} or {@code BeanFactoryPostProcessor}</h3> * <p>Note that actual injection is performed through a * {@link org.springframework.beans.factory.config.BeanPostProcessor * BeanPostProcessor} which in turn means that you <em>cannot</em> * use {@code @Autowired} to inject references into * {@link org.springframework.beans.factory.config.BeanPostProcessor * BeanPostProcessor} or * {@link org.springframework.beans.factory.config.BeanFactoryPostProcessor BeanFactoryPostProcessor} * types. Please consult the javadoc for the {@link AutowiredAnnotationBeanPostProcessor} * class (which, by default, checks for the presence of this annotation). * * @author Juergen Hoeller * @author Mark Fisher * @author Sam Brannen * @since 2.5 * @see AutowiredAnnotationBeanPostProcessor * @see Qualifier * @see Value */ @Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Autowired { /** * Declares whether the annotated dependency is required. * <p>Defaults to {@code true}. */ boolean required() default true; }
-
重点在注释里的一句
Please consult the javadoc for the {@link AutowiredAnnotationBeanPostProcessor}
-
AutowiredAnnotationBeanPostProcessor是Spring的后置处理器,专门处理@Autowired和@Value注解。查看AutowiredAnnotationBeanPostProcessor类,关注postProcessorMergedBeanDefiniton()方法、postProcessorPropertyValues()方法和构造器
//Spring在每个Bean实例化的时候,调用populateBean进行属性注入的时候,即调用postProcessPropertyValues方法。 @Deprecated @Override public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) { return postProcessProperties(pvs, bean, beanName); } //•Spring容器在每个Bean实例化之后,调用AutowiredAnnotationBeanPostProcessor的postProcessMergedBeanDefinition方法。 @Override public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) { InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null); metadata.checkConfigMembers(beanDefinition); } //AutowiredAnnotationBeanPostProcessor构造器 public AutowiredAnnotationBeanPostProcessor() { //后置处理器将处理@Autowire注解 this.autowiredAnnotationTypes.add(Autowired.class); //后置处理器将处理@Value注解 this.autowiredAnnotationTypes.add(Value.class); try { //后置处理器将处理javax.inject.Inject JSR-330注解 this.autowiredAnnotationTypes.add((Class<? extends Annotation>) ClassUtils.forName("javax.inject.Inject", AutowiredAnnotationBeanPostProcessor.class.getClassLoader())); logger.info("JSR-330 'javax.inject.Inject' annotation found and supported for autowiring"); } catch (ClassNotFoundException ex) { // JSR-330 API not available - simply skip. } } @Override public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) { //获取指定类中autowire相关注解的元信息 InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs); try { //对Bean的属性进行自动注入 metadata.inject(bean, beanName, pvs); } catch (BeanCreationException ex) { throw ex; } catch (Throwable ex) { throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex); } return pvs; }
-
查看对Bean的属性进行自动注入metadata.inject(bean, beanName, pvs);方法
public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable { Collection<InjectedElement> checkedElements = this.checkedElements; //要注入的字段集合 Collection<InjectedElement> elementsToIterate = (checkedElements != null ? checkedElements : this.injectedElements); if (!elementsToIterate.isEmpty()) { for (InjectedElement element : elementsToIterate) { element.inject(target, beanName, pvs); } } }
-
查看element.inject(target, beanName, pvs);方法
protected void inject(Object target, @Nullable String requestingBeanName, @Nullable PropertyValues pvs)throws Throwable { if (this.isField) { Field field = (Field) this.member; ReflectionUtils.makeAccessible(field); field.set(target, getResourceToInject(target, requestingBeanName)); } else { if (checkPropertySkipping(pvs)) { return; } try { Method method = (Method) this.member; ReflectionUtils.makeAccessible(method); method.invoke(target, getResourceToInject(target, requestingBeanName)); } catch (InvocationTargetException ex) { throw ex.getTargetException(); } } }
这是element.inject(target, beanName, pvs);的原始方法,它还有两个子类自己实现的方法,如图:
-
此案例是字段注入分析,查看AutowiredFieldElement
//AutowiredAnnotationBeanPostProcessor.java @Override protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable { //获取要注入的字段 Field field = (Field) this.member; Object value; //如果字段的值有缓存 if (this.cached) { //从缓存中获取字段值value value = resolvedCachedArgument(beanName, this.cachedFieldValue); } //没有缓存 else { //创建一个字段依赖描述符 DependencyDescriptor desc = new DependencyDescriptor(field, this.required); desc.setContainingClass(bean.getClass()); Set<String> autowiredBeanNames = new LinkedHashSet<>(1); Assert.state(beanFactory != null, "No BeanFactory available"); //获取容器中的类型转换器 TypeConverter typeConverter = beanFactory.getTypeConverter(); try { //核心!获取注入的值 value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter); } catch (BeansException ex) { throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex); } //线程同步,确保容器中数据一致性 synchronized (this) { //如果字段的值没有缓存 if (!this.cached) { //字段值不为null,并且required属性为true if (value != null || this.required) { this.cachedFieldValue = desc; //为指定Bean注册依赖Bean registerDependentBeans(beanName, autowiredBeanNames); if (autowiredBeanNames.size() == 1) { String autowiredBeanName = autowiredBeanNames.iterator().next(); //如果容器中有指定名称的Bean对象 if (beanFactory.containsBean(autowiredBeanName)) { //依赖对象类型和字段类型匹配,默认按类型注入 if (beanFactory.isTypeMatch(autowiredBeanName, field.getType())) { //创建一个依赖对象的引用,同时缓存 this.cachedFieldValue = new ShortcutDependencyDescriptor( desc, autowiredBeanName, field.getType()); } } } } //如果获取的依赖关系为null,且获取required属性为false else { //将字段值的缓存设置为null this.cachedFieldValue = null; } //容器已经对当前字段的值缓存 this.cached = true; } } } //如果字段值不为null if (value != null) { //显式使用JDK的反射机制,设置自动的访问控制权限为允许访问 ReflectionUtils.makeAccessible(field); //为字段赋值 field.set(bean, value); } }
从注解@Value/@Autowired中获取要注入的值,之后利用反射set到字段中。 重点就是怎么从注解中获取要注入的值,我们来看核心代码
value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
//DefaultListableBeanFactory.java public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName, @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException { descriptor.initParameterNameDiscovery(getParameterNameDiscoverer()); if (Optional.class == descriptor.getDependencyType()) { return createOptionalDependency(descriptor, requestingBeanName); } else if (ObjectFactory.class == descriptor.getDependencyType() || ObjectProvider.class == descriptor.getDependencyType()) { return new DependencyObjectProvider(descriptor, requestingBeanName); } else if (javaxInjectProviderClass == descriptor.getDependencyType()) { return new Jsr330ProviderFactory().createDependencyProvider(descriptor, requestingBeanName); } else { Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary( descriptor, requestingBeanName); if (result == null) { //真正获取值的代码 result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter); } return result; } }
进行跟踪:
//DefaultListableBeanFactory.java public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName, @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException { InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor); try { Object shortcut = descriptor.resolveShortcut(this); if (shortcut != null) { 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); value = evaluateBeanDefinitionString(strVal, bd); } TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter()); return (descriptor.getField() != null ? converter.convertIfNecessary(value, type, descriptor.getField()) : converter.convertIfNecessary(value, type, descriptor.getMethodParameter())); } //如果标识@Autowired注解的属性是集合类型,Array,Collection,Map, // 从这个方法获取@Autowired里的值 <1> Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter); if (multipleBeans != null) { return multipleBeans; } //如果标识@Autowired注解的属性是非集合类型, // 从这个方法获取@Autowired里的值 <2> Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor); //如果没有符合该类型的Bean if (matchingBeans.isEmpty()) { //是否是必须的 if (isRequired(descriptor)) { //抛出异常 raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor); } return null; } String autowiredBeanName; Object instanceCandidate; //如果符合该类型的Bean有多个 if (matchingBeans.size() > 1) { //挑选出最优解 <3> autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor); if (autowiredBeanName == null) { if (isRequired(descriptor) || !indicatesMultipleBeans(type)) { //抛出异常 return descriptor.resolveNotUnique(type, matchingBeans); } else { // In case of an optional Collection/Map, silently ignore a non-unique case: // possibly it was meant to be an empty collection of multiple regular beans // (before 4.3 in particular when we didn't even look for collection beans). 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(); } if (autowiredBeanNames != null) { autowiredBeanNames.add(autowiredBeanName); } 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); } }
大致流程就是: 根据字段类型从IOC容器中获取符合的Bean,如果有多个,则挑选出最优的那一个。
<1>处:@Autowired注入集合数组,如Map.List。
<2>处:@Autowired注入非集合数组,即普通的类如Service
<3>处:多个同类型的bean中挑选出最优解
总结:
在容器启动,为bean属性赋值的时候,spring会用后置处理器AutowiredAnnotationBeanPostProcessor解析@Autowired注解,来创建属性的实例,然后从IOC容器中根据@Primary、@Order、@PriorityOrder或Spring默认规则挑选出最符合的Bean,利用反射注入到字段中完成赋值;