使用Spring设计Java库

时间:2011-03-29 11:08:46

标签: java spring

我正在从现有程序中将一些功能提取到一个单独的库中。 这个程序使用Spring进行依赖注入和其他任务,我也想继续在库中使用它。

这个库需要监视文件系统的变化,所以它会启动某种单独的线程来执行此操作。

我真的不知道我对库的初始化有什么选择:

  • 如何初始化库的上下文?我不能假设库用户也会使用Spring,但我可以使用库分发Spring。

  • 如何管理文件系统监控线程?期望程序实例化库的主类和调用init或类似的东西是好的设计吗?

4 个答案:

答案 0 :(得分:10)

  

如何初始化库的上下文?我不能这么认为   库用户也会使用Spring,但我可以分发Spring   与图书馆。

我正在使用Spring上下文编写一个库,我做了类似的事情,假设您的库名为 FooLib ,有两个名为 FooService 的服务BarService 和一个名为SpringContext的类,它通过java config配置你的spring上下文:

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;
    }
}

然后客户端可以这样使用BarService

BarService barService = FooLib.getBarService();
  

如何管理文件系统监控线程?这是好的设计吗?   期望程序实例化库的主类和   调用init或类似的东西?

例如,您可以在SpringContext类的Spring上下文中静态启动监视子系统。

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

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

}

这应该足够了,因为Spring默认会急切地创建它的bean。

干杯

答案 1 :(得分:8)

  

如何初始化库的上下文?我不能假设库用户也会使用Spring,但我可以使用库分发Spring。

由您的库根据您的需要实例化spring。这通常在您的接口入口点中完成,该入口点使用例如ClassPathXmlApplicationContext来配置例程以配置spring。样本可以是

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

如何管理文件系统监控线程?期望程序实例化库的主类和调用init或类似的东西是好的设计吗?

在这种情况下,您可能会提供一个非守护程序线程,例如,一个必须手动终止的线程,以便应用程序干净地退出。因此,您应该提供startstop机制。在你的情况下,最好将这些称为registerEventListenerunregisterAllEventListener(因为我猜你想把文件系统事件传递给客户端......)。另一种选择可能是使用spring quartz调度。

答案 2 :(得分:4)

  

如何初始化库的上下文?我不能假设库用户也会使用Spring,但我可以使用库分发Spring。

您可以使用PropertyPlaceholderConfigurer从(可能是外部的)属性文件中读取配置设置,该文件可由用户编辑。这样,用户就不会接触到Spring的细节,甚至不会暴露给XML配置文件。

  

如何管理文件系统监控线程?期望程序实例化库的主类和调用init或类似的东西是好的设计吗?

我建议使用Java并发框架,特别是ScheduledExecutorService以指定的时间间隔运行监视任务。但是,您可能希望通过仅暴露一些init方法来传递所需的计时器间隔来隐藏库中用户的此实现细节。

答案 3 :(得分:1)

据我所知,无法将库配置为自动启动线程,您必须将类定义为起点。使用Maven,您可以创建一个可执行jar: http://maven.apache.org/plugins/maven-shade-plugin/examples/executable-jar.html 在您的主要课程中,简单使用:

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

对于线程,您可以尝试实现runnable接口,并初始化使用spring任务执行程序启动线程的bean。我建议的更优雅的解决方案是将您的线程创建为pojo然后使用spring任务调度程序,如下所示:

<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}" />

我希望它会有所帮助。