自定义 AutowireCandidateResolver

2021-07-09  本文已影响0人  蓝笔头

(一)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 beanprint() 方法。

@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)通过在定义一个 ApplicationContextInitializerMyContextAnnotationAutowireCandidateResolver 配置为 BeanFactoryAutowireCandidateResolver

@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 :

参考

上一篇 下一篇

猜你喜欢

热点阅读