深入了解帆软报表系统的启动过程一

楼主
插件开发者

1 帆软报表的启动类为:com.fr.learn.Learner,它的main方法如下:

 public static void main(String[] args) {
        try {
            Class mainClass = Class.forName("com.fr.start.MainDesigner");
            invokeMain(mainClass, args);
        } catch (ClassNotFoundException e) {
            // MainDesigner找不到,走以前的Designer
            try {
                Class oldMainClass = Class.forName("com.fr.start.Designer");
                invokeMain(oldMainClass, args);
            } catch (ClassNotFoundException ex) {
                FineLoggerFactory.getLogger().error(e.getMessage(), e);
            }
        }
    }

        从上面可以看出,首先会d加载com.fr.start.MainDesigner类,如果找不到,就加载com.fr.start.Designer。这两个类都在fine-report-designer.jar中

2 com.fr.start.MainDesigner的main方法:

        

    public static void main(String[] args) {
        StopWatch watch = new StopWatch();
        watch.start();
        DesignerLifecycleMonitorContext.getMonitor().beforeStart();
        FineRuntime.start();
        DesignerSubListener.getInstance().start();
        EventDispatcher.listen(LifecycleErrorEvent.SELF, new Listener<FineLifecycleFatalError>() {
            public void on(Event event, FineLifecycleFatalError param) {
                LifecycleFatalErrorHandler.getInstance().handle(param);
            }
        });
        Module designerRoot = ModuleContext.parseRoot("designer-startup.xml");
        designerRoot.setSingleton(StartupArgs.class, new StartupArgs(args));

        try {
            designerRoot.start();
        } catch (FineLifecycleFatalError var4) {
            LifecycleFatalErrorHandler.getInstance().handle(var4);
        }

        if (WorkContext.getCurrent().isLocal()) {
            ServerTray.init();
        }

        FineLoggerFactory.getLogger().info("Designer started.Time used {} ms", new Object[]{watch.getTime()});
        watch.stop();
    }

关键代码为:

        

Module designerRoot = ModuleContext.parseRoot("designer-startup.xml");
        designerRoot.setSingleton(StartupArgs.class, new StartupArgs(args));

        try {
            designerRoot.start();
        } catch (FineLifecycleFatalError var4) {
            LifecycleFatalErrorHandler.getInstance().handle(var4);
        }

加载解析配置文件designer-startup.xml,这个文件在fine-activator.jar中。解析后会得到根模块,然后调用根模块的start方法,这会导致配置文件中的一系列的Activator的start方法也开始运行。

3 看一下这个jar包中的结构:

        

我们看到在com.fr.config.starter下有两个xml文件,designer-startup.xml与server-startuo.xml,这就是帆软报表整体的配置文件,designer-startup.xml是在设计器模式下加载的配置,server-startuo.xml是非设计器模式下加载的配置。其他目录的xml配置文件都会被这两个配置文件来引用。

3.1 初略看一下designer-startup.xml中的内容:

        

<?xml version="1.0" encoding="UTF-8"?>
<designer-startup activator="com.fr.start.module.DesignerStartup" invoke-subs-strategy="custom" role="root">
    <!--启动前的准备工作-->
    <pre-start activator="com.fr.start.module.PreStartActivator" invoke-subs-strategy="parallel">
        <basic ref="../base/basic.xml"/>
    </pre-start>
    <parallel invoke-subs-strategy="parallel">
        <designer-init activator="com.fr.start.module.DesignerInitActivator"/>
        <workspace activator="com.fr.start.module.DesignerWorkspaceActivator" invoke-subs-strategy="subs-first">
            <!--环境相关模块-->
            <designer-workspace-provider activator="com.fr.start.module.DesignerWorkspaceProvider"
                                         role="workspace-provider"/>
            <!--基于env的模块合集-->
            <env-based activator="com.fr.start.module.EnvBasedModule" invoke-subs-strategy="subs-first">
                <!--core-->
                <core ref="../base/core.xml"/>
                <!--数据源模块,目前还没有启动逻辑,只是注册一下模块版本信息-->
                <parallel invoke-subs-strategy="parallel">
                    <designer-show activator="com.fr.start.module.DesignerShowActivator"/>
                    <function>
                        <datasource activator="com.fr.data.DatasourceActivator" version="10.0"/>

                        <!--功能基础-->
                        <function-base ref="../function/function-base.xml"/>

                        <designer ref="../designer/designer.xml"/>
                        <!--内置服务器功能模块-->
                        <emb-server activator="com.fr.start.server.FineEmbedServerActivator"
                                    invoke-subs-strategy="custom"
                                    auto-invoke-by-parent="false"
                                    binding-workspace="local">
                            <server ref="../server/server.xml"/>
                        </emb-server>
                    </function>
                </parallel>
            </env-based>
        </workspace>
    </parallel>
</designer-startup>

我们发现这里面定义了许多activator,也引用了其他的xml文件,activator这里可以理解为模块,最外层就是根模块,模块也包含父子关系,兄弟关系。

com.fr.start.MainDesigner中使用ModuleContext来解析这个配置文件,并返回一个根Module对象,在解析过程中,将这些模块已经按层次关系组装好了。

当得到根Module之后,就会调用根模块的start方法。

designerRoot.start();

这不仅仅是调用了根模块的start方法,其他的模块的start方法他也一并会调用。

这里有一个对用关系,一个module对应一个activator,帆软报表将所有功能都分配到各个activator里了。

这就是帆软报表的启动过程,这里分析得很简单,后面会详细来分析内部过程。

分享扩散:

沙发
发表于 2021-9-7 10:20:59
板凳
发表于 2021-9-13 09:30:12
干货满满
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

返回顶部 返回列表