执迷不悟,那又如何。
openfire是我接触的第一款通讯开源框架,里面涉及到mina,插件开发更新等知识,项目完全开源,最近一直在学动态更新,偶尔想起以前读过openfire的源码,怕忘记,写一篇blog来复习一下其中的插件开发内容。与君分享。
openfire开源官网地址:http://www.igniterealtime.org/projects/openfire/index.jsp,
openfire github 地址:https://github.com/igniterealtime/Openfire
代码入口为;org.jivesoftware.openfire.starter.ServerStarter
private void start() {
// Setup the classpath using JiveClassLoader
try {
// Load up the bootstrap container
final ClassLoader parent = findParentClassLoader();
String libDirString = System.getProperty("openfire.lib.dir");
File libDir;
if (libDirString != null) {
// If the lib directory property has been specified and it actually
// exists use it, else use the default
libDir = new File(libDirString);
if (!libDir.exists()) {
Log.warn("Lib directory " + libDirString +
" does not exist. Using default " + DEFAULT_LIB_DIR);
libDir = new File(DEFAULT_LIB_DIR);
}
}
else {
libDir = new File(DEFAULT_LIB_DIR);
}
String adminLibDirString = System.getProperty("openfireHome");
if (adminLibDirString == null) {
adminLibDirString = DEFAULT_ADMIN_LIB_DIR;
}
else {
adminLibDirString = adminLibDirString+"/plugins/admin/webapp/WEB-INF/lib";
}
File adminLibDir = new File(adminLibDirString);
if (!adminLibDir.exists()) {
Log.warn("Admin Lib Directory " + adminLibDirString +
" does not exist. Web admin console may not work.");
}
ClassLoader loader = new JiveClassLoader(parent, libDir);
Thread.currentThread().setContextClassLoader(loader);
Class containerClass = loader.loadClass(
"org.jivesoftware.openfire.XMPPServer");
containerClass.newInstance();
}
catch (Exception e) {
e.printStackTrace();
}
}
先找到读取设置的lib路径,如果没有,采用默认的路径。然后用JiveClassLoader其中的class文件
最后加载org.jivesoftware.openfire.XMPPServer,然后newInstance,执行其中的静态方法开始运行
接下来看JiveClassLoader代码,他继承了urlclassloader
构造方法:
JiveClassLoader(ClassLoader parent, File libDir) throws MalformedURLException {
super(new URL[] { libDir.toURI().toURL() }, parent);
File[] jars = libDir.listFiles(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
boolean accept = false;
String smallName = name.toLowerCase();
if (smallName.endsWith(".jar")) {
accept = true;
}
else if (smallName.endsWith(".zip")) {
accept = true;
}
return accept;
}
});
// Do nothing if no jar or zip files were found
if (jars == null) {
return;
}
// sort jars otherwise order differs between installations (e.g. it's not alphabetical)
// order may matter if trying to patch an install by adding patch jar to lib folder
Arrays.sort(jars);
for (int i = 0; i < jars.length; i++) {
if (jars[i].isFile()) {
addURL(jars[i].toURI().toURL());
}
}
}
吧目录下的jar和zip加载进目录中,然后分析urlClassloader的addUrl和构造方法urlClassloader继承SecureClassLoader。
父类加载器为也就是先获取设置的classloader如果没有就是appclassloader
private ClassLoader findParentClassLoader() {
ClassLoader parent = Thread.currentThread().getContextClassLoader();
if (parent == null) {
parent = this.getClass().getClassLoader();
if (parent == null) {
parent = ClassLoader.getSystemClassLoader();
}
}
return parent;
}
在org.jivesoftware.openfire.XMPPServer中,先加载model
public void start() {
try {
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();
// Log that the server has been started
String startupBanner = LocaleUtils.getLocalizedString("short.title") + " " + xmppServerInfo.getVersion().getVersionString() +
" [" + JiveGlobals.formatDateTime(new Date()) + "]";
logger.info(startupBanner);
System.out.println(startupBanner);
started = true;
// Notify server listeners that the server has been started
for (XMPPServerListener listener : listeners) {
listener.serverStarted();
}
}
catch (Exception e) {
e.printStackTrace();
logger.error(e.getMessage(), e);
System.out.println(LocaleUtils.getLocalizedString("startup.error"));
shutdownServer();
}
}
也急速在home下的model下,用loader加载model
loader为刚设置进去的loader,然后loader文件下的所有class
加载进去了 然后得到实例 最后放进一个map里面。然后初始化model
private void initModules() {
for (Module module : modules.values()) {
try {
module.initialize(this);
}
catch (Exception e) {
e.printStackTrace();
// Remove the failed initialized module
this.modules.remove(module.getClass());
module.stop();
module.destroy();
logger.error(LocaleUtils.getLocalizedString("admin.error"), e);
}
}
// Register modules with service discovery provides where applicable.
for (Module module : modules.values() )
{
// Service discovery info
if (module instanceof ServerFeaturesProvider) {
getIQDiscoInfoHandler().addServerFeaturesProvider( (ServerFeaturesProvider) module );
}
if (module instanceof ServerIdentitiesProvider) {
getIQDiscoInfoHandler().addServerIdentitiesProvider( (ServerIdentitiesProvider) module );
}
if (module instanceof UserIdentitiesProvider) {
getIQDiscoInfoHandler().addUserIdentitiesProvider( (UserIdentitiesProvider) module );
}
// Service discovery items
if (module instanceof ServerItemsProvider) {
getIQDiscoItemsHandler().addServerItemsProvider( (ServerItemsProvider) module );
}
if (module instanceof UserItemsProvider) {
getIQDiscoItemsHandler().addUserItemsProvider( (UserItemsProvider) module);
}
}
}
先初始化model,然后在将model根据接口装进不同的handler里面,然后开始执行模块,最后完成模块的加载
接下来就是pluginManager了。
有点长,