前言
@Value注解是Spring3.0后提出来的一个注解。注解内容本身非常之简单,但是它提供的功能却非常之强大。
首先从它的注解本身定义知道,它能使用在:
- 字段上
- set方法上
- 方法入参上
- 当作元注解
它的功能大致可归类为:
- 注入普通字符串
- 书写SpEL表达式(功能强大包括:获取系统属性、调用静态方法、计算、注入bean、调用bean的方法等等~~~)
- 注入Resource。如:@Value("classpath:com/demo/config.txt") 使用Resource类型接收
- 注入URL资源。如:@Value("http://www.baidu.com") 使用Resource类型接收
这里面不得不提的,就是它对强大的SpEL的支持,这是我们感叹@Value非常之强大的核心原因。关于SpEL的使用和原理浅析,请参见:
【小家Spring】SpEL你感兴趣的实现原理浅析spring-expression~(SpelExpressionParser、EvaluationContext、rootObject)
平时我们依赖注入你可能只会使用@Autowired等注解,但其实@Value也有注入bean的功能哦~
@Value
首先看看@Value注解本身,简单到令人发指有木有
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Value { String value(); // 没有默认值 所以是必填的 }
之前我们已经讲过,当Bean进行初始化完成之后会populateBean()对它的属性进行赋值,这个时候AutowiredAnnotationBeanPostProcessor这个后置处理器生效,从而对属性进行依赖注入赋值。
AutowiredAnnotationBeanPostProcessor它能够处理@Autowired和@Value注解~
注意:因为@Value是BeanPostProcessor来解析的,所以具有容器隔离性(本容器内的Bean使用@Value只能引用到本容器内的值哦~,因为BeanPostProcessor是具有隔离性的)
推荐:所有的@Value都写在根容器(也就是我们常说的Service容器)内,请不要放在web容器里。也就是说,请尽量不要在controller从使用@Value注解,因为业务我们都要求放在service层
三层架构:Controller、Service、Repository务必做到职责分离和松耦合~
若对Bean的初始化、实例化原理有不是非常清楚的,可抽空参见:
【小家Spring】细说Spring IOC容器的自动装配(@Autowired),以及Spring4.0新特性之【泛型依赖注入】的源码级解析
有了上面基础,所以我们直接从AutowiredAnnotationBeanPostProcessor#postProcessPropertyValues()方法入手:(Spring5.1后为postProcessProperties方法,方法的语义更加清晰些了~)
public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter implements MergedBeanDefinitionPostProcessor, PriorityOrdered, BeanFactoryAware { // 这个方法是InstantiationAwareBeanPostProcessor的,它在给属性赋值的时候会被调用~~ @Override public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) { // InjectionMetadata 里包含private final Collection<InjectedElement> injectedElements;表示所有需要注入处理的属性们~~~ // 所以最终都是InjectionMetadata去处理~ InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs); try { metadata.inject(bean, beanName, pvs); } ... return pvs; } }
InjectionMetadata
用于管理注入元数据的内部类。不建议直接在应用程序中使用。AutowiredAnnotationBeanPostProcessor和CommonAnnotationBeanPostProcessor以及org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor这几个哥们最终的注入都是靠它~
本处直接看它的inject方法:
public class InjectionMetadata { 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); } } } }
总而言之,最终是委托给了InjectedElement 。它有两个内部类的实现:AutowiredFieldElement和AutowiredMethodElement 此处我们只关注字段注入的。
InjectedElement是InjectionMetadata的一个public内部类,并且是抽象的。AutowiredFieldElement和AutowiredMethodElement都是AutowiredAnnotationBeanPostProcessor的private内部类。
另外:CommonAnnotationBeanPostProcessor中有InjectedElement的实现类:LookupElement、ResourceElement、EjbRefElement、WebServiceRefElement等来辅助完成注入~
AutowiredFieldElement
private class AutowiredFieldElement extends InjectionMetadata.InjectedElement { private final boolean required; private volatile boolean cached = false; @Nullable private volatile Object cachedFieldValue; public AutowiredFieldElement(Field field, boolean required) { super(field, null); this.required = required; } @Override protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable { // member在抽象父类:InjectedElement中定义~~~ Field field = (Field) this.member; Object value; if (this.cached) { 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"); // 此处一般为SimpleTypeConverter,它registerDefaultEditors=true,所以普通类型大都能能通过属性编辑器实现转换的 TypeConverter typeConverter = beanFactory.getTypeConverter(); try { // 最最最根本的原理,其实在resolveDependency这个方法里,它最终返回的就是一个具体的值,这个value是个Object~ value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter); } catch (BeansException ex) { throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex); } synchronized (this) { if (!this.cached) { if (value != null || this.required) { this.cachedFieldValue = desc; registerDependentBeans(beanName, autowiredBeanNames); if (autowiredBeanNames.size() == 1) { String autowiredBeanName = autowiredBeanNames.iterator().next(); if (beanFactory.containsBean(autowiredBeanName) && beanFactory.isTypeMatch(autowiredBeanName, field.getType())) { this.cachedFieldValue = new ShortcutDependencyDescriptor( desc, autowiredBeanName, field.getType()); } } } else { this.cachedFieldValue = null; } this.cached = true; } } } if (value != null) { ReflectionUtils.makeAccessible(field); field.set(bean, value); } } }
DefaultListableBeanFactory#resolveDependency
它是Spring容器整个体系里实现依赖查找的心脏~
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable { ... @Override @Nullable 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()) { // 最终它也会走到:doResolveDependency return createOptionalDependency(descriptor, requestingBeanName); } else if (ObjectFactory.class == descriptor.getDependencyType() || ObjectProvider.class == descriptor.getDependencyType()) { // 直接new一个Provider返回出去~ return new DependencyObjectProvider(descriptor, requestingBeanName); } // 兼容jsr330的javax.inject.Provider else if (javaxInjectProviderClass == descriptor.getDependencyType()) { return new Jsr330Factory().createDependencyProvider(descriptor, requestingBeanName); } else { // ContextAnnotationAutowireCandidateResolver-> QualifierAnnotationAutowireCandidateResolver 他们能够解决 就直接返回 否则交给doResolveDependency Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary( descriptor, requestingBeanName); if (result == null) { result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter); } return result; } } ... // 咱们此处descriptor:field 'personName' // beanName:rootConfig // autowiredBeanNames:[] // typeConverter:SimpleTypeConverter @Nullable public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName, @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException { InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor); try { // 若你的despriptor是ShortcutDependencyDescriptor,这个就会直接去beanFactory.getBean(this.shortcut, this.requiredType) 提前返回 主要作用是缓存的效果~ Object shortcut = descriptor.resolveShortcut(this); if (shortcut != null) { return shortcut; } // public final class String Class<?> type = descriptor.getDependencyType(); // 备注:QualifierAnnotationAutowireCandidateResolver会处理@Qualifier和@Value //QualifierAnnotationAutowireCandidateResolver#getSuggestedValue() //先拿出@Value注解的值 如果为null再去拿Method里这个注解的值~~~ 最终返回~ 所以@Value也是可以标注在方法上的 // 注意此处:若是@Value 这里返回值肯定是String 但是若是@Autowired此处返回值就可能是对象了~ Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor); if (value != null) { // 说明这个注入是@Value 因为它是String if (value instanceof String) { // 使用StringValueResolver处理${}占位符~ // 所以我们常用的只使用@Value("${xxx}")这样来注入值或者你就是个字面量值,到这一步就已经完事了~解析完成 // 若你是个el表达式 或者文件资源Resource啥的,会继续交给下面的beanExpressionResolver处理,所以它是处理复杂类型的核心~ String strVal = resolveEmbeddedValue((String) value); BeanDefinition bd = (beanName != null && containsBean(beanName) ? getMergedBeanDefinition(beanName) : null); // 此处注意:处理器是BeanExpressionResolver~~~~它是处理@Value表达式的核心方法 // 它的默认值是:StandardBeanExpressionResolver#evaluate // 这里面就会解析 value = evaluateBeanDefinitionString(strVal, bd); } // 若我们没有定制,此处为SimpleTypeConverter... 值已经拿到手了,经由转换器以转换 就可以测地的返回喽~~~解析结束 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())); } } // ====================下面就不解释了,多bean和required的解释 前面已经分析过了======================= Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter); if (multipleBeans != null) { return multipleBeans; } Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor); if (matchingBeans.isEmpty()) { if (isRequired(descriptor)) { raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor); } return null; } String autowiredBeanName; Object instanceCandidate; if (matchingBeans.size() > 1) { autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor); if (autowiredBeanName == null) { if (isRequired(descriptor) || !indicatesMultipleBeans(type)) { return descriptor.resolveNotUnique(descriptor.getResolvableType(), 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); } } }
、QualifierAnnotationAutowireCandidateResolver实现了AutowireCandidateResolver,对要自动绑定的field或者参数和bean definition根据@qualifier注解进行匹配,当然也支持javax.inject.Qualifier。同时也支持通过@value注解来绑定表达式的值。
从上面分析知道,当把@Value的占位符替换完成后,最终都会交给beanExpressionResolver由它来统一处理:包括根据beanName获取bean、SpEL计算等等~~~