如何为企业做网站,wordpress怎么弄登录,大学网站建设与功能开发,wordpress固定链接index.php在Java中#xff0c;您可以轻松地在Plain Old Java Object#xff08;POJO#xff09;类中实现一些业务逻辑#xff0c;并且可以在高级服务器或框架中轻松运行它们。 有许多服务器/框架#xff0c;例如JBossAS#xff0c;Spring或Camel等#xff0c;它们使您可以部署POJ… 在Java中您可以轻松地在Plain Old Java ObjectPOJO类中实现一些业务逻辑并且可以在高级服务器或框架中轻松运行它们。 有许多服务器/框架例如JBossASSpring或Camel等它们使您可以部署POJO甚至不对其API进行硬编码。 显然如果愿意耦合到它们的API细节您将获得高级功能但是即使您这样做也可以通过将自己的POJO和他们的API封装在包装器中来使这些特性降至最低。 通过尽可能简单的POJO编写和设计自己的应用程序您将拥有最灵活的方式来选择框架或服务器来部署和运行应用程序。 在这些环境中编写业务逻辑的一种有效方法是使用服务组件。 在本文中我将分享在编写Services方面学到的一些知识。 什么是服务 今天“ 服务 ”一词已被过度使用对不同的人可能意味着很多事情。 当我说Service时 我的定义是一个具有最小生命周期例如init start stop和destroy 的软件组件。 在编写的每个服务中您可能不需要生命周期的所有这些阶段但是您可以忽略那些不适用的服务。 在编写旨在长期运行的大型应用程序例如服务器组件时定义这些生命周期并确保按正确的顺序执行它们是至关重要的 我将引导您完成我准备的Java演示项目。 这是非常基础的应该独立运行。 它具有的唯一依赖性是SLF4J记录器。 如果您不知道如何使用记录器则只需将它们替换为System.out.println 。 但是我强烈建议您学习在应用程序开发期间如何有效使用记录器。 另外如果您想尝试与Spring相关的演示那么显然您也将需要其jar。 编写基本的POJO服务 您可以在界面中如下所示快速定义具有生命周期的服务合同。 package servicedemo;public interface Service {void init();void start();void stop();void destroy();boolean isInited();boolean isStarted();
} 开发人员可以自由地在Service实现中做他们想做的事情但是您可能想给他们一个适配器类这样他们就不必在每个Service上重写相同的基本逻辑。 我将提供这样的抽象服务 package servicedemo;import java.util.concurrent.atomic.*;
import org.slf4j.*;
public abstract class AbstractService implements Service {protected Logger logger LoggerFactory.getLogger(getClass());protected AtomicBoolean started new AtomicBoolean(false);protected AtomicBoolean inited new AtomicBoolean(false);public void init() {if (!inited.get()) {initService();inited.set(true);logger.debug({} initialized., this);}}public void start() {// Init service if it has not done so.if (!inited.get()) {init();}// Start service now.if (!started.get()) {startService();started.set(true);logger.debug({} started., this);}}public void stop() {if (started.get()) {stopService();started.set(false);logger.debug({} stopped., this);}}public void destroy() {// Stop service if it is still running.if (started.get()) {stop();}// Destroy service now.if (inited.get()) {destroyService();inited.set(false);logger.debug({} destroyed., this);}}public boolean isStarted() {return started.get();}public boolean isInited() {return inited.get();}Overridepublic String toString() {return getClass().getSimpleName() [id System.identityHashCode(this) ];}protected void initService() {}protected void startService() {}protected void stopService() {}protected void destroyService() {}
} 这个抽象类提供大多数服务需求的基础。 它有一个记录器并指出了生命周期。 然后它委托新的生命周期方法集以便子类可以选择重写。 注意 start()方法正在检查是否自动调用init() 。 在destroy()方法和stop()方法中也是如此。 如果我们要在只有两个阶段生命周期调用的容器中使用它则这一点很重要。 在这种情况下我们可以简单地调用start()和destroy()来匹配我们服务的生命周期。 一些框架可能会再进一步对于生命周期如每个阶段创建独立的接口InitableService或StartableService等但我认为这将是太多了在一个典型的应用。 在大多数情况下您想要简单的东西所以我只喜欢一个界面。 用户可以选择忽略不需要的方法或仅使用适配器类。 在结束本节之前我将提供一个愚蠢的Hello world服务以后可以在我们的演示中使用它。 package servicedemo;public class HelloService extends AbstractService {public void initService() {logger.info(this inited.);}public void startService() {logger.info(this started.);}public void stopService() {logger.info(this stopped.);}public void destroyService() {logger.info(this destroyed.);}
} 使用容器管理多个POJO服务 现在我们已经定义了服务定义的基础您的开发团队可能会开始编写业务逻辑代码 不久之后您将拥有自己的服务库以供重新使用。 为了能够有效地分组和控制这些服务我们还希望提供一个容器来管理它们。 这个想法是我们通常希望通过容器作为更高级别的组来控制和管理多个服务。 这是一个入门的简单实现 package servicedemo;import java.util.*;
public class ServiceContainer extends AbstractService {private ListService services new ArrayListService();public void setServices(ListService services) {this.services services;}public void addService(Service service) {this.services.add(service);}public void initService() {logger.debug(Initializing this with services.size() services.);for (Service service : services) {logger.debug(Initializing service);service.init();}logger.info(this inited.);}public void startService() {logger.debug(Starting this with services.size() services.);for (Service service : services) {logger.debug(Starting service);service.start();}logger.info(this started.);}public void stopService() {int size services.size();logger.debug(Stopping this with size services in reverse order.);for (int i size - 1; i 0; i--) {Service service services.get(i);logger.debug(Stopping service);service.stop();}logger.info(this stopped.);}public void destroyService() {int size services.size();logger.debug(Destroying this with size services in reverse order.);for (int i size - 1; i 0; i--) {Service service services.get(i);logger.debug(Destroying service);service.destroy();}logger.info(this destroyed.);}
} 从上面的代码中您将注意到一些重要的事情 我们扩展了AbstractService因此容器本身就是服务。 在进入下一个服务之前我们将调用所有服务的生命周期。 除非启动所有其他服务否则不会启动任何服务。 对于大多数一般用例我们应该以相反的顺序停止和销毁服务。 上面的容器实现很简单并且以同步方式运行。 这意味着您启动容器然后所有服务将按照您添加它们的顺序启动。 停止应该相同但顺序相反。 我也希望您能够看到有足够的空间来改进此容器。 例如您可以添加线程池以异步方式控制服务的执行。 运行POJO服务 通过一个简单的运行程序运行服务。 以最简单的形式我们可以自己运行POJO服务而无需任何高级服务器或框架。 Java程序是从静态main方法开始的因此我们肯定可以在其中调用init并start我们的服务。 但是当用户关闭程序时通常通过按CTRLC 我们还需要解决stop和destroy生命周期的问题。为此Java具有java.lang.Runtime#addShutdownHook()功能。 您可以创建一个简单的独立服务器来引导服务如下所示 package servicedemo;import org.slf4j.*;
public class ServiceRunner {private static Logger logger LoggerFactory.getLogger(ServiceRunner.class);public static void main(String[] args) {ServiceRunner main new ServiceRunner();main.run(args);}public void run(String[] args) {if (args.length 1)throw new RuntimeException(Missing service class name as argument.);String serviceClassName args[0];try {logger.debug(Creating serviceClassName);Class? serviceClass Class.forName(serviceClassName);if (!Service.class.isAssignableFrom(serviceClass)) {throw new RuntimeException(Service class serviceClassName did not implements Service.class.getName());}Object serviceObject serviceClass.newInstance();Service service (Service)serviceObject;registerShutdownHook(service);logger.debug(Starting service service);service.init();service.start();logger.info(service started.);synchronized(this) {this.wait();}} catch (Exception e) {throw new RuntimeException(Failed to create and run serviceClassName, e);}}private void registerShutdownHook(final Service service) {Runtime.getRuntime().addShutdownHook(new Thread() {public void run() {logger.debug(Stopping service service);service.stop();service.destroy();logger.info(service stopped.);}});}
} 使用优于跑步者您应该可以使用以下命令运行它 $ java demo.ServiceRunner servicedemo.HelloService 仔细查看您会发现您可以使用上述运行器有很多选择来运行多个服务。 让我突出几个 直接改善上述运行器并为每个新服务类名称而不是仅第一个元素使用所有args 。 或编写一个MultiLoaderService来加载所需的多个服务。 您可以使用“系统属性”控制参数传递。 您能想到其他改进此跑步者的方法吗 使用Spring运行服务 Spring框架是一个IoC容器众所周知它易于使用POJO而Spring可让您将应用程序连接在一起。 这将非常适合在我们的POJO服务中使用。 但是由于Spring提供了所有功能因此错过了易于使用的现成的主程序来引导spring config xml上下文文件。 但是就目前为止构建的内容而言这实际上是一件容易的事。 让我们编写一个POJO 服务来引导一个Spring上下文文件。 package servicedemo;import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;public class SpringService extends AbstractService {private ConfigurableApplicationContext springContext;public void startService() {String springConfig System.getProperty(springContext, spring.xml);springContext new FileSystemXmlApplicationContext(springConfig);logger.info(this started.);}public void stopService() {springContext.close();logger.info(this stopped.);}
} 使用该简单的SpringService您可以运行和加载任何spring xml文件。 例如尝试以下操作 $ java -DspringContextconfig/service-demo-spring.xml demo.ServiceRunner servicedemo.SpringService 在config/service-demo-spring.xml文件中您可以轻松地创建我们的容器该容器在Spring Bean中承载一项或多项服务。 beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdbean idhelloService classservicedemo.HelloService/beanbean idserviceContainer classservicedemo.ServiceContainer init-methodstart destroy-methoddestroyproperty nameserviceslistref beanhelloService//list/property/bean/beans 注意我只需要在serviceContainer bean上设置一次init-method和destroy-method 。 然后您可以根据需要添加一个或多个其他服务例如helloService 。 关闭Spring上下文时它们将全部启动管理然后关闭。 请注意Spring上下文容器没有明确地具有与我们的服务相同的生命周期。 Spring上下文将自动实例化您的所有依赖项Bean然后调用所有设置了init-method Bean。 所有这些操作都在FileSystemXmlApplicationContext的构造函数中完成。 用户未调用任何显式的init方法。 但是最后在服务停止期间Spring提供了container#close()来清理内容。 同样它们不区分stop destroy 。 因此我们必须合并我们的init并start进入Spring的init状态然后合并stop和destroy进入Spring的close状态。 回想一下我们的AbstractService#destory会自动调用stop如果尚未执行的话。 因此为了有效使用Spring我们需要了解这一技巧。 使用JEE应用服务器运行服务 在公司环境中我们通常没有自由运行独立程序所需的内容。 相反它们通常已经具有一些基础设施和更严格的标准技术堆栈例如使用JEE应用程序服务器。 在这种情况下运行POJO服务最可移植的是war Web应用程序。 在Servlet Web应用程序中您可以编写一个实现javax.servlet.ServletContextListener的类这将通过contextInitialized和contextDestroyed为您提供生命周期挂钩。 在其中您可以实例化ServiceContainer对象并相应地调用start和destroy方法。 您可以浏览以下示例 package servicedemo;
import java.util.*;
import javax.servlet.*;
public class ServiceContainerListener implements ServletContextListener {private static Logger logger LoggerFactory.getLogger(ServiceContainerListener.class);private ServiceContainer serviceContainer;public void contextInitialized(ServletContextEvent sce) {serviceContainer new ServiceContainer();ListService services createServices();serviceContainer.setServices(services);serviceContainer.start();logger.info(serviceContainer started in web application.);}public void contextDestroyed(ServletContextEvent sce) {serviceContainer.destroy();logger.info(serviceContainer destroyed in web application.);}private ListService createServices() {ListService result new ArrayListService();// populate services here.return result;}
} 您可以像上面这样在WEB-INF/web.xml配置 listenerlistener-classservicedemo.ServiceContainerListener/listener-class/listener/web-app 该演示提供了一个占位符您必须在代码中添加服务。 但是您可以使用web.xml作为上下文参数轻松地将其配置为可配置的。 如果要在Servlet容器中使用Spring则可以直接使用其org.springframework.web.context.ContextLoaderListener类该类与上述功能大致相同不同之处在于它们允许您使用contextConfigLocation上下文参数指定其xml配置文件。 这就是典型的基于Spring MVC的应用程序的配置方式。 设置完成后您可以像上面给出的Spring xml示例一样尝试我们的POJO服务以进行测试。 您应该在记录器的输出中看到我们的服务正在运行。 PS实际上我们在此描述的只是与Servlet Web应用程序相关而不与JEE有关。 因此您也可以使用Tomcat服务器。 服务生命周期的重要性及其在现实世界中的使用 我在这里提供的所有信息都不是新颖的也不是杀手级的设计模式。 实际上它们已在许多流行的开源项目中使用。 但是根据我过去的工作经验人们总是设法使这些变得极为复杂更糟糕的情况是他们在编写服务时完全无视生命周期的重要性。 的确并非您要编写的所有内容都需要安装到服务中但是如果发现需要请务必注意它们并请务必小心它们的正确调用。 您想要的最后一件事是退出JVM而不清理您为其分配了宝贵资源的服务。 如果您允许在部署过程中动态地重新加载应用程序而不退出JVM这些操作将变得更加灾难性这将导致系统资源泄漏。 以上服务实践已在TimeMachine项目中使用。 实际上如果您查看timemachine.scheduler.service.SchedulerEngine 它将只是许多运行在一起的服务的容器。 这就是用户可以通过编写Service来扩展调度程序功能的方式。 您可以通过一个简单的属性文件动态加载这些服务。 参考 如何在A Programmers Journal博客上从我们的JCG合作伙伴 Zemian Deng 编写更好的POJO服务 。 翻译自: https://www.javacodegeeks.com/2012/09/how-to-write-better-pojo-services.html