likes
comments
collection
share

自定义BeanFactoryPostProcessor的实现

作者站长头像
站长
· 阅读数 24

一:BeanFactoryPostProcessor的执行时机

在自定义BeanFactoryPostProcessor之前,我们需要了解下其执行的时机,才能知道该如何去自定义。

下面,我们看下Spring源码里面BeanFactoryPostProcessor的执行时机。

public void refresh() throws BeansException, IllegalStateException {
    synchronized(this.startupShutdownMonitor) {
        StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");
        this.prepareRefresh();
        ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
        this.prepareBeanFactory(beanFactory);

        try {
            ...
            this.invokeBeanFactoryPostProcessors(beanFactory);
            ...
            this.finishRefresh();
        } catch (BeansException var10) {
            this.destroyBeans();
            this.cancelRefresh(var10);
        } finally {
            this.resetCommonCaches();
        }

    }
}
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
    this.refreshBeanFactory();
    return this.getBeanFactory();
}
protected final void refreshBeanFactory() throws BeansException {
    if (this.hasBeanFactory()) {
        this.destroyBeans();
        this.closeBeanFactory();
    }

    try {
        DefaultListableBeanFactory beanFactory = this.createBeanFactory();
        beanFactory.setSerializationId(this.getId());
        this.customizeBeanFactory(beanFactory);
        this.loadBeanDefinitions(beanFactory);
        this.beanFactory = beanFactory;
    } catch (IOException var2) {
        throw new ApplicationContextException("I/O error parsing bean definition source for " + this.getDisplayName(), var2);
    }
}

在执行invokeBeanFactoryPostProcessors方法之前,会先执行obtainFreshBeanFactory方法,在该方法中,我们会看到调用了loadBeanDefinitions,会从各种配置中去加载bean的定义信息。

所以,我们可以得出结论,当需要在BeanFactory加载Bean定义后,Bean实例化之前,向BeanFactory中注册新的Bean定义时,可以使用BeanFactoryPostProcessor接口来实现

二、自定义BeanFactoryPostProcessor

1、定义需要载入容器的bean信息

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface HandlerType {
    String[] value() default {};
}

public abstract class AbstractTaskRetry {
    /**
     * 监听设备心跳状态
     */
    abstract public void heartbeat(HeartbeatDTO heartbeatDTO);
}


@Component
@HandlerType("QC")
public class QcTaskRetryHandler extends AbstractTaskRetry {
    @Override
    public void heartbeat(HeartbeatDTO heartbeatDTO) {
    
    }
}

@Component
@HandlerType("RTG")
public class RtgTaskRetryHandler extends AbstractTaskRetry {
    @Override
    public void heartbeat(HeartbeatDTO heartbeatDTO) {
    
    }
}

2、定义BeanFactoryPostProcessor的实现类

public class HandlerContext {

    private Map<String, Class> handlerMap;

    public HandlerContext(Map<String, Class> handlerMap) {
        this.handlerMap = handlerMap;
    }

    public AbstractTaskRetry getInstance(String type) {
        Class clazz = handlerMap.get(type);
        if (clazz == null) {
            throw new IllegalArgumentException("not found handler for type: " + type);
        }
        return (AbstractTaskRetry) SpringContextUtil.getBean(clazz);
    }
}

@Component
public class FacilityHeartbeatBeanFactoryPostProcessor implements BeanFactoryPostProcessor {

    private static final String HANDLER_PACKAGE = "com.jz.iecs.handler.biz";

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        Map<String, Class> handlerMap = Maps.newConcurrentMap();
        // 扫描到被HandlerType注解标识的类
        ClassScaner.scan(HANDLER_PACKAGE, HandlerType.class).forEach(clazz -> {
            String[] handlerTypes = clazz.getAnnotation(HandlerType.class).value();
            Arrays.stream(handlerTypes).collect(Collectors.toList()).forEach(type->{
                // 为什么此处不放对应的实例bean,而是放了对应的Class类???
                // 因为此刻只是加载了bean的定义信息,还没有进行bean的实例化与初始化
                handlerMap.put(type, clazz);
            });
        });
        // 将map属性放入HandlerContext,然后将HandlerContext纳入spring容器管理
        HandlerContext context = new HandlerContext(handlerMap);
        beanFactory.registerSingleton(HandlerContext.class.getName(), context);
    }
}

三、使用自动装配注解运用自定义的bean实例

因为在开篇的refresh的执行步骤中,有一个invokeBeanFactoryPostProcessors方法,里面会调用具体的postProcessBeanFactory,逐一进行beanFactory的实例注册。

public static void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
    //收集所有BeanFactoryPostProcessor实现类的bean名称
    String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);
    regularPostProcessors = new ArrayList();
    registryProcessors = new ArrayList();
    currentRegistryProcessors = new ArrayList();
    postProcessorNames = postProcessorNames;
    int var20 = postProcessorNames.length;

    String ppName;
    for(var9 = 0; var9 < var20; ++var9) {
        ppName = postProcessorNames[var9];
        if (!processedBeans.contains(ppName)) {
            if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
                regularPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
            } else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
                registryProcessors.add(ppName);
            } else {
                currentRegistryProcessors.add(ppName);
            }
        }
    }

    // 优先执行实现PriorityOrdered接口的
    sortPostProcessors(regularPostProcessors, beanFactory);
    invokeBeanFactoryPostProcessors((Collection)regularPostProcessors, (ConfigurableListableBeanFactory)beanFactory);
    List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList(registryProcessors.size());
    Iterator var21 = registryProcessors.iterator();

    while(var21.hasNext()) {
        String postProcessorName = (String)var21.next();
        orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
    }

    // 其次执行实现Ordered接口的
    sortPostProcessors(orderedPostProcessors, beanFactory);
    invokeBeanFactoryPostProcessors((Collection)orderedPostProcessors, (ConfigurableListableBeanFactory)beanFactory);
    List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList(currentRegistryProcessors.size());
    Iterator var24 = currentRegistryProcessors.iterator();

    while(var24.hasNext()) {
        ppName = (String)var24.next();
        nonOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
    }
    
    // 最后执行既没有实现PriorityOrdered,也没有实现Ordered接口的
    invokeBeanFactoryPostProcessors((Collection)nonOrderedPostProcessors, (ConfigurableListableBeanFactory)beanFactory);
    beanFactory.clearMetadataCache();
}
private static void invokeBeanFactoryPostProcessors(Collection<? extends BeanFactoryPostProcessor> postProcessors, ConfigurableListableBeanFactory beanFactory) {
    Iterator var2 = postProcessors.iterator();

    while(var2.hasNext()) {
        BeanFactoryPostProcessor postProcessor = (BeanFactoryPostProcessor)var2.next();
        StartupStep var10000 = beanFactory.getApplicationStartup().start("spring.context.bean-factory.post-process");
        postProcessor.getClass();
        StartupStep postProcessBeanFactory = var10000.tag("postProcessor", postProcessor::toString);
        postProcessor.postProcessBeanFactory(beanFactory);
        postProcessBeanFactory.end();
    }

}

到此,所有的BeanFactoryPostProcessor的postProcessBeanFactory方法都会被调用,包括我们自定义的BeanFactoryPostProcessor,那么HandlerContext这类我们自己定义的bean实例就会被注册到容器中,我们在使用的过程中,就可以通过自动注入的方式来进行使用。

@Autowired
private HandlerContext handlerContext;

@Override
public void facilityHeartbeat(HeartbeatDTO heartbeatDTO) {
    if (StringUtils.isEmpty(heartbeatDTO.getMachType())){
        return;
    }
    handlerContext
        // 获取具体的实现类
        .getInstance(heartbeatDTO.getMachType())
        // 调用具体方法
        .process(heartbeatDTO);
}
转载自:https://juejin.cn/post/7372469324983189554
评论
请登录