【无标题】java程序作为Windows服务

这听起来像是你永远都不需要的东西,但是有时候,当你发布最终用户软件时,你可能需要安装一个java程序作为Windows服务。我不得不这么做,因自动转换并将其Excel文件推送到我的国家的opendata门户网站。该工具必须定期运行,因此它是一项服务的主要候选对象(即使公务员完全忘记这项任务,这也将使上传成为可能,此外,重复的手动上传是浪费时间)。

尽管有许多关于这个主题的帖子和stackoverflow答案,但我仍然花了很多时间,因为一些小的警告和一个很少有人拥有的重要先决条件——拥有一个捆绑的JRE,这样就没有人需要下载和安装JRE(这会不必要地使安装过程变得复杂,并且目标受众不一定精通技术)。

所以,有了带jar打包的maven项目,我首先想到的是打包一个e将其注册为服务。这样做的问题是,java程序使用一个预定的执行器,所以它永远不会退出,这使得它不可能作为一个进程启动。

所以我不得不“妖魔化”它普罗克伦。在此之前,我必须将所需的每个组件组装到一个目标文件夹中fat jar(包括所有依赖项)、JRE、commons-daemon二进制文件和配置文件。

你可以看到完整${installer.dir}存在${project.basedir}/target/installer}):

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

<plugin>

    <groupId>org.apache.maven.plugins</groupId>

    <artifactId>maven-compiler-plugin</artifactId>

    <version>2.3.2</version>

    <configuration>

        <source>1.8</source>

        <target>1.8</target>

    </configuration>

</plugin>

<plugin>

    <artifactId>maven-assembly-plugin</artifactId>

    <executions>

        <execution>

            <id>assembly</id>

            <phase>package</phase>

            <goals>

                <goal>single</goal>

            </goals>

            <configuration>

                <descriptorRefs>

                    <descriptorRef>jar-with-dependencies</descriptorRef>

                </descriptorRefs>

                <finalName>opendata-ckan-pusher</finalName>

                <appendAssemblyId>false</appendAssemblyId>

            </configuration>

        </execution>

    </executions>

</plugin>

<plugin>

    <groupId>org.apache.maven.plugins</groupId>

    <artifactId>maven-antrun-plugin</artifactId>

    <version>1.7</version>

    <executions>

        <execution>

            <id>default-cli</id>

            <phase>package</phase>

            <goals>

                <goal>run</goal>

            </goals>

            <configuration>

                <target>

                    <copy todir="${installer.dir}/jre1.8.0_91">

                        <fileset dir="${project.basedir}/jre1.8.0_91" />

                    </copy>

                    <copy todir="${installer.dir}/commons-daemon">

                        <fileset dir="${project.basedir}/commons-daemon" />

                    </copy>

                    <copy file="${project.build.directory}/opendata-ckan-pusher.jar" todir="${installer.dir}" />

                    <copy file="${project.basedir}/install.bat" todir="${installer.dir}" />

                    <copy file="${project.basedir}/uninstall.bat" todir="${installer.dir}" />

                    <copy file="${project.basedir}/config/pusher.yml" todir="${installer.dir}" />

                    <copy file="${project.basedir}/LICENSE" todir="${installer.dir}" />

                </target>

            </configuration>

        </execution>

    </executions>

</plugin>

您会注意到installer.bat和uninstaller.bat这两个文件使用commons-daemon来管理服务。安装程序创建服务。Commons-daemon有三种模式:exe(允许你包装任意可执行文件)、java(类似exe,但针对java应用)和jvm(在同一个进程中运行Java应用;虽然我不知道具体如何)。

我可以使用所有三个选项(包括launch4j created exe),但是jvm允许您有一个指定的方法来控制您正在运行的应用程序。start class/start method/stop class/stop method参数就是为此准备的。这是完整的安装程序。蝙蝠:

https://movie.douban.com/review/14637559/

1

2

3

4

5

6

7

8

9

commons-daemon\prunsrv //IS//OpenDataPusher --DisplayName="OpenData Pusher" --Description="OpenData Pusher"^

     --Install="%cd%\commons-daemon\prunsrv.exe" --Jvm="%cd%\jre1.8.0_91\bin\client\jvm.dll" --StartMode=jvm --StopMode=jvm^

     --Startup=auto --StartClass=bg.government.opendatapusher.Pusher --StopClass=bg.government.opendatapusher.Pusher^

     --StartParams=start --StopParams=stop --StartMethod=windowsService --StopMethod=windowsService^

     --Classpath="%cd%\opendata-ckan-pusher.jar" --LogLevel=DEBUG^ --LogPath="%cd%\logs" --LogPrefix=procrun.log^

     --StdOutput="%cd%\logs\stdout.log" --StdError="%cd%\logs\stderr.log"

      

      

commons-daemon\prunsrv //ES//OpenDataPusher

一些澄清:

  • Jvm参数指向jvm dll
  • start class/start method/stop class/stop method指向用于控制正在运行的应用程序的指定方法。在这种情况下,启动将只调用main方法,停止将关闭预定的执行器,以便应用程序可以退出
  • 类路径参数指向胖罐子
  • 使用%cd%来确定当前目录的路径是有风险的,但是由于最终用户总是从它所在的目录启动它,所以在这种情况下是安全的。

windowsService看起来是这样的:

https://baa.yiche.com/DEUSdiandongpaoche/thread-42947806.html

1

2

3

4

5

6

7

8

9

10

11

12

13

public static void windowsService(String args[]) throws Exception {

     String cmd = "start";

     if (args.length > 0) {

        cmd = args[0];

    }

    if ("start".equals(cmd)) {

        Pusher.main(new String[]{});

    } else {

        executor.shutdownNow();

        System.exit(0);

    }

}

这里需要注意的一点是您可能遇到的32位/64位问题。这就是为什么捆绑32位JRE并使用32位(默认)prunsrv.exe更安全的原因。

然后,我有一个“安装程序”文件夹,其中有jre和commons-daemon文件夹、两个bat文件和一个fat jar。然后,我可以将它打包成一个可自解压的归档文件,并分发它(当然,附带一个手册)。我调查但是找不到如何捆绑一个JRE(也许你可以)。

这是一个非常小的场景——通常我们开发部署到Linux服务器上,但是为一个使用Java的大组织提供本地工具可能不时需要。在我的例子中,长时间运行的部分是一个预定的执行器,但是它也可以运行一个服务于web接口的jetty服务。为什么要这样做,而不是提供一个URL——在访问本地机器很重要的情况下。它甚至可以是分布式搜索个你想用Java写的p2p软件。

Hibernate提供事件监听器作为其SPI的一部分。您可以将侦听器与许多事件挂钩,包括预插入、后插入、预删除、刷新等。

但是有时在这些监听器中,你想要使用spring依赖。hibernate已经升级了,现在有了更好的方法(由于缺少类,旧方法在最新版本中不起作用)。

这次更简单。你只需要一颗像这样的豆子:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

@Component

public class HibernateListenerConfigurer {

     

    @PersistenceUnit

    private EntityManagerFactory emf;

     

    @Inject

    private YourEventListener listener;

     

    @PostConstruct

    protected void init() {

        SessionFactoryImpl sessionFactory = emf.unwrap(SessionFactoryImpl.class);

        EventListenerRegistry registry = sessionFactory.getServiceRegistry().getService(EventListenerRegistry.class);

        registry.getEventListenerGroup(EventType.POST_INSERT).appendListener(listener);

        registry.getEventListenerGroup(EventType.POST_UPDATE).appendListener(listener);

        registry.getEventListenerGroup(EventType.POST_DELETE).appendListener(listener);

    }

}

它然而,这是行不通的,因为它也依赖于过时的类。

你也可以注射一个List<..>侦听器(尽管它们没有共享一个公共接口,但您可以定义自己的接口)。

正如SO回答中所指出的,您不能在监听器中存储新的

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值