質問

I have an application Config object that gathers information from several sources — .properties files, database tables, the OS, etc. — and makes this available to the rest of the application as if they were java.util.Properties, for example:

private static String devToAddress = Config.getConfig().getProperty("testAddress");

These are often stored, as shown above, as a static so it's always available to all instances of a class without having to constantly fetch it.

I also have a way to tell this (web) application to re-load these "properties" so I can reconfigure the application while it's running without doing a restart.

What I want to do is register with my Guava EventBus to subscribe to my "ConfigurationChangeEvent" so the class can update this devToAddress when I use my re-load feature. In some cases this may be a static class with only static methods that still needs the application Config information, so I can't necessarily count on having an instance to do the work of updating the static variables.

What I tried is this:

package com.sample.mw;

import com.google.common.eventbus.Subscribe;

import com.example.mw.events.ConfigurationChangeEvent;
import com.example.mw.events.EventDispatcher;
import com.example.mw.Config;

public class SampleMailer
{
    private static String devToAddress;

    // constructor(s)
    public SampleMailer()
    {
        // ...
    }

    // instance methods
    //    ...

    // static methods
    public static String getTheAddress()
    {
        return devToAddress;
    }

    @Subscribe
    public static void loadConfig(ConfigurationChangeEvent cce)
    {
        devToAddress = Config.getConfig().getProperty("testAddress");
    }

    // static/class registration with the event bus
    static
    {
        loadConfig(null); // initial config load without an event
        // 'EventDispatcher' is my singleton that encapsulates the EventBus
        EventDispatcher.getDispatcher().register(SampleMailer.class); // <-- not sure what to register here
    }
}

The questions are (a) Is this possible at all? Can you statically register with the Guava EventBus? (b) What Object do I pass to the EventBus .register(Object object) method?

役に立ちましたか?

解決

No, you can't register a static method with an EventBus... not directly. First of all, I'd strongly recommend trying to avoid a need for this to begin with. Static state like you have in SampleMailer is a smell.

That said, there's a pretty simple workaround here using an anonymous inner class:

eventBus.register(new Object() {
  @Subscribe
  public void loadConfig(ConfigurationChangeEvent cce) {
    SampleMailer.loadConfig(cce);
  }
});

But again, it should really probably be an instance method on something to begin with.

Edit: Huh, looks like EventBus will register a static method given an instance of that class. Still, I wouldn't recommend taking advantage of that: EventBus is based around registration of object instances as subscribers, and static subscriber methods interact somewhat strangely with that.

他のヒント

Following ColinD's answer, I found that the Guava @Subscribe annotation is perfectly happy registering and calling a static method, but it needs an instance passed for registration. The trick is you don't want to register the subscribed static method many times, for each instance, you only want to register once so the class loadConfig() method (below) doesn't get called 100 times when a reload occurs.

This slightly rewritten example better demonstrates how I actually use my configuration items; there are no getters and the world outside of this Class never sees the "state" of the config vars.

package com.sample.mw;

import com.google.common.eventbus.Subscribe;

import com.example.mw.events.ConfigurationChangeEvent;
import com.example.mw.events.EventDispatcher;
import com.example.mw.mail.Mailer;
import com.example.mw.Config;

public class SampleMailer
{
    private static boolean registered = false;

    private static String devToAddress;
    private static boolean override;

    // constructor(s)
    public SampleMailer()
    {
        if (!registered) // could be protected with synchronized() block
        {
            // 'EventDispatcher' is my singleton that encapsulates the EventBus
            // if you register 'this' instance it will find the annotated static method.
            EventDispatcher.getDispatcher().register(this);
            registered = true;
        }
    }

    // instance methods
    public void performAction(String toAddress)
    {
        doSomething( override ? devToAddress : toAddress );
    }

    private void doSomething(String toAddress)
    {
        Mailer.sendAnEmailToTheAddress(toAddress, getEmailText());
    }

    @Subscribe
    public static void loadConfig(ConfigurationChangeEvent cce)
    {
        Config config = Config.getConfig();
        devToAddress = config.getProperty("testAddress");
        override = Boolean.parseBoolean( config.getProperty("overrideMailDestination") );
    }

    // static/class initial load
    static
    {
        loadConfig(null); // initial config load without an event
    }
}

This is closer to the real-world use; while still only example code, it does demonstrate how static handling of guava EventBus calls can be done.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top