有没有办法使@Bean可区分的一些豆类创建



这是一个异国情调的用例,因此需要耐心才能理解并且可能需要异国情调的解决方案。

上下文

我正在制作一个与弹簧一起使用的库,该库在上下文中存在的特定bean实例上执行自动操作,而不是由@Bean方法创建,而不是由@ComponentScan创建。如果可能的话,bean应该不是按类型来区分的,而应通过其他方式来区分,最好是出厂方法上的注释

这是理想的情况。例如。假设有2种豆类生产方法:

@Bean
public SomeType makeSome() {...}
@Bean
@Special
public SomeOtherType makeOther() {...}

在这里,第二个bean是 special ,因为在创建它的方法上的@Special注释。但是任何使其可区分的机制都是选项

然后,我想以某种方式获得 special bean。

警告

我知道,如果所有豆类都可以实现相同的接口,我可以按类型注入它们。但这应该尽可能透明地工作,需要对现有应用的更改。

潜在方法

这是我想到的两种广泛方法:

1(插入注册豆的过程,然后将bean实例透明地包裹在某种容器中(我很确定这部分是可行的(。例如

public void registerBean(Object bean, ApplicationContext ctx) {
   ctx.register(bean); //do the usual
   ctx.register(new Wrapper(bean); //register it wrapped as well
}

然后,注入Wrapper类型的所有豆类。这里的问题显然是重复的...另外,我可以即时生成一个可以实现Wrapper接口的代理实例,因此它可以同时用作原始bean and 作为一个包装纸。我确实说我也可以对异国情调的解决方案,不是吗?

2(Spring已经将Bean 候选者与实际注册豆区分开(例如@ComponentScan可以通过包装,注释等过滤候选者(。我希望也许能进入此过程,并掌握候选人的描述符,这些描述符仍然包含一些有用的元数据(例如他们的工厂方法(,这些元数据允许我以后区分这些bean实例。

似乎您需要使用 @Qualifier,它提供了区分豆的功能:

@Bean
@Qualifier("special")
class MyBean {}
@Bean
class OtherBean {
    @Qualifier("special")
    private MyBean bean;
}

您可以在此处阅读更多信息:https://spring.io/blog/2014/11/11/04/a-quality-qualifier

upd(了解您在说什么:)(您可能想看看BeanDefinitionRegistryPostProcessor

在这里使用样本:

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.AnnotatedGenericBeanDefinition;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import static java.util.Collections.unmodifiableMap;
/**
 * This is hack to collect all beans of some type in single map without eager initialization of those beans
 *
 * Usage:
 * 1. Register new bean of type {@link ServiceTrackingBeanPostProcessor} parametrized with class of
 *    beans you want to collect
 * 2. Now you can inject {@link ServiceTracker} parametrized with your type anywhere
 *
 * @param <T> Located type
 */
public class ServiceTrackingBeanPostProcessor<T> implements BeanPostProcessor, BeanDefinitionRegistryPostProcessor {
    private final ConcurrentMap<String, T> registeredBeans = new ConcurrentHashMap<>();
    private final Class<T> clazz;
    private final String beanName;
    public ServiceTrackingBeanPostProcessor(Class<T> clazz) {
        this.clazz = clazz;
        beanName = "locatorFor" + clazz.getCanonicalName().replace('.', '_');
    }
    @Override
    public Object postProcessBeforeInitialization(Object o, String s) throws BeansException {
        return o;
    }
    @Override
    public Object postProcessAfterInitialization(Object o, String s) throws BeansException {
        if (!clazz.isInstance(o)) {
            return o;
        }
        registeredBeans.putIfAbsent(s, (T) o);
        return o;
    }
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        AnnotatedGenericBeanDefinition def = new AnnotatedGenericBeanDefinition(Wrapper.class);
        registry.registerBeanDefinition(beanName, def);
    }
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        beanFactory.registerSingleton(beanName, new Wrapper(unmodifiableMap(registeredBeans)));
    }
    private class Wrapper extends AbstractServiceTracker<T> {
        public Wrapper(Map<String, T> services) {
            super(services);
        }
    }
}

您只需要将检查条件从clazz.isInstance更改为从应用程序上下文获得BeanDefinition的BEAN名称,您几乎可以获取有关实例化和注释的任何信息

这是一种用@Special注释获得所有bean的一种方法。

Map<String,Object> beans = applicationContext.getBeansWithAnnotation(Special.class);

参考:https://stackoverflow.com/a/14236573/1490322

编辑:上面的答案似乎仅在使用@Special注释的课程时工作,因此它不适用于您的方案。但是对同一问题的另一个答案可能会起作用。它使用来自configurallistablebeanfactory的元数据来识别使用特定注释注释的方法的任何bean。

我认为@qualifier注释是一种方法。但是我将显示不同的例子:

@Bean
public SomeType makeSome() {...}
@Bean
public SomeType makeSomeOther() {...}

在您的组件(@service(中,您想要的豆子可以:

@Autowired
@Qualifier("makeSome")
SomeType makeSomeBean;

您看到的两个具有相同类型的豆子可以通过bean名称来区分(bean分配了与@Bean注释方法相同的名称(

相关内容

  • 没有找到相关文章

最新更新