引
看见一个专栏,Spring 编程常见错误 50 例 ,进行spring知识点的相关巩固
非常赞同评论区的一句话:
之前忙业务需求疲于奔命,偶尔看些源码却只是窥豹一斑。
最近想把基础知识重新梳理一遍,搭建自己的知识体系。
spring core
spring boot 默认扫描包路径 - 扫描不到启动类同级包
ComponentScanAnnotationParser#parse
结论:使用启动类所在包作为基础包路径
bean存在构造方法 报Parameter 0 of constructor in xxx required a bean of type xxxx that could not be found.
创建bean调用的方法
AbstractAutowireCapableBeanFactory#createBeanInstance
首先获取可能的构造器,然后获取其构造参数进行创建(仅1个有参构造器时)
如果存在多个有参构造器,spring 会使用无参构造器,当不存在无参构造器时会抛出异常。
Constructor[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR || mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) { return autowireConstructor(beanName, mbd, ctors, args);}
@Autowired 装载原型bean prototype时,为每个类分别分配一个,每个类固定
当一个属性成员 serviceImpl 声明为 @Autowired 后,那么在创建 HelloWorldController 这个 Bean 时,会先使用构造器反射出实例,然后来装配各个标记为 @Autowired 的属性成员(装配方法参考 AbstractAutowireCapableBeanFactory#populateBean)。
AutowiredAnnotationBeanPostProcessor
它会通过 DefaultListableBeanFactory#findAutowireCandidates 寻找到依赖
然后设置给对应的属性(即 serviceImpl 成员)
AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement#inject:
@Lookup 主动的依赖查找
@RestController
public class HelloWorldController {
@RequestMapping(path = "hi", method = RequestMethod.GET)
public String hi() {
return "helloworld, service is : " + getServiceImpl();
};
@Lookup
public ServiceImpl getServiceImpl() {
return null;
}
}
原理,使用代理实现,获取函数返回类型,去容器中寻找,不调用原函数
CglibSubclassingInstantiationStrategy.LookupOverrideMethodInterceptor
LookupOverrideMethodInterceptor#intercept
@Autowired 发生位置与核心
- 执行 AbstractAutowireCapableBeanFactory#createBeanInstance 通过构造器反射构造出Bean
- 执行 AbstractAutowireCapableBeanFactory#populate 方法
- populate 方法遍历所有的BeanPostProcessor处理器
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
//省略非关键代码
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
//省略非关键代码
}
}
}
}
- 其中有AutowiredAnnotationBeanPostProcessor处理器
- 寻找所有需要注入的字段与方法,获取这些字段的元信息(类型)
InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
- AutowiredFieldElement#inject 从容器中找到依赖并使用反射完成注入
@Override
protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
Field field = (Field) this.member;
Object value;
//省略非关键代码
try {
DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
//寻找“依赖”,desc为"dataService"的DependencyDescriptor
value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
}
}
//省略非关键代码
if (value != null) {
ReflectionUtils.makeAccessible(field);
//装配“依赖”
field.set(bean, value);
}
}
@Autowire required a single bean, but 2 were found 原因
- 上述 value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
- DefaultListableBeanFactory#doResolveDependency
- 通过类型查找,找到大于1个以上该类型,触发优先级候选,如果没有优先级,判断是否是该对象是否必须的同时不是List Map 集合这种可以接受对个对象的DefaultListableBeanFactory#indicatesMultipleBeans,则要求该对象必须唯一,否则异常
候补选取流程:
是否有@Primary 如果有的话直接使用
否则使用@Priority 优先级高的
否则根据matchesBeanName,通过指定名称去匹配
DefaultListableBeanFactory#determineAutowireCandidate
protected String determineAutowireCandidate(Map<String, Object> candidates, DependencyDescriptor descriptor) {
Class<?> requiredType = descriptor.getDependencyType();
String primaryCandidate = determinePrimaryCandidate(candidates, requiredType);
if (primaryCandidate != null) {
return primaryCandidate;
}
String priorityCandidate = determineHighestPriorityCandidate(candidates, requiredType);
if (priorityCandidate != null) {
return priorityCandidate;
}
// Fallback
for (Map.Entry<String, Object> entry : candidates.entrySet()) {
String candidateName = entry.getKey();
Object beanInstance = entry.getValue();
if ((beanInstance != null && this.resolvableDependencies.containsValue(beanInstance)) ||
matchesBeanName(candidateName, descriptor.getDependencyName())) {
return candidateName;
}
}
return null;
}
@Priority(value=${number}),数字越小,优先级越高
默认bean名称的来源
- 先找到要生成bean的类(扫描),ClassPathBeanDefinitionScanner#doScan
- BeanNameGenerator#generateBeanName 调用该方法生成名称
- 走注解标记的bean,使用AnnotationBeanNameGenerator#generateBeanName 生成bean名称
@Override
public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
if (definition instanceof AnnotatedBeanDefinition) {
String beanName = determineBeanNameFromAnnotation((AnnotatedBeanDefinition) definition);
if (StringUtils.hasText(beanName)) {
// Explicit bean name found.
return beanName;
}
}
// Fallback: generate a unique default bean name.
return buildDefaultBeanName(definition, registry);
}
- 注解显示指定名称则使用显示名称,否则调用AnnotationBeanNameGenerator#buildDefaultBeanName
protected String buildDefaultBeanName(BeanDefinition definition) {
String beanClassName = definition.getBeanClassName();
Assert.state(beanClassName != null, "No bean class name set");
String shortClassName = ClassUtils.getShortName(beanClassName);
return Introspector.decapitalize(shortClassName);
}
public static String decapitalize(String name) {
if (name == null || name.length() == 0) {
return name;
}
if (name.length() > 1 && Character.isUpperCase(name.charAt(1)) &&
Character.isUpperCase(name.charAt(0))){
return name;
}
char chars[] = name.toCharArray();
chars[0] = Character.toLowerCase(chars[0]);
return new String(chars);
}
结论