Openfire源码分析

一、Openfire启动控制台监听分析

Openfire启动时序图

这里写图片描述

在Eclipse或者Intellij IDEA中运行openfire源码时,需要先指定openfire启动类:ServerStarter(该类里面有main()方法),Intellij IDEA中配置如下图所示:

openfire 启动配置

ServerStarter类中关键代码如下:

 ClassLoader loader = new JiveClassLoader(parent, libDir);
            Thread.currentThread().setContextClassLoader(loader);
            Class containerClass = loader.loadClass(
                    "org.jivesoftware.openfire.XMPPServer");
            containerClass.newInstance();

从代码中我们可以看出,Openfire通过反射加载XmppServer.class,并调用newInstance方法,实例化XmppServer对象

XmppServer类是一个很重要的类,很多对象实例都可以通过XmppServer.getInstance().getXxx()方法得到。
在XmppServer对象被初始化时,会调用start()方法,关键代码如下:

  initialize();
  /* Create PluginManager now (but don't start it) so that modules may use it*/
   File pluginDir = new File(openfireHome, "plugins");
   pluginManager = new PluginManager(pluginDir);

   // If the server has already been setup then we can start all the server's modules
   if (!setupMode) {
       verifyDataSource();
       // First load all the modules so that modules may access other modules while being initialized
       loadModules();
       // Initize all the modules
       initModules();
       // Start all the modules
       startModules();
    }
    // Initialize statistics
    ServerTrafficCounter.initStatistics();
    // Load plugins (when in setup mode only the admin console will be loaded)
    pluginManager.start();

intialize()方法主要做了两件事:1. 读取openfireHome属性,2. 初始化Cache,openfire cache实现后面再分析。2.初始化PluginManager对象,PluginManager这个类是用来管理各种插件的。3.判断是否为setupmode,即openfire是否已做过初始化安装,这里先假设setupmode为false。4.初始化统计类,A ServerTrafficCounter counts the number of bytes read and written by the server. 5. PluginManager start,扫描plugins文件夹插件并加载插件,通过插件加载流程机制,会实例化AdminConsolePlugin类。

AdminConsolePlugin类分析
先来看一下InitialPlugin()方法:

public void initializePlugin(PluginManager manager, File pluginDir)  {
        this.pluginDir = pluginDir;
        createWebAppContext();
        startup();
}

private void createWebAppContext() {
    WebAppContext context;
    // Add web-app. Check to see if we're in development mode. If so, we don't
   // add the normal web-app location, but the web-app in the project directory.
   boolean developmentMode  =  Boolean.getBoolean("developmentMode");
   if( developmentMode )
   {           System.out.println(LocaleUtils.getLocalizedString("admin.console.devmode"));

    context = new WebAppContext(contexts,
    pluginDir.getParentFile().getParentFile().getParentFile().getParent() + File.separator + "src" + File.separator + "web", "/");
   }else {
   context = new WebAppContext(contexts,    pluginDir.getAbsoluteFile() + File.separator + "webapp", "/");
   }
}

 public void startup() {
        restartNeeded = false;

        // Add listener for certificate events
        certificateListener = new CertificateListener();
        CertificateManager.addListener(certificateListener);

        // the number of threads allocated to each connector/port
        int serverThreads = JiveGlobals.getXMLProperty("adminConsole.serverThreads", 2);

        adminPort = JiveGlobals.getXMLProperty("adminConsole.port", 9090);
        adminSecurePort = JiveGlobals.getXMLProperty("adminConsole.securePort", 9091);

        final QueuedThreadPool tp = new QueuedThreadPool();
        tp.setName("Jetty-QTP-AdminConsole");

        adminServer = new Server(tp);

        if (JMXManager.isEnabled()) {
            JMXManager jmx = JMXManager.getInstance();
            adminServer.addBean(jmx.getContainer());
        }

        // Create connector for http traffic if it's enabled.
        if (adminPort > 0) {
            final HttpConfiguration httpConfig = new HttpConfiguration();

            // Do not send Jetty info in HTTP headers
            httpConfig.setSendServerVersion( false );

            final ServerConnector httpConnector = new ServerConnector(adminServer, null, null, null, -1, serverThreads, new HttpConnectionFactory(httpConfig));

            // Listen on a specific network interface if it has been set.
            String bindInterface = getBindInterface();
            httpConnector.setHost(bindInterface);
            httpConnector.setPort(adminPort);
            adminServer.addConnector(httpConnector);
        }

        // Create a connector for https traffic if it's enabled.
        sslEnabled = false;
        try {

       final ConnectionManagerImpl connectionManager = ( (ConnectionManagerImpl) XMPPServer.getInstance().getConnectionManager() );
                    final ConnectionConfiguration configuration = connectionManager.getListener( ConnectionType.WEBADMIN, true ).generateConnectionConfiguration();
                    final SslContextFactory sslContextFactory = new EncryptionArtifactFactory( configuration ).getSslContextFactory();

                    final ServerConnector httpsConnector;
                    if ( "npn".equals( JiveGlobals.getXMLProperty( "spdy.protocol", "" ) ) )
                    {
                        httpsConnector = new HTTPSPDYServerConnector( adminServer, sslContextFactory );
                    }
                    else
                    {
                        final HttpConfiguration httpsConfig = new HttpConfiguration();
                        httpsConfig.setSendServerVersion( false );
                        httpsConfig.setSecureScheme( "https" );
                        httpsConfig.setSecurePort( adminSecurePort );
                        httpsConfig.addCustomizer( new SecureRequestCustomizer() );

                        final HttpConnectionFactory httpConnectionFactory = new HttpConnectionFactory( httpsConfig );
                        final SslConnectionFactory sslConnectionFactory = new SslConnectionFactory( sslContextFactory, org.eclipse.jetty.http.HttpVersion.HTTP_1_1.toString() );

                        httpsConnector = new ServerConnector( adminServer, null, null, null, -1, serverThreads,
                                sslConnectionFactory, httpConnectionFactory );
                    }
                    final String bindInterface = getBindInterface();
                    httpsConnector.setHost(bindInterface);
                    httpsConnector.setPort(adminSecurePort);
                    adminServer.addConnector(httpsConnector);

                    sslEnabled = true;
                }
            }
        }
        catch ( Exception e )
        {
            Log.error( "An exception occurred while trying to make available the admin console via HTTPS.", e );
        }

        HandlerCollection collection = new HandlerCollection();
        adminServer.setHandler(collection);
        collection.setHandlers(new Handler[] { contexts, new DefaultHandler() });

        try {
            adminServer.start();
            logAdminConsolePorts();
        }
        catch (Exception e) {
            Log.error("Could not start admin console server", e);
        }
    }

createWebAppContext()法里面new 了一个新的WebAppContext对象,做过javaweb开发的童鞋应该知道,每一个web应用都会有一个这样的对象,在构造方法里面指明了web.xml的加载路径。再看startUp()方法,初始化配置这些有兴趣的童鞋以自己看下,看最关键代码:
try {
adminServer.start();
// Log the ports that the admin server is listening on.
logAdminConsolePorts();
}

这里开启了对9090端口的监听。同时本地控制台中会输出日志:
2148 INFO 管理平台开始监听:
http://localhost:9090
https://localhost:9091
此时大家打开浏览器访问http://localhost:9090, 便可看到openfire控制台页面了。


版权声明:本文为u012361112原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。