先贴出来sgs核心代码的中文注释的翻译,然后在对它的各个组件做简单的分析:
package com.sun.sgs.impl.kernel; import com.sun.sgs.kernel.NodeType; import com.sun.sgs.app.AppListener; import com.sun.sgs.app.NameNotBoundException; import com.sun.sgs.internal.InternalContext; import com.sun.sgs.auth.Identity; import com.sun.sgs.auth.IdentityAuthenticator; import com.sun.sgs.auth.IdentityCoordinator; import com.sun.sgs.impl.auth.IdentityImpl; import com.sun.sgs.impl.kernel.AccessCoordinatorImpl; import com.sun.sgs.impl.kernel.BootProperties; import com.sun.sgs.impl.kernel.ComponentRegistryImpl; import com.sun.sgs.impl.kernel.ConfigManager; import com.sun.sgs.impl.kernel.ContextResolver; import com.sun.sgs.impl.kernel.IdentityCoordinatorImpl; import com.sun.sgs.impl.kernel.KernelContext; import com.sun.sgs.impl.kernel.KernelShutdownController; import com.sun.sgs.impl.kernel.ManagerLocatorImpl; import com.sun.sgs.impl.kernel.StandardProperties; import com.sun.sgs.impl.kernel.StartupKernelContext; import com.sun.sgs.impl.kernel.TaskSchedulerImpl; import com.sun.sgs.impl.kernel.TransactionProxyImpl; import com.sun.sgs.impl.kernel.TransactionSchedulerImpl; import com.sun.sgs.impl.kernel.StandardProperties.StandardService; import com.sun.sgs.impl.kernel.logging.TransactionAwareLogManager; import com.sun.sgs.impl.profile.ProfileCollectorHandle; import com.sun.sgs.impl.profile.ProfileCollectorHandleImpl; import com.sun.sgs.impl.profile.ProfileCollectorImpl; import com.sun.sgs.impl.service.data.DataServiceImpl; import com.sun.sgs.impl.service.transaction.TransactionCoordinator; import com.sun.sgs.impl.service.transaction.TransactionCoordinatorImpl; import com.sun.sgs.impl.sharedutil.LoggerWrapper; import com.sun.sgs.impl.util.AbstractKernelRunnable; import com.sun.sgs.impl.util.Version; import com.sun.sgs.kernel.ComponentRegistry; import com.sun.sgs.profile.ProfileCollector; import com.sun.sgs.profile.ProfileCollector.ProfileLevel; import com.sun.sgs.profile.ProfileListener; import com.sun.sgs.service.DataService; import com.sun.sgs.service.Service; import com.sun.sgs.service.TransactionProxy; import com.sun.sgs.service.WatchdogService; import java.io.File; import java.io.InputStream; import java.io.IOException; import java.net.URL; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.Properties; import java.util.Timer; import java.util.TimerTask; import java.util.logging.Level; import java.util.logging.Logger; import java.util.logging.LogManager; import javax.management.JMException; /** * 功能描述: 这是中國壹石頭根据Project DarkStar自己的一个DarkStar服务器的<br> * 核心类,主要是用于学习和交流使用。 * * 这是整个服务器的核心类。这是第一个被创建的类,返回整个服务器的运行时间。<br> * 它的责任是负责初始化系统的所有组件和运行在整个系统上的应用的配置信息。 * <p> * * 根据默认的配置,系统内部使用最小的连接数量。要想使用大的连接数量,需要配置<br> * 这个核心类的 {@value com.sun.sgs.impl.kernel.Kernel0#PROFILE_LEVEL_PROPERTY} * 属性,这个属性值要在合法的范围内。 设置该类需要调用 *{@link com.sun.sgs.profile.ProfileCollector#setDefaultProfileLevel(ProfileLevel)} * 这个方法。 * * 根据系统的默认信息,没有连接事件的监听者。设置系统的这个 * {@value com.sun.sgs.impl.kernel.Kernel0#PROFILE_LISTENERS}监听者属性,需要 * 一个被独立复制(线程安全)的链表,并且要有完整的路径名,并且每个监听者都要实现<br> * {@link ProfileListener}这个接口。 * * @author 中國壹石頭 * @version 1.0 * @since 2009-04-24 22:13:40 */ class Kernel { // 该类的日志工具 private static final LoggerWrapper logger = new LoggerWrapper(Logger .getLogger(Kernel.class.getName())); // 设置连接的客户端的连接等级 public static final String PROFILE_LEVEL_PROPERTY = "com.sun.sgs.impl.kernel.profile.level"; // 设置客户端连接的监听程序 public static final String PROFILE_LISTENERS = "com.sun.sgs.impl.kernel.profile.listeners"; // 默认的客户端认证用户 private static final String DEFAULT_IDENTITY_AUTHENTICATOR = "com.sun.sgs.impl.auth.NullAuthenticator"; // 默认的服务 private static final String DEFAULT_CHANNEL_SERVICE = "com.sun.sgs.impl.service.channel.ChannelServiceImpl"; private static final String DEFAULT_CLIENT_SESSION_SERVICE = "com.sun.sgs.impl.service.session.ClientSessionServiceImpl"; private static final String DEFAULT_DATA_SERVICE = "com.sun.sgs.impl.service.data.DataServiceImpl"; private static final String DEFAULT_TASK_SERVICE = "com.sun.sgs.impl.service.task.TaskServiceImpl"; private static final String DEFAULT_WATCHDOG_SERVICE = "com.sun.sgs.impl.service.watchdog.WatchdogServiceImpl"; private static final String DEFAULT_NODE_MAPPING_SERVICE = "com.sun.sgs.impl.service.nodemap.NodeMappingServiceImpl"; // 默认的数据库管理程序 private static final String DEFAULT_CHANNEL_MANAGER = "com.sun.sgs.impl.app.profile.ProfileChannelManager"; private static final String DEFAULT_DATA_MANAGER = "com.sun.sgs.impl.app.profile.ProfileDataManager"; private static final String DEFAULT_TASK_MANAGER = "com.sun.sgs.impl.app.profile.ProfileTaskManager"; // 默认的服务器连接的关闭时间(15分钟) private static final int DEFAULT_SHUTDOWN_TIMEOUT = 15 * 600000; // 所有事务处理组件的代理 private static final TransactionProxy proxy = new TransactionProxyImpl(); // the properties used to start the application // 这个属性用于启动应用程序 private final Properties appProperties; // the schedulers used for transactional and non-transactional tasks // 这个计划任务用户事务和非事务的任务 private final TransactionSchedulerImpl transactionScheduler; private final TaskSchedulerImpl taskScheduler; // the application that is running in this kernel // 这个应用用于启动该服务器核心类 private KernelContext application; // The system registry which contains all shared system components // 该属性用于系统注册所有包含系统共享信息的组件 private final ComponentRegistryImpl systemRegistry; // collector of profile information // 收集系统的文件信息 private final ProfileCollectorImpl profileCollector; // shutdown controller that can be passed to components who need to be able // to issue a kernel shutdown. the watchdog also constains a reference for // services to call shutdown. // 关闭控制器可以被传输到因为某些问题需要关闭服务器的组件中。这个看门狗也包含一个引用 // 用于让服务(业务逻辑层)来调用关闭事件。 private final KernelShutdownControllerImpl shutdownCtrl = new KernelShutdownControllerImpl(); // specifies whether this node has already been shutdown // 验证某个节点是否已经关闭 private boolean isShutdown = false; /** * * 创建一个<code>EstoneKernel</code>的实例。一旦该实例被创建,系统的组件<br> * 就已经准备好并开始运行。创建一个当然也会使系统初始化并启动整个服务器应<br> * 用和该服务器相关的服务。 * * @param appProperties * 应用程序的属性 * * @throws Exception * 如果有任何原因导致服务器不能正常启动,则抛出该异常。 */ protected Kernel(Properties appProperties) throws Exception { logger.log(Level.CONFIG, "Booting the Kernel"); this.appProperties = appProperties;// 获取应用程序接口的属性配置文件 try { // 检查我们是否最服务器的应用信息做了配置。 String level = appProperties.getProperty(PROFILE_LEVEL_PROPERTY, ProfileLevel.MIN.name()); ProfileLevel profileLevel;// 配置信息的等级 try { profileLevel = ProfileLevel.valueOf(level.toUpperCase());// 获取配置信息的等级值 if (logger.isLoggable(Level.CONFIG)) { logger.log(Level.CONFIG, "Profiling level is {0}", level); } } catch (IllegalArgumentException iae) { // 若参数不符合要求则抛出参数非法的异常。 if (logger.isLoggable(Level.WARNING)) { logger.log(Level.WARNING, "Unknown profile level {0}", level); } throw iae; } // 创建系统的组件注册器 systemRegistry = new ComponentRegistryImpl(); // 创建服务器信息的管理器 profileCollector = new ProfileCollectorImpl(profileLevel, appProperties, systemRegistry); // 创建处理服务器信息管理器的句柄 ProfileCollectorHandle profileCollectorHandle = new ProfileCollectorHandleImpl( profileCollector); // 创建服务器MBean的配置器,并将它注册到系统中。这个用于 // 构造函数和后面的组件中。 ConfigManager config = new ConfigManager(appProperties); try { // 向配置信息的管理器注册管理MBean的配置器和名字 profileCollector.registerMBean(config, ConfigManager.MXBEAN_NAME); } catch (JMException e) { // 若不能注册,抛出不能注册的异常 logger.logThrow(Level.CONFIG, e, "Could not register MBean"); } // 创建认证组件和该认证组件的协作者 ArrayList<IdentityAuthenticator> authenticators = new ArrayList<IdentityAuthenticator>(); /** * 从属性文件中读取要认证的组件的类名,这里使用的 Properties.getProperty() * 方法是调用的JDK中的属性文件的操作的一个方法,该方法是用于: * 根据制定的键值(key)从属性文件中寻找对应的属性值。如果这个键值没有在这 * 在这个属性文件中,该方法会对整个属性文件进行检验,并返回该属性文件默 认的一个属性值。 */ String[] authenticatorClassNames = appProperties.getProperty( StandardProperties.AUTHENTICATORS, DEFAULT_IDENTITY_AUTHENTICATOR).split(":"); // 从属性文件中读取所有已经注册(配置)的组件信息 for (String authenticatorClassName : authenticatorClassNames) { authenticators.add(getAuthenticator(authenticatorClassName, appProperties)); } // 调用组件信息认证的协作者对该组件列表进行验证 IdentityCoordinator identityCoordinator = new IdentityCoordinatorImpl( authenticators); // 初始化事务信息的验证者 TransactionCoordinator transactionCoordinator = new TransactionCoordinatorImpl( appProperties, profileCollectorHandle); // 尽可能的更新的事物的日志信息 LogManager logManager = LogManager.getLogManager(); // 如果日志系统被配置为要处理事务的日志信息,那么这个日志信息的 // 管理者就必须是一个TransactionAwareLogManager类型的对象 if (logManager instanceof TransactionAwareLogManager) { TransactionAwareLogManager txnAwareLogManager = (TransactionAwareLogManager) logManager; // 通过事务的日志管理对象将注册的组件添加到事务处理的代理中 txnAwareLogManager.configure(appProperties, proxy); } // 创建客户端访问的协作者,传递的三个参数分别是 // appProperties 处理事物的组件信息 // proxy 事务处理的代理 // profileCollectorHandle 经过配置的处理对应事务的Handler AccessCoordinatorImpl accessCoordinator = new AccessCoordinatorImpl( appProperties, proxy, profileCollectorHandle); // 创建一个计划的事务处理对象,并提供一个空的上下文,以防止 // 任何已经配置的组件尝试这去执行事务 /** * 解释一个这几个参数的含义: appProperties 待处理的已经注册的组件 transactionCoordinator * 事务处理的协作者 profileCollectorHandle 处理相关事务的句柄 accessCoordinator * 客户端访问信息的协作者 * */ transactionScheduler = new TransactionSchedulerImpl(appProperties, transactionCoordinator, profileCollectorHandle, accessCoordinator); // 事务计划的真正处理者(任务的具体处类) taskScheduler = new TaskSchedulerImpl(appProperties, profileCollectorHandle); // 服务器核心类的上下文 KernelContext ctx = new StartupKernelContext("EstoneKernel"); transactionScheduler.setContext(ctx);// 设置事件处理的上下文 taskScheduler.setContext(ctx);// 设置任务调度的上下文 // 收集系统的共享组件,并将其注册到系统的注册器中 systemRegistry.addComponent(accessCoordinator);// 注册访问处理组件 systemRegistry.addComponent(transactionScheduler);// 注册事务处理计划组件 systemRegistry.addComponent(taskScheduler);// 注册任务调度组件 systemRegistry.addComponent(identityCoordinator);// 注册组件信息认证组件 systemRegistry.addComponent(profileCollector);// 注册配置信息的管理者 // 创建配置文件的监听者。知道我们将组件注册到系统中后,当 // 其他的监听者使用该组件的时候,我们就会知道他的重要性了。 loadProfileListeners(profileCollector);// 装载配置文件的监听者 if (logger.isLoggable(Level.INFO)) { logger.log(Level.INFO, "The Kernel is ready, version: {0}", Version.getVersion()); } // 系统的核心程序已经准备好了,所以开始启动这个应用程序。 createAndStartApplication(); } catch (Exception e) { if (logger.isLoggable(Level.SEVERE)) { logger.logThrow(Level.SEVERE, e, "Failed on Kernel boot"); } // 无论何时我们启动服务器,只要有异常抛出,都要关闭服务器 shutdown(); throw e; } } /** *一个私有的方法,用于加载所有请求注册的组件监听者的配置数据。 */ private void loadProfileListeners(ProfileCollector profileCollector) { // 从系统配置文件管理器中获取所有要注册的监听组件信息 String listenerList = appProperties.getProperty(PROFILE_LISTENERS); if (listenerList != null) { // 将所有的组件信息添加到服务器的监听者序列中 for (String listenerClassName : listenerList.split(":")) { try { profileCollector.addListener(listenerClassName); } catch (InvocationTargetException e) { // 通过java的映射机制跳出异常机制 if (logger.isLoggable(Level.WARNING)) { logger .logThrow( Level.WARNING, e.getCause(), "Failed to load ProfileListener {0} ... " + "it will not be available for profiling", listenerClassName); } } catch (Exception e) { if (logger.isLoggable(Level.WARNING)) { logger .logThrow( Level.WARNING, e, "Failed to load ProfileListener {0} ... " + "it will not be available for profiling", listenerClassName); } } } } // 最后也将计划任务注册为一个监听器 // 注意:如果我们添加计划任务的插件时,或者添加的组件是监听器的时候 // 我们需要扫描系统中的所有组件,并验证他们是不是监听者 profileCollector.addListener(transactionScheduler, false); } /** * 帮助启动服务器的应用程序。这个方法配置与应用相关的服务,并启动该应用 * * @throws Exception * if there is any error in startup 若启动错误,则抛出异常 */ private void createAndStartApplication() throws Exception { String appName = appProperties.getProperty(StandardProperties.APP_NAME); if (logger.isLoggable(Level.CONFIG)) { logger.log(Level.CONFIG, "{0}: starting application", appName); } // 开始创建服务 IdentityImpl owner = new IdentityImpl("app:" + appName); createServices(appName, owner);// 创建服务 startApplication(appName, owner);// 启动应用 } /** * 按顺序创建每一个服务和与该服务相关的管理器,为启动该应用做准备 */ private void createServices(String appName, Identity owner) throws Exception { if (logger.isLoggable(Level.CONFIG)) { logger.log(Level.CONFIG, "{0}: starting services", appName); } // 创建并添加一个完整用于启动的上下文信息 application = new StartupKernelContext(appName); transactionScheduler.setContext(application); taskScheduler.setContext(application); ContextResolver.setTaskState(application, owner); // 通知应用程序的上下文怎样去寻找其相关的管理器 InternalContext.setManagerLocator(new ManagerLocatorImpl()); try { fetchServices((StartupKernelContext) application); } catch (Exception e) { if (logger.isLoggable(Level.SEVERE)) { logger.logThrow(Level.SEVERE, e, "{0}: failed to create " + "services", appName); } throw e; } // 当所有的管理者都被完整的创建时,交换一个用于验证的上下文 application = new KernelContext(application); transactionScheduler.setContext(application); taskScheduler.setContext(application); ContextResolver.setTaskState(application, owner); // 通知所有已经准备好的应用程序的服务 try { application.notifyReady(); } catch (Exception e) { if (logger.isLoggable(Level.SEVERE)) { logger.logThrow(Level.SEVERE, e, "{0}: failed when notifying " + "services that application is ready", appName); } throw e; } // 使用关闭控制器,一但各组件和服务都已经建立,并允许一个节点关闭时调用它们中的 // 任何一个 shutdownCtrl.setReady(); } /** * 该方法是一个私有的方法,用于帮助创建服务和与服务相关的管理器,首先要<br> * 小心的调用标准的服务,因为我们需要按顺序排列,并确定他们都存在。 */ private void fetchServices(StartupKernelContext startupContext) throws Exception { // 在我们启动前,要验证我们是运行在一个服务的子集合,在这种情况下 // 不能扩展该服务集合 String finalService = appProperties .getProperty(StandardProperties.FINAL_SERVICE); StandardService finalStandardService = null; String externalServices = appProperties .getProperty(StandardProperties.SERVICES); String externalManagers = appProperties .getProperty(StandardProperties.MANAGERS); if (finalService != null) { if ((externalServices != null) || (externalManagers != null)) { throw new IllegalArgumentException( "Cannot specify external services and a final service"); } // 验证最终的服务 try { finalStandardService = Enum.valueOf(StandardService.class, finalService); } catch (IllegalArgumentException iae) { if (logger.isLoggable(Level.SEVERE)) { logger.logThrow(Level.SEVERE, iae, "Invalid final " + "service name: {0}", finalService); } throw iae; } // 确认我们没有运行一个应用 if (!appProperties.getProperty(StandardProperties.APP_LISTENER) .equals(StandardProperties.APP_LISTENER_NONE)) { throw new IllegalArgumentException("Cannot specify an app " + "listener and a final " + "service"); } } else { finalStandardService = StandardService.LAST_SERVICE; } final int finalServiceOrdinal = finalStandardService.ordinal(); // 加载数据服务 String dataServiceClass = appProperties.getProperty( StandardProperties.DATA_SERVICE, DEFAULT_DATA_SERVICE); String dataManagerClass = appProperties.getProperty( StandardProperties.DATA_MANAGER, DEFAULT_DATA_MANAGER); setupService(dataServiceClass, dataManagerClass, startupContext); // 为没有相关管理器的服务添加看门狗 if (StandardService.WatchdogService.ordinal() > finalServiceOrdinal) { return; } String watchdogServiceClass = appProperties.getProperty( StandardProperties.WATCHDOG_SERVICE, DEFAULT_WATCHDOG_SERVICE); setupServiceNoManager(watchdogServiceClass, startupContext); // 为看门狗服务提供一个句柄用于关闭控制器 shutdownCtrl.setWatchdogHandle(startupContext .getService(WatchdogService.class)); // 为没有相关关联器的服务,添加节点的映射信息 if (StandardService.NodeMappingService.ordinal() > finalServiceOrdinal) { return; } String nodemapServiceClass = appProperties.getProperty( StandardProperties.NODE_MAPPING_SERVICE, DEFAULT_NODE_MAPPING_SERVICE); setupServiceNoManager(nodemapServiceClass, startupContext); // 加载任务服务 if (StandardService.TaskService.ordinal() > finalServiceOrdinal) { return; } String taskServiceClass = appProperties.getProperty( StandardProperties.TASK_SERVICE, DEFAULT_TASK_SERVICE); String taskManagerClass = appProperties.getProperty( StandardProperties.TASK_MANAGER, DEFAULT_TASK_MANAGER); setupService(taskServiceClass, taskManagerClass, startupContext); // 加载客户端的会话服务,这个服务没有相关的管理器 if (StandardService.ClientSessionService.ordinal() > finalServiceOrdinal) { return; } String clientSessionServiceClass = appProperties.getProperty( StandardProperties.CLIENT_SESSION_SERVICE, DEFAULT_CLIENT_SESSION_SERVICE); setupServiceNoManager(clientSessionServiceClass, startupContext); // 加载数据通道服务 if (StandardService.ChannelService.ordinal() > finalServiceOrdinal) { return; } String channelServiceClass = appProperties.getProperty( StandardProperties.CHANNEL_SERVICE, DEFAULT_CHANNEL_SERVICE); String channelManagerClass = appProperties.getProperty( StandardProperties.CHANNEL_MANAGER, DEFAULT_CHANNEL_MANAGER); setupService(channelServiceClass, channelManagerClass, startupContext); // 最后加载所有的扩展服务和他们相关的服务管理器 if ((externalServices != null) && (externalManagers != null)) { String[] serviceClassNames = externalServices.split(":", -1); String[] managerClassNames = externalManagers.split(":", -1); if (serviceClassNames.length != managerClassNames.length) { if (logger.isLoggable(Level.SEVERE)) { logger.log(Level.SEVERE, "External service count " + "({0}) does not match manager count ({1}).", serviceClassNames.length, managerClassNames.length); } throw new IllegalArgumentException("Mis-matched service " + "and manager count"); } for (int i = 0; i < serviceClassNames.length; i++) { if (!managerClassNames[i].equals("")) { setupService(serviceClassNames[i], managerClassNames[i], startupContext); } else { setupServiceNoManager(serviceClassNames[i], startupContext); } } } } /** * 用完整的类名来创建一个没有管理器的服务 */ private void setupServiceNoManager(String className, StartupKernelContext startupContext) throws Exception { Class<?> serviceClass = Class.forName(className); Service service = createService(serviceClass); startupContext.addService(service); } /** * 根据(一个服务的完整的类名)创建一个服务和其相关的管理器。 */ private void setupService(String serviceName, String managerName, StartupKernelContext startupContext) throws Exception { // 获取服务的实例 Class<?> serviceClass = Class.forName(serviceName); Service service = createService(serviceClass); // (根据Java的映射机制)反转一个服务的类和构造器,根据构造器检查 // 服务的类型,检测其是否是一个Service的一个超类型 Class<?> managerClass = Class.forName(managerName); Constructor<?>[] constructors = managerClass.getConstructors(); Constructor<?> managerConstructor = null; for (int i = 0; i < constructors.length; i++) { Class<?>[] types = constructors[i].getParameterTypes(); if (types.length == 1) { if (types[0].isAssignableFrom(serviceClass)) { managerConstructor = constructors[i]; break; } } } // 如果我们没有找到和管理器相匹配的构造器,这就是一个错误。 if (managerConstructor == null) { throw new NoSuchMethodException("Could not find a constructor " + "that accepted the Service"); } // 创建一个管理器,并将其放入服务的管理器和组件启动的上下文中 Object manager = managerConstructor.newInstance(service); startupContext.addService(service); startupContext.addManager(manager); } /** * 一个私有的方法,该方法用于创建一个法服务的实例,但是该服务没有相关的管理<br> * 器, 该实例是通过服务类的完整类名来创建的。 */ private Service createService(Class<?> serviceClass) throws Exception { Constructor<?> serviceConstructor; try { // 查找服务相关的构造器 serviceConstructor = serviceClass.getConstructor(Properties.class, ComponentRegistry.class, TransactionProxy.class); // 返回一个实例 return (Service) (serviceConstructor.newInstance(appProperties, systemRegistry, proxy)); } catch (NoSuchMethodException e) { // 若上面的方法检测时服务器抛出异常,就检测带有四个参数的构造器,并且该构造器应该 // 创建的服务应该带有一个用于关闭服务的方法。 serviceConstructor = serviceClass.getConstructor(Properties.class, ComponentRegistry.class, TransactionProxy.class, KernelShutdownController.class); // 返回一个服务的实例 return (Service) (serviceConstructor.newInstance(appProperties, systemRegistry, proxy, shutdownCtrl)); } } // 启动应用程序,若出现问题则抛出一个异常 private void startApplication(String appName, Identity owner) throws Exception { // 到此系统的服务已经准备完毕,最后一步就是通过一个特定的无阻塞的事务处理的核心 // 线程来初始化这个应用这个应用。否则我们启动后,系统将无法提供服务。 if (!appProperties.getProperty(StandardProperties.APP_LISTENER).equals( StandardProperties.APP_LISTENER_NONE)) { try { if (logger.isLoggable(Level.CONFIG)) { logger.log(Level.CONFIG, "{0}: starting application", appName); } // 计划处理事务的实例启动,用于调用一个非绑定的服务 // 来完成系统的服务的初始化 transactionScheduler.runUnboundedTask(new AppStartupRunner( appProperties), owner); logger .log(Level.INFO, "{0}: application is ready", application); } catch (Exception e) { if (logger.isLoggable(Level.CONFIG)) { logger.logThrow(Level.CONFIG, e, "{0}: failed to " + "start application", appName); } throw e; } } else { // 若添加的服务不符合系统服务的要求,那么这个系统启动后将无法提供相关法服务, // 到此我们整个服务的启动就完成了。 logger.log(Level.INFO, "{0}: non-application context is ready", application); } } /** * 在节点的处理线程消耗的时间过长时, 计时器将调用{@link System#exit System.exit} * 系统退出的方法,强制该节点的事务处理线程关闭。这个计时器是一个守护进程,所以<br> * . 当 一 个服务正常完整的关闭时,任务不会运行该程序。 */ private void startShutdownTimeout(final int timeout) { new Timer(true).schedule(new TimerTask() { public void run() { System.exit(1); } }, timeout); } /** * 关闭所有的服务和计划任务(按一定的顺序关闭) */ synchronized void shutdown() { if (isShutdown) { return; } startShutdownTimeout(DEFAULT_SHUTDOWN_TIMEOUT); logger.log(Level.FINE, "Kernel.shutdown() called."); // 关闭系统的应用和服务 if (application != null) { application.shutdownServices(); } // 关闭系统的配置信息管理器 if (profileCollector != null) { profileCollector.shutdown(); } // The schedulers must be shut down last. // 事务的计划任务必须在最后关闭 if (transactionScheduler != null) { transactionScheduler.shutdown(); } // 关闭任务的计划任务 if (taskScheduler != null) { taskScheduler.shutdown(); } logger.log(Level.FINE, "Node is shut down."); isShutdown = true; } /** * 创建一个新的系统验证者。 */ private IdentityAuthenticator getAuthenticator(String className, Properties properties) throws Exception { Class<?> authenticatorClass = Class.forName(className); Constructor<?> authenticatorConstructor = authenticatorClass .getConstructor(Properties.class); return (IdentityAuthenticator) (authenticatorConstructor .newInstance(properties)); } /** * 一个帮助助手程序,用与装载属性配置文件,用于保存系统的属性信息。 */ private static Properties loadProperties(URL resource, Properties backingProperties) throws Exception { InputStream in = null; try { Properties properties; if (backingProperties == null) { // 创建一个在系统运行期间保存系统属性的一个实例 properties = new Properties(); } else { properties = new Properties(backingProperties); } in = resource.openStream();// 打开文件的操作 properties.load(in);// 将属性文件加载到流中 return properties; } catch (IOException ioe) { if (logger.isLoggable(Level.SEVERE)) { logger.logThrow(Level.SEVERE, ioe, "Unable to load " + "from resource {0}: ", resource); } throw ioe; } finally { if (in != null) { try { in.close(); } catch (IOException e) { if (logger.isLoggable(Level.CONFIG)) { logger.logThrow(Level.CONFIG, e, "failed to close " + "resource {0}", resource); } } } } } /** * 一个助手程序用于过滤属性信息。加载系统需要的默认的相关属性信息。 */ private static Properties filterProperties(Properties properties) throws Exception { try { // 根据需要扩展相关的属性 String value = properties.getProperty(StandardProperties.NODE_TYPE); if (value == null) { // 系统默认的是一个单独的节点 value = NodeType.singleNode.name(); } NodeType type; // 当属性中没有一个枚举类型的 参数并要改变错误的信息的时候,将抛<br> // 出以参数非法的异常。 try { type = NodeType.valueOf(value); } catch (IllegalArgumentException e) { throw new IllegalArgumentException("Illegal value for " + StandardProperties.NODE_TYPE); } // 根据参数的类型判断 switch (type) { case singleNode: default: break; // 由于单节点是系统默认的,所以不用做任何处理 case coreServerNode:// 核心服务节点 // 不启动相关的应用 properties.setProperty(StandardProperties.APP_LISTENER, StandardProperties.APP_LISTENER_NONE); // 只是运行一些基础的服务组件 properties.setProperty(StandardProperties.FINAL_SERVICE, "NodeMappingService"); // 启动服务的相关服务 properties.setProperty(StandardProperties.SERVER_START, "true"); // 启动网络服务用于存储数据 properties.setProperty( DataServiceImpl.DATA_STORE_CLASS_PROPERTY, "com.sun.sgs.impl.service.data." + "store.net.DataStoreClient"); break; case appNode: // 应用程序节点 // 不启动服务 properties .setProperty(StandardProperties.SERVER_START, "false"); break; } return properties; } catch (IllegalArgumentException iae) { if (logger.isLoggable(Level.SEVERE)) { logger.logThrow(Level.SEVERE, iae, "Illegal data in " + "properties"); } throw iae; } } /** * 检验属性文件中一些明显的错误信息。当有错误时记录并抛出一个参数非法的异常。 */ private static void checkProperties(Properties appProperties) { String appName = appProperties.getProperty(StandardProperties.APP_NAME); // 当要启动应用程序的时候,确认在当前至少有一个需要的主键。 if (appName == null) { logger.log(Level.SEVERE, "Missing required property " + StandardProperties.APP_NAME); throw new IllegalArgumentException("Missing required property " + StandardProperties.APP_NAME); } if (appProperties.getProperty(StandardProperties.APP_ROOT) == null) { logger.log(Level.SEVERE, "Missing required property " + StandardProperties.APP_ROOT + " for application: " + appName); throw new IllegalArgumentException("Missing required property " + StandardProperties.APP_ROOT + " for application: " + appName); } if (appProperties.getProperty(StandardProperties.APP_LISTENER) == null) { logger.log(Level.SEVERE, "Missing required property " + StandardProperties.APP_LISTENER + "for application: " + appName); throw new IllegalArgumentException("Missing required property " + StandardProperties.APP_LISTENER + "for application: " + appName); } } /** * 当第一次启动程序的时候,在没有其他的应用被调用七千,这个线程用于应用<br> * 程序的 调用初始化方法。 */ private static final class AppStartupRunner extends AbstractKernelRunnable { // 应用的属性 private final Properties properties; // 创建一个AppStartupRunner的实例 AppStartupRunner(Properties properties) { super(null); this.properties = properties; } // 启动应用程序,当启动失败时,抛出一个异常。 public void run() throws Exception { DataService dataService = Kernel.proxy .getService(DataService.class); try { // 通过测试检测该程序的名字是否和设定的相符合,并且检测 // 该程序的监听者是否已经被绑定了。 dataService.getServiceBinding(StandardProperties.APP_LISTENER); } catch (NameNotBoundException nnbe) { // 若没有,则创建并给其绑定一个监听者。 String appClass = properties .getProperty(StandardProperties.APP_LISTENER); AppListener listener = (AppListener) (Class.forName(appClass) .newInstance()); dataService.setServiceBinding(StandardProperties.APP_LISTENER, listener); // 当我们创建一个监听者时,我们是第一次启动这个应用程序 // 所以我们也需要启动它。 listener.initialize(properties); } } } /** * 该对象提供了一个关闭服务器的信息,它由核心的服务器程序 {@code Kernel}创建 * 并将其传递到系统服务和组件中。该对象允许服务器的在需要的时候关闭一个节点的<br> * 操作发生关系,比如当一个服务连接失败,或者是节点变得无效的时候。 */ private final class KernelShutdownControllerImpl implements KernelShutdownController { private WatchdogService watchdogSvc = null; private boolean shutdownQueued = false; private boolean isReady = false; private final Object shutdownQueueLock = new Object(); /** * 这个方法为关闭看门狗程序提供了一个句柄。组件层可以利用该句柄将该 错误<br> * 信息传递给看门够,从而取代直接关闭一个服务的方式。当一个节点 需要关闭时,<br> * 对应的服务得到了通知,该方法被允许调用。这个句柄只能 被调用<br> * 一次,任何一个调用将会使该方法厌恶。 */ public void setWatchdogHandle(WatchdogService watchdogSvc) { if (this.watchdogSvc != null) { // 当看门狗已经存在时,拒绝对其进行重写。 return; } this.watchdogSvc = watchdogSvc; } /** * 这个方法标记当控制器出现问题时被关闭。当关闭操作确实被放入到了 关<br> * 闭事件的队列中,节点就已经被关闭了。 */ public void setReady() { synchronized (shutdownQueueLock) { isReady = true; if (shutdownQueued) { shutdownNode(this); } } } /** * 该方法用于关闭一个节点。 */ public void shutdownNode(Object caller) { synchronized (shutdownQueueLock) { if (isReady) { // 服务已经被关闭。我们已经通知了服务器,所现在可以关闭节点了。 if (caller instanceof WatchdogService) { runShutdown(); } else { // 关闭组件。我们通过通知看门狗来清理并首先通知服务器。 if (watchdogSvc != null) { watchdogSvc.reportFailure(watchdogSvc .getLocalNodeId(), caller.getClass() .toString()); } else { // 当看门狗还没有被创建直接关闭服务器。 runShutdown(); } } } else { // 当服务器的核心程序还未准备好时,将节点的请求放 // 入事件对列中。 shutdownQueued = true; } } } /** * 关闭节点。该方法启动一个新的线程,用与阻止可能发生的死锁。目的是使服务层 * 或者是组件层调用关闭方法的时候等待发生问题的线程从被关闭的方法中退出。例如, * 当核心程序关闭并重新创建一个线程时,且看门够服务关闭已经后,方法将阻塞。 */ private void runShutdown() { logger.log(Level.WARNING, "Controller issued node shutdown."); new Thread(new Runnable() { public void run() { shutdown(); } }).start(); } } /** * 该方法用于自动检测后服务器应用配置信息的集合。 */ private static Properties findProperties(String propLoc) throws Exception { // 如果文件存在时,根据指定的设置加载指定的配置文件的信息。 Properties baseProperties = new Properties(); URL propsIn = ClassLoader .getSystemResource(BootProperties.DEFAULT_APP_PROPERTIES); if (propsIn != null) { baseProperties = loadProperties(propsIn, null); } // 根据文件名的参数加载服务的配置信息集合。 Properties fileProperties = baseProperties; if (propLoc != null && !propLoc.equals("")) { File propFile = new File(propLoc); if (!propFile.isFile() || !propFile.canRead()) { logger.log(Level.SEVERE, "can't access file : " + propFile); throw new IllegalArgumentException("can't access file " + propFile); } fileProperties = loadProperties(propFile.toURI().toURL(), baseProperties); } // 如果一个配置信息的集合存在于用户的根目录下,就使用该目录 // 覆盖其他的配置文件的配置信息。 Properties homeProperties = fileProperties; File homeConfig = new File(System.getProperty("user.home") + File.separator + BootProperties.DEFAULT_HOME_CONFIG_FILE); if (homeConfig.isFile() && homeConfig.canRead()) { homeProperties = loadProperties(homeConfig.toURI().toURL(), fileProperties); } else if (homeConfig.isFile() && !homeConfig.canRead()) { logger.log(Level.WARNING, "can't access file : " + homeConfig); } // 从系统的配置取值,复写系统所有的属性信息 Properties finalProperties = new Properties(homeProperties); finalProperties.putAll(System.getProperties()); return finalProperties; } /** * r用于启动核心程序的一个主线程。每个核心程序的实<br> * 例返回一个独立的应用的实例。 * * <p> * 如果一个单例的参数给定了,该值将被当作一个问价的参数。该文件用与检测服务的<br> * 设置属性,并联合使用一些集合来合作配置服务的信息。 * * <p> * 整个服务器加载和配置属性文件的顺序如下: * * (1)系统的属性指定的命令参数为"-D"<br> * (2)用户目录下的命令参数根据 {@link BootProperties#DEFAULT_HOME_CONFIG_FILE}来指定。 <br> * (3)属性文件在文件中之处了命令行的参数。 * * (4)这个文件明显的包含了包含整个应用的一个jar文件。属性文件根据名字指定了 服务的源文件所在地位置。 * * 若给定的属性文件没有配置任何的属性值。系统默认使用抛出一个异常。(根据 默认的信息是否<br> * 合法。) 一些特殊的属性需要被指定在应用的配置信息中。请查看{@link StandardProperties}<br> * (标准信息配置)中指定的需要设置参数和属性值 的标准。<br> * * @param args * 配置文件用于获取属性值对象,该属性对象和程序的运行相关。 * * @throws Exception * if there is any problem starting the system */ public static void main(String[] args) throws Exception { // 确认我们没有太多的信息 if (args.length > 1) { logger.log(Level.SEVERE, "Invalid number of arguments: halting"); System.exit(1); } // 如果一个特定的参数在命令行中被指定,该参数就会被当作 // 文件的名字。 Properties appProperties; if (args.length == 1) { appProperties = findProperties(args[0]); } else { appProperties = findProperties(null); } // 通过默认的信息,过滤属性文件 filterProperties(appProperties); // 检测标准的配置信息 checkProperties(appProperties); // 启动核心程序 new Kernel(appProperties); } }