Spring 之autowired
Spring中autowired主要用于装配树形值,其关键类为BeanWrapperImpl,阅读代码发现其关键方法setPropertyValue有如下一段代码。
1 PropertyHandler ph = getLocalPropertyHandler(actualName); 2 if (ph == null || !ph.isWritable()) { 3 if (pv.isOptional()) { 4 if (logger.isDebugEnabled()) { 5 logger.debug("Ignoring optional value for property '" + actualName + 6 "' - property not found on bean class [" + getRootClass().getName() + "]"); 7 } 8 return; 9 } 10 else { 11 throw createNotWritablePropertyException(propertyName); 12 } 13 } 14 Object oldValue = null; 15 try { 16 Object originalValue = pv.getValue(); 17 Object valueToApply = originalValue; 18 if (!Boolean.FALSE.equals(pv.conversionNecessary)) { 19 if (pv.isConverted()) { 20 valueToApply = pv.getConvertedValue(); 21 } 22 else { 23 if (isExtractOldValueForEditor() && ph.isReadable()) { 24 try { 25 oldValue = ph.getValue(); 26 } 27 catch (Exception ex) { 28 if (ex instanceof PrivilegedActionException) { 29 ex = ((PrivilegedActionException) ex).getException(); 30 } 31 if (logger.isDebugEnabled()) { 32 logger.debug("Could not read previous value of property '" + 33 this.nestedPath + propertyName + "'", ex); 34 } 35 } 36 } 37 valueToApply = convertForProperty( 38 propertyName, oldValue, originalValue, ph.toTypeDescriptor()); 39 } 40 pv.getOriginalPropertyValue().conversionNecessary = (valueToApply != originalValue); 41 } 42 ph.setValue(this.wrappedObject, valueToApply);
View Code
显然最终都是调用setPropertyValue来设置属性值的。真实注入的时候是发生在getBean的时候,在实例化完成后会调用populateBean方法。查看populateBean方法发现如下代码:
1 protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) { 2 PropertyValues pvs = mbd.getPropertyValues(); 3 4 if (bw == null) { 5 if (!pvs.isEmpty()) { 6 throw new BeanCreationException( 7 mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance"); 8 } 9 else { 10 // Skip property population phase for null instance. 11 return; 12 } 13 } 14 15 // Give any InstantiationAwareBeanPostProcessors the opportunity to modify the 16 // state of the bean before properties are set. This can be used, for example, 17 // to support styles of field injection. 18 boolean continueWithPropertyPopulation = true; 19 20 if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) { 21 for (BeanPostProcessor bp : getBeanPostProcessors()) { 22 if (bp instanceof InstantiationAwareBeanPostProcessor) { 23 InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp; 24 if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) { 25 continueWithPropertyPopulation = false; 26 break; 27 } 28 } 29 } 30 } 31 32 if (!continueWithPropertyPopulation) { 33 return; 34 } 35 36 if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME || 37 mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) { 38 MutablePropertyValues newPvs = new MutablePropertyValues(pvs); 39 40 // Add property values based on autowire by name if applicable. 41 if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) { 42 autowireByName(beanName, mbd, bw, newPvs); 43 } 44 45 // Add property values based on autowire by type if applicable. 46 if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) { 47 autowireByType(beanName, mbd, bw, newPvs); 48 } 49 50 pvs = newPvs; 51 } 52 53 boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors(); 54 boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE); 55 56 if (hasInstAwareBpps || needsDepCheck) { 57 PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching); 58 if (hasInstAwareBpps) { 59 for (BeanPostProcessor bp : getBeanPostProcessors()) { 60 if (bp instanceof InstantiationAwareBeanPostProcessor) { 61 InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp; 62 pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName); 63 if (pvs == null) { 64 return; 65 } 66 } 67 } 68 } 69 if (needsDepCheck) { 70 checkDependencies(beanName, mbd, filteredPds, pvs); 71 } 72 } 73 74 applyPropertyValues(beanName, mbd, bw, pvs); 75 }
View Code
注意如下代码:
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp; pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
在给属性赋值之前会调用InstantiationAwareBeanPostProcessor的postProcessPropertyValues方法,获取最终的PropertyValues。
在Spring注入的InstantionAwaireBeanPostProcessor中比较关键的子类就是处理@Autowired的子类,AutowiredAnnotationBeanPostProcessor。下如战士postProcessPropertyValues的实现过程,只列出了几个关键的方法。
(1) findAutowiringMetadata方法的主要功能是对InjectMetadata添加了本地缓存,真实的解析InjectMetadata会使用反射,添加缓存可以名小减少对反射的依赖。真实的生成InjectMetadata是buildAutowiringMetadata方法。
1 private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) { 2 LinkedList<InjectionMetadata.InjectedElement> elements = new LinkedList<InjectionMetadata.InjectedElement>(); 3 Class<?> targetClass = clazz; 4 5 do { 6 final LinkedList<InjectionMetadata.InjectedElement> currElements = 7 new LinkedList<InjectionMetadata.InjectedElement>(); 8 9 ReflectionUtils.doWithLocalFields(targetClass, new ReflectionUtils.FieldCallback() { 10 @Override 11 public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException { 12 AnnotationAttributes ann = findAutowiredAnnotation(field); 13 if (ann != null) { 14 if (Modifier.isStatic(field.getModifiers())) { 15 if (logger.isWarnEnabled()) { 16 logger.warn("Autowired annotation is not supported on static fields: " + field); 17 } 18 return; 19 } 20 boolean required = determineRequiredStatus(ann); 21 currElements.add(new AutowiredFieldElement(field, required)); 22 } 23 } 24 }); 25 26 ReflectionUtils.doWithLocalMethods(targetClass, new ReflectionUtils.MethodCallback() { 27 @Override 28 public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException { 29 Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method); 30 if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) { 31 return; 32 } 33 AnnotationAttributes ann = findAutowiredAnnotation(bridgedMethod); 34 if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) { 35 if (Modifier.isStatic(method.getModifiers())) { 36 if (logger.isWarnEnabled()) { 37 logger.warn("Autowired annotation is not supported on static methods: " + method); 38 } 39 return; 40 } 41 if (method.getParameterTypes().length == 0) { 42 if (logger.isWarnEnabled()) { 43 logger.warn("Autowired annotation should be used on methods with parameters: " + method); 44 } 45 } 46 boolean required = determineRequiredStatus(ann); 47 PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz); 48 currElements.add(new AutowiredMethodElement(method, required, pd)); 49 } 50 } 51 }); 52 53 elements.addAll(0, currElements); 54 targetClass = targetClass.getSuperclass(); 55 } 56 while (targetClass != null && targetClass != Object.class); 57 58 return new InjectionMetadata(clazz, elements); 59 }
buildAutowiringMetadata
其实doWithLocalFields和doWithLocalMethods比较类似,都使用策略模式的实现回调方法来实现。这种回调方式是常用的方法。
1 ReflectionUtils.doWithLocalFields(targetClass, new ReflectionUtils.FieldCallback() { 2 @Override 3 public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException { 4 AnnotationAttributes ann = findAutowiredAnnotation(field); 5 if (ann != null) { 6 if (Modifier.isStatic(field.getModifiers())) { 7 if (logger.isWarnEnabled()) { 8 logger.warn("Autowired annotation is not supported on static fields: " + field); 9 } 10 return; 11 } 12 boolean required = determineRequiredStatus(ann); 13 currElements.add(new AutowiredFieldElement(field, required)); 14 } 15 } 16 });
doWithLocalFields
1 public static void doWithLocalFields(Class<?> clazz, FieldCallback fc) { 2 for (Field field : getDeclaredFields(clazz)) { 3 try { 4 fc.doWith(field); 5 } 6 catch (IllegalAccessException ex) { 7 throw new IllegalStateException("Not allowed to access field '" + field.getName() + "': " + ex); 8 } 9 } 10 }
doWithLocalFields
注意到@Autowired不支持静态注入的原因,就是增加了判断签名为static的时候,并没有解析。
InjectElement有两个关键子类,AutowiredMethodElement主要解决method上面的注解,AutowiredFieldElement主要解决field上面的注解。不同之处就是field会从容器查找filed对应的bean,method会将每一个参数都注入。其最关键的方法均为resolveDependency方法。其中观察resolveDependency方法的调用中有个关键方法findAutowireCandidates。
1 protected Map<String, Object> findAutowireCandidates( 2 String beanName, Class<?> requiredType, DependencyDescriptor descriptor) { 3 4 String[] candidateNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors( 5 this, requiredType, true, descriptor.isEager()); 6 Map<String, Object> result = new LinkedHashMap<String, Object>(candidateNames.length); 7 for (Class<?> autowiringType : this.resolvableDependencies.keySet()) { 8 if (autowiringType.isAssignableFrom(requiredType)) { 9 Object autowiringValue = this.resolvableDependencies.get(autowiringType); 10 autowiringValue = AutowireUtils.resolveAutowiringValue(autowiringValue, requiredType); 11 if (requiredType.isInstance(autowiringValue)) { 12 result.put(ObjectUtils.identityToString(autowiringValue), autowiringValue); 13 break; 14 } 15 } 16 } 17 for (String candidateName : candidateNames) { 18 if (!isSelfReference(beanName, candidateName) && isAutowireCandidate(candidateName, descriptor)) { 19 addCandidateEntry(result, candidateName, descriptor, requiredType); 20 } 21 } 22 if (result.isEmpty() && !indicatesMultipleBeans(requiredType)) { 23 // Consider fallback matches if the first pass failed to find anything... 24 DependencyDescriptor fallbackDescriptor = descriptor.forFallbackMatch(); 25 for (String candidateName : candidateNames) { 26 if (!isSelfReference(beanName, candidateName) && isAutowireCandidate(candidateName, fallbackDescriptor)) { 27 addCandidateEntry(result, candidateName, descriptor, requiredType); 28 } 29 } 30 if (result.isEmpty()) { 31 // Consider self references before as a final pass 32 for (String candidateName : candidateNames) { 33 if (isSelfReference(beanName, candidateName) && isAutowireCandidate(candidateName, fallbackDescriptor)) { 34 addCandidateEntry(result, candidateName, descriptor, requiredType); 35 } 36 } 37 } 38 } 39 return result; 40 }
View Code
首先处理的是resolevableDependencies,如果已经注册依赖,直接从注册的依赖中提取。否则直接调用getType方法获取bean。注册依赖可能是容易被忽略的。
在refresh中就有直接注册依赖的调用:
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {....//省略部分代码beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);beanFactory.registerResolvableDependency(ResourceLoader.class, this);beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);beanFactory.registerResolvableDependency(ApplicationContext.class, this);......//省略部分代码 } }
转载于:https://www.cnblogs.com/dragonfei/p/5973855.html
Spring 之autowired相关推荐
- Spring中@Autowired、@Qualifier、@Resource的区别
转自: Spring中@Autowired.@Qualifier.@Resource的区别_老周聊架构的博客-CSDN博客_qualifier和resource区别1.@Autowired@Autow ...
- Spring的@Autowired和@Resource
@Autowired 当Spring发现@Autowired注解时,将自动在代码上下文中找到和其匹配(默认是类型匹配)的Bean,并自动注入到相应的地方去. 必须确保该类型在IOC容器中只有一个对象: ...
- Spring注解@Autowired
Spring注解@Autowired 一.@Autowired注解作用 1.@Autowired 注解@Autowired是Spring对组件自动装配的一种方式.常用于在一个组件中引入其他组件. // ...
- Spring之autowired
spring提供@autowired注解来对组件进行注入初始化,其底层机制是利用java反射来控制组件的访问, 这简化了我们的编程,省掉了一堆毫无业务逻辑的set方法. 但是我们需要注意的是,auto ...
- Spring中@Autowired注解、@Resource注解的区别
Spring不但支持自己定义的@Autowired注解,还支持几个由JSR-250规范定义的注解,它们分别是@Resource.@PostConstruct以及@PreDestroy. @Resour ...
- 使用Spring的@Autowired 实现DAO, Service, Controller三层的注入(转)
简述: 结合Spring和Hibernate进行开发 使用@Autowired实现依赖注入, 实现一个学生注册的功能,做一个技术原型 从DAO(Repository) -> Service -& ...
- Spring中@Autowired和@Resource区别
Spring可以基于注解方式配置并注入依赖.在Java代码中使用@Resource或者@Autowired注解方式注入. 1. @Resource: 1)默认按照名称装配注入,只有当找不到与名称nam ...
- Spring中 @Autowired注解与@Resource注解的区别
相同点: @Resource的作用相当于@Autowired,均可标注在字段或属性的setter方法上. 不同点: (1)提供方:@Autowired是由org.springframework.bea ...
- 为什么使用Spring的@autowired注解后就不用写setter了
问题: 在java中如果属性或者方法的标识符是private的话,是不能直接访问这个属性的,必须通过setter和getter方法才能够访问这个属性,那么使用@autowired注解来完成属性的依赖注 ...
- spring的Autowired和@Resource的区别是什么
2019独角兽企业重金招聘Python工程师标准>>> @Resource默认按照名称方式进行bean匹配,@Autowired默认按照类型方式进行bean匹配 @Resource( ...
最新文章
- 移动端touchstart、touchmove事件的基本使用
- 《ES6标准入门》49~68Page 数值的拓展 数组的拓展
- uboot启动过程中关闭Caches
- GUI_PICTURE以及context_menu学习笔记
- Dreamweaver 2019安装教程
- 做网页前端遇到的一些问题
- MapReduce算法设计(三)----相对频率计算
- 判断字符串中是否包含指定字符(JavaScript)
- SQL转换全角和半角函数
- bartender实现即扫即打印功能扫描完后自动打印_日本彩色激光打印机推荐人气排名15款...
- Linux学习笔记005----CentOS7 vi模式保存并退出
- java中的interface
- Mysql(2)_ binlog文件
- 论文丨免费下载SCI全文文献的10个方法
- 林子雨大数据软件安装和编程指南导航
- springboot xml转json工具类
- 微信公众号使用:给微信公众号设置头像和微信号的步骤
- 程序员的工资是不是太高了?真相让人心疼
- 安卓电子书格式_纯干货|提升电子书阅读体验的四点感受
- 菲波那切数列(剑指offer)---c语言
热门文章
- webpack配置_webpack的配置
- ofdma技术_数字化领航 | Wi-Fi 6 关键技术剖析
- C语言:编写一个程序,建立一个abc.txt文本文件,向其中写入“this is a test”,然后显示该字符串
- xmpppy获取服务器版本信息,为什么XMPP? - 今幕明的个人页面 - OSCHINA - 中文开源技术交流社区...
- while求和java,while语句基本练习(求和思想,统计思想)
- Hive union vs union all
- WinDbg常用命令For Kernel Debug
- 微信小程序多位验证码/密码输入框
- centos7---mysql5.7主从复制读写分离
- POJ 1755 Triathlon(半平面交)