Designing a Java library with Spring

11,765

Solution 1

How do I initialise the library's context? I cannot assume that library users will make use of Spring too, but I can distribute Spring with the library.

It's up to your library to instantiate spring the way you need it. This is typically done in your interface entrypoint which delegates to a routine using e.g., ClassPathXmlApplicationContext to configure spring. A sample could be

public class SpringContextLoader {
   private static ApplicationContext ctx = null;
   public static void init() {
       if (ctx == null) {
          ctx = ClassPathXmlApplicationContext("classpath:/applicatonContext.xml");
       }
   }
}

How do I manage my filesystem monitoring thread? Is it good design to expect the program to instantiate a main class of the library and the call init or something like that?

In this case you will probably provide a non-daemon thread, e.g., a thread which must be terminated manually for the application to exit cleanly. Hence you should provide start and stop mechanisms. In your case these probably better be called registerEventListener and unregisterAllEventListener (since I'm guessing you want to pass filesystem events to the client ... ). Another alternative could be to use quartz scheduling with spring.

Solution 2

How do I initialise the library's context? I cannot assume that library users will make use of Spring too, but I can distribute Spring with the library.

I am writing a library using Spring context as well and I did something like that, assuming your library is called FooLib, has two services called FooService and BarService and a class called SpringContext that configures your spring context through java config:

public final class FooLib {

    private static ApplicationContext applicationContext;

    private FooLib() {
    }

    public static FooService getFooService() {
        return getApplicationContext().getBean(FooService.class);
    }

    public static BarService getBarService() {
        return getApplicationContext().getBean(BarService.class);
    }

    private static ApplicationContext getApplicationContext() {
        if (applicationContext == null) {
            applicationContext = new AnnotationConfigApplicationContext(SpringContext.class);
        }
        return applicationContext;
    }
}

Then a client can use BarService this way:

BarService barService = FooLib.getBarService();

How do I manage my filesystem monitoring thread? Is it good design to expect the program to instantiate a main class of the library and the call init or something like that?

You can start your monitoring subsystem statically within Spring context, inside the SpringContext class, for example.

@Configuration
@ComponentScan(basePackages = "com.yourgroupid.foolib")
public class SpringContext {

    @Bean
    public MonitoringSystem monitoringSystem() {
        MonitoringSystem monitoringSystem = new MonitoringSystem();
        monitoringSystem.start();
        return monitoringSystem;
    }

}

That should be enough because Spring creates its beans eagerly by default.

Cheers

Solution 3

How do I initialise the library's context? I cannot assume that library users will make use of Spring too, but I can distribute Spring with the library.

You can use a PropertyPlaceholderConfigurer to read configuration settings from a (possibly external) property file, which can be edited by the users. This way users aren't exposed to the details of Spring, not even to XML config files.

How do I manage my filesystem monitoring thread? Is it good design to expect the program to instantiate a main class of the library and the call init or something like that?

I recommend using the Java concurrency framework, specifically a ScheduledExecutorService to run monitoring task(s) at specified intervals. However, you may want to hide this implementation detail from the users of your library, by only exposing some init method to pass in the desired timer interval.

Solution 4

As far as I know, it is not possible to configure your library to start a thread automatically, you have to define a class as starting point. Using Maven you can create an executable jar: http://maven.apache.org/plugins/maven-shade-plugin/examples/executable-jar.html In your main class, simple use:

ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:myspring-context.xml");      
    context.registerShutdownHook();

For threads, you can try either implementing the runnable interface, and initialize a bean which starts the threads using spring task executors. A more elegant solution that I can suggest is however creating your thread as a pojo and then using spring task scheduler, as follows:

<bean id="threadPojo" class="com.mydomain.ThreadPojo">
</bean>
<task:scheduled-tasks scheduler="mydomainTaskScheduler">
    <task:scheduled ref="threadPojo" method="process" fixed-delay="${delay-pool}"/>
</task:scheduled-tasks>
<task:scheduler id="mydomainTaskScheduler" pool-size="${my-pool-size}" />

I hope it will be helpful.

Share:
11,765

Related videos on Youtube

Iker Jimenez
Author by

Iker Jimenez

#SOreadytohelp

Updated on July 19, 2020

Comments

  • Iker Jimenez
    Iker Jimenez almost 4 years

    I am extracting some functionality from an existing program into a separate library. This program uses Spring for dependency injection and other tasks and I'd like to keep using it in the library as well.

    This library needs to monitor the filesystem for changes, so it will kick off some kind of separate thread to do this.

    I don't really know what my options are for initialisation of the library:

    • How do I initialise the library's context? I cannot assume that library users will make use of Spring too, but I can distribute Spring with the library.

    • How do I manage my filesystem monitoring thread? Is it good design to expect the program to instantiate a main class of the library and the call init or something like that?

  • Iker Jimenez
    Iker Jimenez about 13 years
    Actually I don't need to pass FS events to the client. Is only for the library to be aware of available files, as it needs to access different versions of some files that get changed at random times. So it is for internal consumption of the library and I have it currently designed as a daemon thread, but I don't know what's the best way of handling a deamon thread from Spring.
  • Johan Sjöberg
    Johan Sjöberg about 13 years
    @Jimenez, Simplest approach isn't always the worst: new Thread(new Runnable()).setDaemon(true), unless you're going for the nice @Scheduled approach.
  • Iker Jimenez
    Iker Jimenez about 13 years
    I know, that's the way it is now :) , but I was just curious to see if there was another better option.
  • Johan Sjöberg
    Johan Sjöberg about 13 years
    @Jimenez, Spring is an IoC container in core, it doesn't concern itself with threading models which are already provided by the java language.
  • Katona
    Katona almost 9 years
    Regarding the first part, I think a java library should be configurable through java API and not property files.

Related