WebService(9)_Apache CXF_CXFFrame_发布框架

CXFFrame 

封装CXF框架(发布平台),业务模块作为SDK插入平台


目的:

    1.封装WebService发布过程 

    2.对外发布一个WebService服务,即可包含不同的业务模块,统一入口/出口 参数类型

    3.WebService服务 与 业务模块代码 解耦

    4.业务组开发人员不用再关心WebService的发布,只要关注SDK业务模块的业务处理即可

    5.业务模块可插拔,更灵活


平台功能:

    1.发布WebService服务

    2.加载SDK业务模块程序

    3.加载SDK业务模块配置信息

    4.对传递的参数做基本校验功能

    5.SDK私有模块的实例化


CXFFrame平台源码已经上传GitHub,如果代码更新就在这个上面(CSDN下载包不更新),地址:CXFFrame

CXFFrame Linux服务器安装包,地址:CXFFrame平台 模块SDK Linux安装包

CXFFrame平台-SDK源码,地址:CXFFrame平台-SDKDemo源码


在平台中有一个抽象类ServiceBase,SDK模块主类继承这个类之后,实现三个方法,分别是:(调用顺序也是以下顺序)

loadConfig(HashMap<String, String> configs):从平台中获取sdk私有模块配置信息

init():sdk私有模块参数/资源初始化

process(String params):sdk私有模块主方法


下面讲解下CXFFrame平台的代码:

cxfframe_conf.properties

#CXF发布端口
CXFFRAME_PORT=9099
#CXF发布服务名
CXFFRAME_RELEASE_NAME=CXFFrame_QueryService

这个是平台发布WebService的必要参数,这里只要指定发布名称和端口,平台默认读取安装机器的IP地址


cxfframe_log4j.properties

log4j.rootCategory=DEBUG,stdout
log4j.addivity.org.apache=true
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %l - %m%n

log4j.logger.cxfframe=DEBUG,cxfframe
log4j.appender.cxfframe=org.apache.log4j.RollingFileAppender
log4j.appender.cxfframe.File=./log/cxfframe.log
log4j.appender.cxfframe.Threshold=DEBUG
log4j.appender.cxfframe.MaxBackupIndex=5
log4j.appender.cxfframe.MaxFileSize=1KB
log4j.appender.cxfframe.layout=org.apache.log4j.PatternLayout
log4j.appender.cxfframe.layout.ConversionPattern=%d %p %l - %m%n

log4j.logger.sample=DEBUG,sample
log4j.appender.sample=org.apache.log4j.RollingFileAppender
log4j.appender.sample.File=./log/sample.log
log4j.appender.sample.Threshold=DEBUG
log4j.appender.sample.MaxBackupIndex=5
log4j.appender.sample.MaxFileSize=1KB
log4j.appender.sample.layout=org.apache.log4j.PatternLayout
log4j.appender.sample.layout.ConversionPattern=%d %p %l - %m%n
这个是平台和sdk私有模块的log4j配置,当添加一个sdk后,需要在这个里面配置对应的logger配置。

这个配置是根据不同模块打印不同的地址信息。注意看模块名以及输出路径

平台加载log4j配置的时候,加入了log4j的监听器,支持动态修改log4j配置文件。


Modules.xml

<?xml version="1.0" encoding="UTF-8" ?>

<!-- 配置模块SDK信息 -->
<modules>

	<!-- 模块名和class全路径 -->
	<!-- 注意,模块名必须与模块工程名(Linux模块名)完全一致 -->
	<module name="sample" class="com.module.sample.Sample" />
	<module name="gis" class="com.module.gis.GisServer" />

</modules>
这个是平台获取sdk主类的配置,每次添加sdk模块,都需要在这里加上对应的配置信息。

name 就是 sdk模块的名字,这个名字很重要,很多地方都要保持一直,比如说安装服务器后再modules目录下的目录名,以及客户端调用服务端传的模块名

class 就是 sdk模块的主类全路径


CommConstans.java

package com.cxfframe.server.common;

import com.cxfframe.server.util.CommonUtils;

/**
 * 常量
 *
 * @author CYX
 * @create 2017-05-24-21:41
 */
public class CommConstans {

    //判断相对路径根路径
    static {
        if (CommonUtils.isWindowsOS()) {
            SYSTEN_ROOT_PATH = "./";
        } else {
            SYSTEN_ROOT_PATH = "../";
        }
    }

    /**
     * 相对路径根路径
     * Windows(./) Linux(../)
     */
    public static String SYSTEN_ROOT_PATH;

    /**
     * CXFFrame配置文件路径
     */
    public static final String CXFFRAME_CONF_PATH = SYSTEN_ROOT_PATH + "conf/cxfframe_conf.properties";

    /**
     * CXFFrame_log4j配置文件路径
     */
    public static final String CXFFRAME_LOG4J_CONF_PATH = SYSTEN_ROOT_PATH + "conf/cxfframe_log4j.properties";

    /**
     * modules目录的路径
     */
    public static final String MODULES_DIR_PATH = SYSTEN_ROOT_PATH + "modules";

    /**
     * Modules.xml配置文件路径
     */
    public static final String MODULES_XML_PATH = SYSTEN_ROOT_PATH + "conf/Modules.xml";
}
这里配置的是成员变量,主要是平台配置文件的路径


ExceptionInfoConstans.java

package com.cxfframe.server.common;

/**
 * Exception错误信息
 *
 * @author CYX
 */
public class ExceptionInfoConstans {

    /**
     * moduleName和Params参数错误
     */
    public static final String MODULENAME_PARAMS_EXCEPTION = "[ErrorCode-01] Error information : Server receives the information , moduleName or params is null , please check it ";

    /**
     * moduleName找不到对应模块
     */
    public static final String MODULENAME_CLASS_EXCEPTION = "[ErrorCode-02] Error information : The server can not find the corresponding module";

    /**
     * 实例化模块错误
     */
    public static final String INSTANTIATE_MODULE_EXCEPTION = "[ErrorCode-03] Error information : Instantiate module error";

    /**
     * 服务端模块处理错误
     */
    public static final String SERVER_PROCESS_EXCEPTION = "[ErrorCode-04] Error information : Server module processing error";
}
这个配置的是平台/sdk处理异常后,返回给客户端的错误信息


KeyConstans.java

package com.cxfframe.server.common;

/**
 * 配置文件中的key常量
 *
 * @author CYX
 * @create 2017-05-24-22:15
 */
public class KeyConstans {

    public static final String CXFFRAME_PORT = "CXFFRAME_PORT";

    public static final String CXFFRAME_RELEASE_NAME = "CXFFRAME_RELEASE_NAME";


}
这里配置的是properties配置文件中的key,常量


QueryService.java

package com.cxfframe.server.inter;

import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebService;

/**
 * Created by CYX on 2017/5/24.
 */
@WebService
public interface QueryService {

    @WebMethod
    String queryServerInformation(@WebParam(name = "ModuleName") String moduleName, @WebParam(name = "params") String params);

}
CXF发布的接口,这个不多说,使用过CXF或者WebService都知道,不了解的先去看之前的webService系列文章


QueryServiceImpl.java

package com.cxfframe.server.impl;

import com.cxfframe.server.common.ExceptionInfoConstans;
import com.cxfframe.server.inter.QueryService;
import com.cxfframe.server.load.LoadConfig;
import com.cxfframe.server.module.ModuleFactory;
import com.cxfframe.server.module.ServiceBase;
import com.cxfframe.service.CXFFrameRelease;
import org.apache.cxf.common.util.StringUtils;
import org.apache.log4j.Logger;

/**
 * WebService接口实现
 *
 * @author CYX
 * @create 2017-05-24-21:15
 */
public class QueryServiceImpl implements QueryService {


    private final Logger logger = CXFFrameRelease.logger;


    public String queryServerInformation(String moduleName, String params) {

        // 参数为空,直接返回错误信息
        if (StringUtils.isEmpty(moduleName) & StringUtils.isEmpty(params)) {
            logger.info(ExceptionInfoConstans.MODULENAME_PARAMS_EXCEPTION);
            return ExceptionInfoConstans.MODULENAME_PARAMS_EXCEPTION;
        }

        // 根据模块名找class,找不到直接返回错误信息
        LoadConfig loadConfig = LoadConfig.getInstance();
        if (loadConfig.getModulesConfigWithInfomation().get(moduleName).isEmpty()) {
            logger.info("module name : " + moduleName + " can not find the corresponding module");
            return ExceptionInfoConstans.MODULENAME_CLASS_EXCEPTION;// moduleName找不到对应模块
        }


        logger.info("==================== The server begins processing ====================");
        logger.info("==================== The server begins processing ====================");


        logger.info("module name : " + moduleName + " , params : " + params);

        String responseResult = "";

        try {

            // 根据模块名获取模块实例,加载模块配置并初始化
            ServiceBase serviceBase = ModuleFactory.getModuleInstance(moduleName);

            //实例化模块失败,返回错误信息
            if (serviceBase == null) {
                logger.info(ExceptionInfoConstans.INSTANTIATE_MODULE_EXCEPTION);
                return ExceptionInfoConstans.INSTANTIATE_MODULE_EXCEPTION;
            }


            // 调用私有模块主方法
            responseResult = serviceBase.process(params);


        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            return ExceptionInfoConstans.SERVER_PROCESS_EXCEPTION;
        }

        logger.info("==================== The server is finished ====================");
        logger.info("==================== The server is finished ====================");

        return responseResult;
    }
}
CXF接口的实现。

在这个类中,会根据模块名,生成对应的模块实例,然后调用主方法,执行sdk业务,并返回指定数据


CXFFrameRelease.java

package com.cxfframe.service;

import com.cxfframe.server.impl.QueryServiceImpl;
import com.cxfframe.server.load.LoadConfig;
import org.apache.log4j.Logger;

import javax.xml.ws.Endpoint;

/**
 * CXFFrame发布主程序
 *
 * @author CYX
 * @create 2017-05-24-21:22
 */
public class CXFFrameRelease {

    public static final Logger logger = Logger.getLogger("cxfframe");

    public static void main(String[] args) {

        LoadConfig loadConfig = null;

        // 加载配置文件,出现异常,直接退出程序
        try {

            loadConfig = LoadConfig.getInstance();
            loadConfig.init();

        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            System.exit(1);
        }

        // 发布CXF服务(WebService)
        try {

            String address = "http://" + loadConfig.getCxfFrame_IP() + ":" + loadConfig.getCxfFrame_PORT() + "/" + loadConfig.getCxfFrame_ServiceName() + "?wsdl";

            // CXFFrame主方法
            Endpoint.publish(address, new QueryServiceImpl());

            logger.info("CXFFrame release is success , address : " + address);

        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }

    }

}
CXFFrame平台发布主方法


LoadConfig.java

package com.cxfframe.server.load;

import com.cxfframe.server.common.CommConstans;
import com.cxfframe.server.common.KeyConstans;
import com.cxfframe.service.CXFFrameRelease;
import org.apache.commons.io.FileUtils;
import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;

import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.net.InetAddress;
import java.util.HashMap;
import java.util.List;
import java.util.Properties;

/**
 * 加载配置
 *
 * @author CYX
 * @create 2017-05-24-21:39
 */
public class LoadConfig {

    private final Logger logger = CXFFrameRelease.logger;

    //单例
    private static class LoadConfigHolder {
        private static final LoadConfig INSTANCE = new LoadConfig();
    }

    public static final LoadConfig getInstance() {
        return LoadConfigHolder.INSTANCE;
    }


    private String cxfFrame_IP;
    private String cxfFrame_PORT;
    private String cxfFrame_ServiceName;

    /**
     * 模块名和class全路径的映射
     */
    private HashMap<String, String> moduleNameWithClass = new HashMap<String, String>(20);

    /**
     * 存放私有模块的配置信息
     * 模块名-(配置文件名-配置文件内容)
     */
    private HashMap<String, HashMap<String, String>> modulesConfigWithInfomation = new HashMap<String, HashMap<String, String>>(20);

    /**
     * CXFFrame初始化
     *
     * @throws Exception
     */
    public void init() throws Exception {

        // 加载logger
        loadLogger();

        // 加载配置文件
        loadCXFFrameCofig();

        // 加载所有模块的私有配置
        loadModulesCofig();

        // 加载modules.xml
        loadModulesXML();

    }

    /**
     * 加载logger 支持动态改变log4j配置(类似于热部署)
     *
     * @throws Exception
     */
    private void loadLogger() throws Exception {
        PropertyConfigurator.configure(CommConstans.CXFFRAME_LOG4J_CONF_PATH);
        PropertyConfigurator.configureAndWatch(CommConstans.CXFFRAME_LOG4J_CONF_PATH, 1000);
    }

    /**
     * 加载CXFFrame配置文件
     *
     * @throws Exception
     */
    private void loadCXFFrameCofig() throws Exception {
        Properties pro = new Properties();
        pro.load(new FileInputStream(new File(CommConstans.CXFFRAME_CONF_PATH)));

        // 默认获取本地IP
        cxfFrame_IP = InetAddress.getLocalHost().getHostAddress();
        cxfFrame_PORT = pro.getProperty(KeyConstans.CXFFRAME_PORT);
        cxfFrame_ServiceName = pro.getProperty(KeyConstans.CXFFRAME_RELEASE_NAME);

        logger.debug("cxfFrame_IP : " + cxfFrame_IP);
        logger.debug("cxfFrame_PORT : " + cxfFrame_PORT);
        logger.debug("cxfFrame_ServiceName : " + cxfFrame_ServiceName);

    }

    /**
     * 加载modules.xml
     *
     * @throws Exception
     */
    private void loadModulesXML() throws Exception {

        String modulesResult = FileUtils.readFileToString(new File(CommConstans.MODULES_XML_PATH), "UTF-8");

        // 解析modules.xml
        handleModulesXML(modulesResult);

    }

    /**
     * 解析modules.xml
     *
     * @param modulesResult
     * @throws Exception
     */
    private void handleModulesXML(String modulesResult) throws Exception {

        Document document = DocumentHelper.parseText(modulesResult);
        Element rootElement = document.getRootElement();

        // 获取modules节点下所有的module节点
        List<Element> modules = rootElement.elements("module");

        for (Element module : modules) {
            String moduleName = module.attributeValue("name");// 获取name的属性值
            String moduleClass = module.attributeValue("class");// 获取class的属性值

            moduleNameWithClass.put(moduleName, moduleClass);
        }

    }

    /**
     * 加载modules目录下所有模块的私有配置
     *
     * @throws Exception
     */
    private void loadModulesCofig() throws Exception {

        // modules目录下,所有的子模块
        File[] moduleDirs = new File(CommConstans.MODULES_DIR_PATH).listFiles(new FileFilter() {
            public boolean accept(File pathname) {
                return pathname.isDirectory();
            }
        });

        for (File moduleDir : moduleDirs) {

            // 加载单个私有模块的配置信息
            loadPrivatelyOwnedModuleConf(moduleDir);
        }

    }

    /**
     * 加载单个私有模块的配置
     */
    private void loadPrivatelyOwnedModuleConf(File moduleDir) throws Exception {

        String moduleName = moduleDir.getName();// 模块名

        // 获取私有模块conf目录下所有配置文件
        File[] configFiles = new File(moduleDir.getPath() + "/conf").listFiles(new FileFilter() {
            public boolean accept(File pathname) {
                return pathname.isFile();
            }
        });

        // 循环读取conf目录下的配置文件
        HashMap<String, String> configFileNameWithinfo = new HashMap<String, String>();

        if (null != configFiles) {

            for (File configFile : configFiles) {

                String configFileName = configFile.getName();// 文件名
                String configInformation = FileUtils.readFileToString(configFile, "UTF-8");// 文件内容

                // 文件名-文件内容,存入map
                configFileNameWithinfo.put(configFileName, configInformation);
            }

        } else {
            logger.info("module Name : " + moduleName + " , configFiles is null");
        }

        // 模块名-(配置文件名-配置文件内容)
        modulesConfigWithInfomation.put(moduleName, configFileNameWithinfo);

        logger.info("All modules private configuration" + modulesConfigWithInfomation);
    }

    public String getCxfFrame_IP() {
        return cxfFrame_IP;
    }

    public String getCxfFrame_PORT() {
        return cxfFrame_PORT;
    }

    public String getCxfFrame_ServiceName() {
        return cxfFrame_ServiceName;
    }

    public HashMap<String, String> getModuleNameWithClass() {
        return moduleNameWithClass;
    }

    public HashMap<String, HashMap<String, String>> getModulesConfigWithInfomation() {
        return modulesConfigWithInfomation;
    }
}
这个类是加载平台配置信息,以及SDK私有模块配置信息的。

上面代码注释写的已经很清楚了。


ModuleFactory.java

package com.cxfframe.server.module;

import com.cxfframe.server.load.LoadConfig;
import com.cxfframe.service.CXFFrameRelease;
import org.apache.cxf.common.util.StringUtils;
import org.apache.log4j.Logger;

import java.util.HashMap;

/**
 * 模块工厂,负责创建模块对象
 *
 * @author CYX
 * @create 2017-05-25-11:00
 */
public class ModuleFactory {

    private static final Logger logger = CXFFrameRelease.logger;

    /**
     * 获取模块实例
     *
     * @param modeulName
     * @return
     */
    public static ServiceBase getModuleInstance(String moduleName) {

        LoadConfig loadConfig = LoadConfig.getInstance();

        ServiceBase serviceBase = null;

        // 实例化模块
        Object obj = null;
        try {
            // 获取模块对应的class路径
            String moduleClass = loadConfig.getModuleNameWithClass().get(moduleName);
            logger.info("module : " + moduleName + " , class : " + moduleClass);
            if (StringUtils.isEmpty(moduleClass)) {
                logger.info("module : " + moduleName + " , class is null");
                return null;
            }

            // 通过反射获取模块实例
            Class exampleClass = Class.forName(moduleClass);
            obj = exampleClass.newInstance();

            serviceBase = (ServiceBase) obj;

            // 加载模块并初始化

            // 根据模块名,取出模块对应的配置文件
            HashMap<String, String> moduleConfigNameWithInfo = loadConfig.getModulesConfigWithInfomation().get(moduleName);

            // 私有模块加载配置
            serviceBase.loadConfig(moduleConfigNameWithInfo);

            // 私有模块初始化
            serviceBase.init();

            logger.info("===== Load Configuration Initialize the private module is complete =====");

        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            return null;
        }

        return serviceBase;
    }

}
这个类是根据模块名声称对应模块实例的主要方法


ServiceBase.java

package com.cxfframe.server.module;

import java.util.HashMap;

/**
 * 基类
 *
 * @author CYX
 * @create 2017-05-25-11:01
 */
public abstract class ServiceBase {

    /**
     * CXFFrame将模块对应的配置文件,传给对应私有模块
     *
     * @param moduleConf
     * @throws Exception
     */
    public abstract void loadConfig(HashMap<String, String> moduleConf) throws Exception;

    /**
     * 初始化
     *
     * @throws Exception
     */
    public abstract void init() throws Exception;

    /**
     * 模块主处理方法(子模块返回建议不要返回null)
     *
     * @param information
     * @return
     * @throws Exception
     */
    public abstract String process(String information) throws Exception;


}
这个是给SDK私有模块主类继承用的


CommonUtils.java

package com.cxfframe.server.util;

/**
 * 公共方法
 *
 * @author CYX
 * @create 2017-05-24-21:43
 */
public class CommonUtils {

    /**
     * 判断是否是windows操作系统
     *
     * @return String
     */
    public static boolean isWindowsOS() {
        boolean isWindowsOS = false;
        String osName = System.getProperty("os.name");
        if (osName.toLowerCase().indexOf("windows") > -1) {
            isWindowsOS = true;
        }
        return isWindowsOS;
    }

}
公共方法


pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<groupId>com</groupId>
	<artifactId>CXF_Frame</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>jar</packaging>

	<name>CXF_Frame</name>
	<url>http://maven.apache.org</url>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<cxf.version>3.1.11</cxf.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>3.8.1</version>
			<scope>test</scope>
		</dependency>

		<dependency>
			<groupId>org.apache.cxf</groupId>
			<artifactId>cxf-rt-frontend-jaxws</artifactId>
			<version>${cxf.version}</version>
		</dependency>
		<dependency>
			<groupId>org.apache.cxf</groupId>
			<artifactId>cxf-rt-transports-http</artifactId>
			<version>${cxf.version}</version>
		</dependency>
		<!-- Jetty is needed if you're are not using the CXFServlet -->
		<dependency>
			<groupId>org.apache.cxf</groupId>
			<artifactId>cxf-rt-transports-http-jetty</artifactId>
			<version>${cxf.version}</version>
		</dependency>

		<dependency>
			<groupId>log4j</groupId>
			<artifactId>log4j</artifactId>
			<version>1.2.17</version>
		</dependency>

		<dependency>
			<groupId>dom4j</groupId>
			<artifactId>dom4j</artifactId>
			<version>1.6.1</version>
		</dependency>

		<dependency>
			<groupId>commons-io</groupId>
			<artifactId>commons-io</artifactId>
			<version>2.5</version>
		</dependency>

		<dependency>
			<groupId>commons-lang</groupId>
			<artifactId>commons-lang</artifactId>
			<version>2.6</version>
		</dependency>

		<dependency>
			<groupId>commons-collections</groupId>
			<artifactId>commons-collections</artifactId>
			<version>3.2.2</version>
		</dependency>

	</dependencies>
	
	<build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-dependency-plugin</artifactId>
                <executions>
                    <execution>
                        <id>copy</id>
                        <phase>package</phase>
                        <goals>
                            <goal>copy-dependencies</goal>
                        </goals>
                        <configuration>
                            <outputDirectory>${project.build.directory}/lib</outputDirectory>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
	
</project>

这里平台的代码就讲解到这里...


这里贴上服务器上CXFFrame的结构图




SDK开发样例




在上面的安装包中,有详细的开发文档,欢迎互相讨论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值