• Oct
    • 24
    • 2011

Multiple Controllers with Shared Resources

Posted by In Uncategorized
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 Comments

  • Alan
    March 27, 2012

    Hi Zonski!
    Is the default behavior of Spring to share the resource?

    • zonski Author
      March 27, 2012

      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.

      • Alan
        March 29, 2012

        That was my doubt.
        Thanks for the explanation.

Leave a Comment