首先定义一个自定义注解,这个注解帮助我们去标记需要被我们自己工厂管理使用的Bean,同样我也希望能够结合使用 Spring 帮我将 Bean 创建并管理起来。

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Inherited
@Component
public @interface FactoryExecutor {
     ActionEnum[] actionType() default {};
}

这里是注解的使用,我们通过使用注解 @FactoryExecutor 标记不同的业务处理类。

​
@FactoryExecutor(actionType = {ActionEnum.RETREAT})
public class BackxxxExecute extends AbstractExecute {
    @Resource
    private XxxService xxxService;
    @Resource
    private XxTmpService xxTmpService;
​
    @Override
    public void execute(ExecuteBo info) {
            batchProcess(info, false, false, true);
        .... 
            handler(info);
    }

通过 autoRegisterHandler 方法从Spring容器中将标记为 @FactoryExecutor 注解 已经帮我们创建好的Bean对象找出来,然后 Put 到我们自己定义的 STRATEGY 容器中去,并对外提供 getStrategy 方法获取对应的策略使用。

​
@Component
public class XxxExecutorFactory {
    private static final Map<Integer, AbstractXxxExecute> STRATEGY = new HashMap<>();
    @Resource
    private ApplicationContext context;
​
​
    public static XxxExecute getStrategy(ActionEnum actionEnum) {
        if (null == actionEnum || !STRATEGY.containsKey(actionEnum.getCode())) {
            throw exception(XXXX_ACTION_NOT_EXISTS);
        }
        return STRATEGY.get(actionEnum.getCode());
    }
​
    @PostConstruct
    private synchronized void autoRegisterHandler() {
        String[] beanNames = context.getBeanNamesForAnnotation(FactoryExecutor.class);
        for (String beanName : beanNames) {
            Object beanInstance = context.getBean(beanName);
            StockExecutor taxTypeAnnotation = beanInstance.getClass().getAnnotation(FactoryExecutor.class);
            ActionEnum[] actions = taxTypeAnnotation.actionType();
            for (ActionEnum action : actions) {
                STRATEGY.put(action.getCode(), (AbstractStockExecute) beanInstance);
            }
        }
    }
}

关于 getBeanNamesForAnnotation 方法,从Spring源码可以看到具体实现是在 DefaultListableBeanFactory 这个类中。 是通过从 beanDefinitionMap 中去遍历查找有没有包含我们的自定义注解,有的话会将bean的名称放到List内最终返回。

    public String[] getBeanNamesForAnnotation(Class<? extends Annotation> annotationType) {
        List<String> result = new ArrayList();
        Iterator var3 = this.beanDefinitionNames.iterator();
​
        String beanName;
        while(var3.hasNext()) {
            beanName = (String)var3.next();
            BeanDefinition bd = (BeanDefinition)this.beanDefinitionMap.get(beanName);
            if (bd != null && !bd.isAbstract() && this.findAnnotationOnBean(beanName, annotationType) != null) {
                result.add(beanName);
            }
        }
​
        var3 = this.manualSingletonNames.iterator();
​
        while(var3.hasNext()) {
            beanName = (String)var3.next();
            if (!result.contains(beanName) && this.findAnnotationOnBean(beanName, annotationType) != null) {
                result.add(beanName);
            }
        }
​
        return StringUtils.toStringArray(result);
    }

关于 context.getBean(beanName) 方法,在这里如果我们需要获取的bean已经被Spring创建好放在单例池了,就会直接从单例池获取并返回,如果没有,就会走Spring的Bean创建流程,这里就不再展开了。