当前位置: 首页 > 知识库问答 >
问题:

使用Spring IoC在Guava EventBus中自动注册beans

狄珂
2023-03-14

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

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

我有很多bean实现了这个用@Component注释的接口,因此它们在Spring IoC中可用。我还有一个活动巴士豆:

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

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

languageSwitcher.register(myNewBean);

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

共有3个答案

岑明辉
2023-03-14

为事件总线使用工厂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对其进行注释

孟德曜
2023-03-14

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应用程序中是必要的,因为注释不是在对象的实际(动态)类上,而是在父类上。

鞠子轩
2023-03-14

好,使用一个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;
    }

}

请注意,如果您有许多事件总线字节,则应使用应用程序上下文.getBean(字符串来获取所需的事件总线。

我引用javadoc:

对于FactoryBean,将为FactoryBean实例和由FactoryBean创建的对象调用此回调(从Spring 2.0开始)。后处理器可以通过FactoryBean检查的相应Bean实例来决定是应用于FactoryBean还是创建的对象,或者同时应用于两者。

 类似资料:
  • 使用Spark,决定使用Kryo,因为它是推荐的反序列化程序。 假设我有: 我需要注册两个班级吗

  • 问题内容: 我们正在Symfony 2中从头开始构建一个业务应用程序,我在用户注册流程上遇到了一些麻烦:用户创建帐户后,应该使用这些凭据自动登录。立即被迫再次提供其凭据。 任何人都对此有任何经验,或者能够为我指明正确的方向? 问题答案: Symfony 4.0 此过程尚未从symfony 3更改为4,但是这里是使用新推荐的AbstractController的示例。无论是和服务注册在父方法,所以你

  • 问题内容: 我希望能够创建一个python装饰器,该装饰器会在全局存储库(具有某些属性)中自动“注册”类方法。 示例代码: 我希望加载完成后,某处将包含以下内容: 这可能吗? 问题答案: 不只是装饰,不。但是,元类可以在创建类后自动使用它。如果您的装饰器仅记录了元类应该做什么,则可以执行以下操作: 印刷

  • 问题内容: 这是我目前用于注册的内容: 是否可以不要求用户在创建帐户后手动登录,而是简单地自动登录?谢谢。 编辑:我曾尝试过login()函数,但没有成功。我相信问题是未设置AUTHENTICATION_BACKENDS。 问题答案: 使用authenticate()和login()功能:

  • 我试图使用kafka-avro-console-producer 5.4.0-ccs不自动注册模式。我试着用: 但它仍然在注册模式。属性似乎正确:https://github.com/confluentinc/schema-registry/blob/a0a04628687a72ac6d01869d881a60fbde4177e7/avro-serializer/src/main/java/io/

  • 问题内容: 我想要在spring成功注册后自动登录:我有一个受保护的页面,需要登录才能访问它们,我要在注册后跳过登录页面并进行自动登录,以便用户可以看到受保护的页面有我吗?我正在使用spring 3.0,spring security 3.0.2,该怎么做? 问题答案: 可以通过以下方式(半伪代码)通过spring安全性完成此操作: 更新:仅包含注册后如何创建会话