使用 Spring 设计 Java 库

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5471550/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 11:16:21  来源:igfitidea点击:

Designing a Java library with Spring

javaspring

提问by Iker Jimenez

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.

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

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?

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

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

采纳答案by Johan Sj?berg

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.

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

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., ClassPathXmlApplicationContextto configure spring. A sample could be

由您的库以您需要的方式实例化 spring。这通常在您的接口入口点中完成,该入口点使用例如ClassPathXmlApplicationContext配置 spring委托给例程。一个样本可以是

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?

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

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 startand stopmechanisms. In your case these probably better be called registerEventListenerand unregisterAllEventListener(since I'm guessing you want to pass filesystem events to the client ... ). Another alternative could be to use quartzscheduling with spring.

在这种情况下,您可能会提供一个非守护进程线程,例如,必须手动终止的线程才能使应用程序干净地退出。因此你应该提供startstop机制。在你的情况下,这些可能是更好的被称为registerEventListenerunregisterAllEventListener(因为我猜你想通过文件系统事件给客户...)。另一种选择可能是在quartzspring 中使用调度。

回答by Marcio Oliveira

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.

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

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 FooServiceand BarServiceand a class called SpringContext that configures your spring context through java config:

我也在使用 Spring 上下文编写一个库,我做了类似的事情,假设您的库名为FooLib,有两个名为FooServiceBarService 的服务以及一个名为 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;
    }
}

Then a client can use BarServicethis way:

然后客户端可以使用BarService这种方式:

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?

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

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

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

@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.

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

Cheers

干杯

回答by Péter T?r?k

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.

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

You can use a PropertyPlaceholderConfigurerto 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.

您可以使用 aPropertyPlaceholderConfigurer从(可能是外部的)属性文件中读取配置设置,该文件可由用户编辑。这样用户就不会接触到 Spring 的细节,甚至不会接触到 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?

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

I recommend using the Java concurrency framework, specifically a ScheduledExecutorServiceto 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.

我建议使用 Java 并发框架,特别是ScheduledExecutorService在指定的时间间隔运行监控任务。但是,您可能希望对库的用户隐藏此实现细节,方法是仅公开一些 init 方法以传入所需的计时器间隔。

回答by ruhsuzbaykus

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.htmlIn your main class, simple use:

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

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:

对于线程,您可以尝试实现可运行接口,并使用 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}" />

I hope it will be helpful.

我希望它会有所帮助。