(一)AutowireCandidateResolver 流程剖析
AutowireCandidateResolver
:用于确定特定BeanDefinition
是否有资格作为特定依赖项的自动装配候选者的策略接口。
接口定义:
public interface AutowireCandidateResolver {
// 确定给定的 BeanDefinition 是否有资格作为给定依赖项的自动装配候选者
default boolean isAutowireCandidate(BeanDefinitionHolder bdHolder, DependencyDescriptor descriptor) {
return bdHolder.getBeanDefinition().isAutowireCandidate();
}
// 指定的依赖是否是必要的
// 仅在没有候选者 bean 或者存在多个候选者 bean 的时候有用
default boolean isRequired(DependencyDescriptor descriptor) {
return descriptor.isRequired();
}
}
源码解读:
package org.springframework.beans.factory.support;
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
...
public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
...
try {
// 1. 查找符合条件的所有的 Bean
// 条件:isAutowireCandidate() 返回 true
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
if (matchingBeans.isEmpty()) {
// 2. 没有符合条件的 Bean
if (isRequired(descriptor)) {
// 2.1 isRequired()==true,需要进行依赖注入。抛出异常
raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
}
// 2.2 isRequired()==false,不需要进行依赖注入。则返回 null
return null;
}
String autowiredBeanName;
Object instanceCandidate;
if (matchingBeans.size() > 1) {
// 3. 从多个候选者中选取优先级最高的一个
// 查找是否有候选者被 @Primary 注解
// or 查找 @Priority 最大的一个
autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
if (autowiredBeanName == null) {
// 4. 没有找到
if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {
// 4.1 isRequired()==true,需要进行依赖注入
// 4.2 !indicatesMultipleBeans(type),表示不是一个集合(Array、Collection、Map)
// 抛出异常
return descriptor.resolveNotUnique(descriptor.getResolvableType(), matchingBeans);
}
else {
// 4.3 否则,则返回 null
return null;
}
}
// 5. 返回找到的候选者实例
instanceCandidate = matchingBeans.get(autowiredBeanName);
}
else {
// We have exactly one match.
// 6. 只有一个候选者,返回即可。
}
return result;
}
}
}
1)定义一个接口,和两个实现此接口的 Spring Bean
public interface MyService {
void print();
}
@Slf4j
@Component
public class AService implements MyService {
@Override
public void print() {
log.info("I am the AService");
}
}
@Slf4j
@Component
public class BService implements MyService {
@Override
public void print() {
log.info("I am the BService");
}
}
2)在另一个 Spring Bean 中注入此接口的 Bean
@Service
@RequiredArgsConstructor
public class DemoService {
private final MyService aService;
public void print() {
aService.print();
}
}
3)启动服务,打印如下报错信息。
***************************
APPLICATION FAILED TO START
***************************
Description:
Parameter 0 of constructor in com.example.springdemo.service.DemoService required a single bean, but 2 were found:
- AService: defined in file [F:\tmp\spring-demo\target\classes\com\example\springdemo\service\AService.class]
- BService: defined in file [F:\tmp\spring-demo\target\classes\com\example\springdemo\service\BService.class]
Action:
Consider marking one of the beans as @Primary, updating the consumer to accept multiple beans, or using @Qualifier to identify the bean that should be consumed
4)给 BService
添加 @Primary
注解。
@Slf4j
@Component
@Primary
public class BService implements MyService
5)调用 DemoService bean
的 print()
方法。
@Slf4j
@SpringBootApplication
public class SpringDemoApplication {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(SpringDemoApplication.class, args);
context.getBean(DemoService.class).print();
}
}
控制台输出:
2021-07-09 14:23:29.198 INFO 8608 --- [ main] com.example.springdemo.service.BService : I am the BService
(二)自定义 ApplicationContextInitializer
接口定义:
// 用于在 refresh() 方法调用之前初始化 Spring ConfigurableApplicationContext 的回调接口。
// 通常在需要对应用程序上下文进行一些编程初始化的 Web 应用程序中使用。
@FunctionalInterface
public interface ApplicationContextInitializer<C extends ConfigurableApplicationContext> {
/**
* Initialize the given application context.
* @param applicationContext the application to configure
*/
void initialize(C applicationContext);
}
1)实现 ApplicationContextInitializer
package com.example.springdemo.registry;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
@Slf4j
public class MyApplicationContextInitializer implements ApplicationContextInitializer {
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
log.info("-----MyApplicationContextInitializer initialize-----");
}
}
2)在 META-INF/spring.factories
中配置
org.springframework.context.ApplicationContextInitializer=com.example.springdemo.registry.MyApplicationContextInitializer
3)启动项目,控制台打印如下内容:
2021-07-08 19:45:14.426 INFO 17968 --- [ main] c.e.s.r.MyApplicationContextInitializer : -----MyApplicationContextInitializer initialize-----
(三)自定义 AutowireCandidateResolver
1)自定义一个 ContextAnnotationAutowireCandidateResolver
。
@Slf4j
public class MyContextAnnotationAutowireCandidateResolver extends ContextAnnotationAutowireCandidateResolver {
@Override
public boolean isAutowireCandidate(BeanDefinitionHolder bdHolder, DependencyDescriptor descriptor) {
boolean match = super.isAutowireCandidate(bdHolder, descriptor);
String beanClassName = bdHolder.getBeanDefinition().getBeanClassName();
if (beanClassName != null && beanClassName.startsWith("com.example.springdemo")) {
log.info("");
log.info("[isAutowireCandidate] [descriptor] dependencyName:{}, dependencyType:{}", descriptor.getDependencyName(), descriptor.getDependencyType());
log.info("[isAutowireCandidate] [bdHolder] beanName:{}, beanClassName:{}", bdHolder.getBeanName(), beanClassName);
log.info("[isAutowireCandidate] match:{}", match);
log.info("");
}
return match;
}
@Override
public boolean isRequired(DependencyDescriptor descriptor) {
boolean required = super.isRequired(descriptor);
if (descriptor.getDependencyType().getName().startsWith("com.example.springdemo")) {
log.info("");
log.info("[isRequired] [descriptor] dependencyName:{}, dependencyType:{}", descriptor.getDependencyName(), descriptor.getDependencyType());
log.info("[isRequired] required:{}", required);
log.info("");
}
return required;
}
}
2)通过在定义一个 ApplicationContextInitializer
将 MyContextAnnotationAutowireCandidateResolver
配置为 BeanFactory
的 AutowireCandidateResolver
@Slf4j
public class MyApplicationContextInitializer implements ApplicationContextInitializer {
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
log.info("-----MyApplicationContextInitializer initialize-----");
if (applicationContext.getBeanFactory() instanceof DefaultListableBeanFactory) {
DefaultListableBeanFactory bf = (DefaultListableBeanFactory) applicationContext.getBeanFactory();
bf.setAutowireCandidateResolver(new MyContextAnnotationAutowireCandidateResolver());
} else {
throw new IllegalStateException("错误的 BeanFactory");
}
}
}
3)启动服务,控制台打印如下内容:
2021-07-09 14:37:12.315 INFO 17004 --- [ main] ntextAnnotationAutowireCandidateResolver :
2021-07-09 14:37:12.315 INFO 17004 --- [ main] ntextAnnotationAutowireCandidateResolver : [isAutowireCandidate] [descriptor] dependencyName:aService, dependencyType:interface com.example.springdemo.service.MyService
2021-07-09 14:37:12.316 INFO 17004 --- [ main] ntextAnnotationAutowireCandidateResolver : [isAutowireCandidate] [bdHolder] beanName:AService, beanClassName:com.example.springdemo.service.AService
2021-07-09 14:37:12.316 INFO 17004 --- [ main] ntextAnnotationAutowireCandidateResolver : [isAutowireCandidate] match:true
2021-07-09 14:37:12.316 INFO 17004 --- [ main] ntextAnnotationAutowireCandidateResolver :
2021-07-09 14:37:12.316 INFO 17004 --- [ main] ntextAnnotationAutowireCandidateResolver :
2021-07-09 14:37:12.316 INFO 17004 --- [ main] ntextAnnotationAutowireCandidateResolver : [isAutowireCandidate] [descriptor] dependencyName:aService, dependencyType:interface com.example.springdemo.service.MyService
2021-07-09 14:37:12.316 INFO 17004 --- [ main] ntextAnnotationAutowireCandidateResolver : [isAutowireCandidate] [bdHolder] beanName:BService, beanClassName:com.example.springdemo.service.BService
2021-07-09 14:37:12.316 INFO 17004 --- [ main] ntextAnnotationAutowireCandidateResolver : [isAutowireCandidate] match:true
2021-07-09 14:37:12.316 INFO 17004 --- [ main] ntextAnnotationAutowireCandidateResolver :
2021-07-09 14:37:12.316 INFO 17004 --- [ main] ntextAnnotationAutowireCandidateResolver :
2021-07-09 14:37:12.317 INFO 17004 --- [ main] ntextAnnotationAutowireCandidateResolver : [isRequired] [descriptor] dependencyName:aService, dependencyType:interface com.example.springdemo.service.MyService
2021-07-09 14:37:12.317 INFO 17004 --- [ main] ntextAnnotationAutowireCandidateResolver : [isRequired] required:true
2021-07-09 14:37:12.317 INFO 17004 --- [ main] ntextAnnotationAutowireCandidateResolver :
2021-07-09 14:37:24.370 INFO 17004 --- [ main] ntextAnnotationAutowireCandidateResolver :
2021-07-09 14:37:24.371 INFO 17004 --- [ main] ntextAnnotationAutowireCandidateResolver : [isRequired] [descriptor] dependencyName:aService, dependencyType:interface com.example.springdemo.service.MyService
2021-07-09 14:37:24.371 INFO 17004 --- [ main] ntextAnnotationAutowireCandidateResolver : [isRequired] required:true
2021-07-09 14:37:24.372 INFO 17004 --- [ main] ntextAnnotationAutowireCandidateResolver :
网友评论