Multiple Controllers with Shared Resources

This entry is part 3 of 15 in the series Building JEE applications in JavaFX 2.0

In this post we’re going to create two controllers that share a common resource. We will start with something simple and unimpressive in this post and refine it into something more useful in subsequent posts.

For now we will create two controllers, one that allows us to edit our Person object, and another that provides a friendly welcome message for that person. Here’s how it will look:

To keep things simple, I’ve just placed the two views on the same top-level page and we’re not using property bindings so you will have to hit the ‘save’ button before hitting the ‘show welcome’ button. The goal here is to simply show how two controllers can share resources – we’ll create a more architecturally elegant solution soon enough.

Our code now consists of two controllers, EnterDetailsController and WelcomeController, and these each have a corresponding FXML file, EnterDetails.fxml and Welcome.fxml. These are pretty unexciting and straight forward – you can check out the code directly for more details. The only interesting thing in our controllers is that they both define the following:


@Autowired private Person person;

This tells Spring that we want the Person to be injected (aka ‘wired up’) automatically.

In our factory, we now load each of the controllers in separate methods in the factory and annotate these methods with @Bean. Spring will then inject the same person instance into each. Even though we create a new Person in the person() factory method, Spring knows to cache the result and reuse it for all injection because of the @Bean annotation.

Our factory now looks like this:

@Configuration
public class SampleAppFactory
{
    @Bean
    public Person person()
    {
        return new Person();
    }

    @Bean
    public WelcomeController welcomePageController() throws IOException
    {
        return (WelcomeController) loadController("/Welcome.fxml");
    }

    @Bean
    public EnterDetailsController enterDetailsController() throws IOException
    {
        return (EnterDetailsController) loadController("/EnterDetails.fxml");
    }

    protected Object loadController(String url) throws IOException
    {
        InputStream fxmlStream = null;
        try
        {
            fxmlStream = getClass().getResourceAsStream(url);
            FXMLLoader loader = new FXMLLoader();
            loader.load(fxmlStream);
            return loader.getController();
        }
        finally
        {
            if (fxmlStream != null)
            {
                fxmlStream.close();
            }
        }
    }
}

That’s it – sharing resources in a nice way via Dependency Injection is actually incredibly simple. It ought to be, that’s really what dependency injection is all about!

Of course, our example is still pretty raw and clunky but we’ll work on this over the next few posts to clean it all up.

The full source code for this post can be found at: http://code.google.com/p/jfxee/source/browse/trunk/jfxspring3/

Series Navigation<< Better Controller InjectionViews within Views, Controllers within Controllers >>

5 thoughts on “Multiple Controllers with Shared Resources

  1. Pingback: Java desktop links of the week, October 31 | Jonathan Giles

  2. Pingback: JavaFX links of the week, October 31 // JavaFX News, Demos and Insight // FX Experience

    • Hi Alan,

      If I understand your question correctly, then ‘yes’ – when you annotate a factory method with @Bean then Spring will, by default, make sure only one instance of the object is created and so it is shared.

      So if my factory method is:

      @Bean
      public SomeThing createSomeThing()
      {
      return new SomeThing();
      }

      Then when you inject SomeThing into other classes, only one Object will exist in memory and will be shared. Spring basically caches it and shares it everywhere. Spring actually does this by rewritting the Java class at runtime (pretty hard core stuff) so even if you directly call the method from within the factory class the instance will be cached.

      Sometimes you don’t want this behaviour, in that case you can add the annotation of @Prototype, which tells Spring you want the resulting Object to be created every time it is injected so then it is not shared.

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>