5

假设我的应用程序中有一个语言更改事件接口(它基于 Vaadin):

public interface ILanguageChangeListener{
    @Subscribe onLanguageChange(LanguageChangeEvent event);
}

而且我有许多 bean 实现了这个用 @Component 注释的接口,因此它们在 Spring IoC 中可用。我还有一个 EventBus bean:

<bean id="languageSwitcher" class="com.google.common.eventbus" scope="session" />

现在,在从 IoC 获取任何 bean 的实例后,我还必须获取 languageSwitcher 的实例并在其中注册新创建的 bean:

languageSwitcher.register(myNewBean);

为了接收这个事件。是否有可能以某种方式告诉 IoC 我想在每个实现 ILanguageChangeListener 的新 bean 上调用 languageSwitcher bean 的 register 方法?

4

4 回答 4

9

好的,使用 BeanPostProcessor,注册接口的每个 bean:

public class EventBusRegisterBeanPostProcessor implements BeanPostProcessor,
        ApplicationContextAware {

    private ApplicationContext context;

    @Autowired
    private EventBus eventBus; // The only event bus i assume...

    public Object postProcessBeforeInitialization(Object bean, String beanName)
            throws BeansException {

        return bean;
    }

    public Object postProcessAfterInitialization(Object bean, String beanName)
            throws BeansException {

        if (bean instanceof ILanguageChangeListener) {
            registerToEventBus(bean);
        }

        return bean;
    }

    private void registerToEventBus(Object bean) {
        this.eventBus.register(bean);
    }

    public void setApplicationContext(ApplicationContext applicationContext)
            throws BeansException {
        this.context = applicationContext;
    }

}

请注意,如果您有许多 EventBus bean,则应使用ApplicationContext.getBean(String)来获取所需的 EventBus。

我引用javadoc

在使用 FactoryBean 的情况下,将为 FactoryBean 实例和由 FactoryBean 创建的对象(从 Spring 2.0 开始)调用此回调。后处理器可以通过相应的 bean instanceof FactoryBean 检查来决定是否应用到 FactoryBean 或创建的对象或两者。

于 2012-12-10T19:51:23.150 回答
3

IMO,使用类级别注释来标记应该注册的bean,而不是实现标记接口,它甚至更好(耦合更少)。这是修改后的 bean 后处理器代码:

public class EventBusListenersRegistererBeanPostProcessor implements BeanPostProcessor{

    Logger log = LoggerFactory.getLogger(this.getClass());

    @Inject
    private EventBus bus;

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if(bean.getClass().isAnnotationPresent(RegisterWithEventBus.class)){
            log.info("Event Bus is registering bean named \"{}\" of class {}.", beanName, bean.getClass().getCanonicalName());
            bus.register(bean);
        }

        return bean;
    }
}

和注释:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Inherited // important when working with dynamically generated proxies i.e. CGLib
public @interface RegisterWithEventBus {}

请注意,注释接口具有 @Inherited 元注释。这在使用 CGLIB 代理的 Spring 应用程序中是必需的,因为注释不会在对象的实际(动态)类上,而是在父类上。

于 2016-03-20T19:27:49.853 回答
1

为您的事件总线使用工厂 bean,并在您的上下文中注入所有 ILanguageChangeListener bean 的列表。

public class EventBusFactoryBean implements FactoryBean<EventBus> {

    @Autowired
    private List<ILanguageChangeListener> languageChangeListeners;

    private EventBus instance;

    @PostConstruct
    public void init() {

        this.instance = new EventBus();

        for (ILanguageChangeListener listener : this.languageChangeListeners) {
            this.instance.register(listener);
        }
    }

    public EventBusFactoryBean() {

    }

    public EventBus getObject() throws Exception {
        return this.instance;
    }

    public Class<?> getObjectType() {
        return EventBus.class;
    }

    public boolean isSingleton() {
        return true;
    }

    public List<ILanguageChangeListener> getLanguageChangeListeners() {
        return languageChangeListeners;
    }

    public void setLanguageChangeListeners(
            List<ILanguageChangeListener> languageChangeListeners) {
        this.languageChangeListeners = languageChangeListeners;
    }

}

然后在 Spring Bean 定义文件中定义你的 bean 或者用@Component

于 2012-12-10T19:25:47.487 回答
0

一种方法是使用接口InitializingBean并在您的 bean 中注入语言切换器。像这样的东西:

public class NotVeryUsefulLanguageListener implements ILanguageChangeListener,
        InitializingBean {

    @Autowired
    private EventBus languageSwitcher;

    public void afterPropertiesSet() throws Exception {

        this.languageSwitcher.register(this);
    }

    //... getters, setters, etc

}

如果NotVeryUsefulLanguageLisetener是单例,它只会发生一次……如果是原型,那么每次你从 Spring 获得一个实例

如果您使用的是 XML,那么您可以使用如下内容:

<bean id="languageListenerA" init-method="afterPropertiesSet" class="org.company.whatever.NotVeryUsefulLanguageListener">
        <!-- stuff -->
    </bean>
于 2012-12-10T16:44:35.187 回答