Browse Source

动态加载路由代码调试

lingfeng 8 years ago
parent
commit
8b0293ed7f
20 changed files with 544 additions and 285 deletions
  1. 9 4
      Hos-Framework/src/main/java/com/yihu/ehr/framework/util/operator/ClassFileUtil.java
  2. 36 11
      hos-broker/pom.xml
  3. 3 10
      hos-broker/src/main/java/com/yihu/hos/HosBrokerApplication.java
  4. 67 0
      hos-broker/src/main/java/com/yihu/hos/common/classLoader/DynamicClassLoader.java
  5. 1 1
      hos-broker/src/main/java/com/yihu/hos/configuration/ApplicationConfiguration.java
  6. 1 1
      hos-broker/src/main/java/com/yihu/hos/configuration/ArbiterConfiguration.java
  7. 13 0
      hos-broker/src/main/java/com/yihu/hos/common/constants/Constant.java
  8. 59 0
      hos-broker/src/main/java/com/yihu/hos/common/dao/BrokerDao.java
  9. 124 0
      hos-broker/src/main/java/com/yihu/hos/common/listener/ApplicationStartListener.java
  10. 1 1
      hos-broker/src/main/java/com/yihu/hos/listener/HosServiceListener.java
  11. 8 2
      hos-broker/src/main/java/com/yihu/hos/controllers/ESBCamelController.java
  12. 0 23
      hos-broker/src/main/java/com/yihu/hos/dao/BrokerDao.java
  13. 0 173
      hos-broker/src/main/java/com/yihu/hos/listener/ApplicationStartListener.java
  14. 0 16
      hos-broker/src/main/java/com/yihu/hos/model/CamelContextQueue.java
  15. 17 0
      hos-broker/src/main/java/com/yihu/hos/models/SystemCamelContext.java
  16. 2 2
      hos-broker/src/main/java/com/yihu/hos/model/SystemPathMapping.java
  17. 72 0
      hos-broker/src/main/java/com/yihu/hos/models/SystemServiceFlow.java
  18. 61 0
      hos-broker/src/main/java/com/yihu/hos/models/SystemServiceFlowClass.java
  19. 2 2
      hos-broker/src/main/java/com/yihu/hos/services/BrokerServerService.java
  20. 68 39
      hos-broker/src/main/java/com/yihu/hos/services/ESBCamelService.java

+ 9 - 4
Hos-Framework/src/main/java/com/yihu/ehr/framework/util/operator/ClassFileUtil.java

@ -25,17 +25,22 @@ public class ClassFileUtil {
     * @param className class文件的类名信息
     * @param path class文件的路径
     */
    public static void createClassfile(URL systemRootURL , String packageName, String className, String path) {
    public static void createClassfile(URL systemRootURL, String packageName, String className, String path) {
        // 开始输出文件内容
        try {
            FileInputStream in = new FileInputStream(new File(path));
            String classPath = systemRootURL.getPath() + "/" + packageName + "/" + className;
            File packageFile = new File(systemRootURL.getPath() + "/" + packageName);
            if (!packageFile.exists()) {
                packageFile.mkdirs();
            }
            String classPath = packageFile + "/" + className + ".class";
            File file = new File(classPath);
            if (file.isFile() && file.exists()) {
                return;
            } else {
                file.createNewFile();
            }
            FileOutputStream out = new FileOutputStream(classPath);
            int n = 0;// 每次读取的字节长度
            byte[] bb = new byte[1024];// 存储每次读取的内容
@ -54,7 +59,7 @@ public class ClassFileUtil {
        // 开始输出文件内容
        try {
            FileInputStream in = new FileInputStream(new File(path));
            String classPath = systemRootURL.getPath() + "/" + packageName + "/" + className;
            String classPath = systemRootURL.getPath() + "/" + packageName + "/" + className + ".class";
            File file = new File(classPath);
            if (file.isFile() && file.exists()) {
                file.delete();
@ -78,7 +83,7 @@ public class ClassFileUtil {
    public static void deleteClassfile(URL systemRootURL , String packageName, String className) {
        // 开始输出文件内容
        try {
            String classPath = systemRootURL.getPath() + "/" + packageName + "/" + className;
            String classPath = systemRootURL.getPath() + "/" + packageName + "/" + className + ".class";
            File file = new File(classPath);
            if (file.isFile() && file.exists()) {
                file.delete();

+ 36 - 11
hos-broker/pom.xml

@ -61,12 +61,42 @@
			<artifactId>camel-spring-boot</artifactId>
			<version>2.17.1</version> <!-- use the same version as your Camel core version -->
		</dependency>
		<!--<dependency>-->
			<!--<groupId>org.apache.camel</groupId>-->
			<!--<artifactId>camel-stream</artifactId>-->
			<!--<version>2.17.1</version> &lt;!&ndash; use the same version as your Camel core version &ndash;&gt;-->
		<!--</dependency>-->
		<dependency>
			<groupId>org.apache.camel</groupId>
			<artifactId>camel-http</artifactId>
			<version>2.17.1</version>
		</dependency>
		<dependency>
			<groupId>org.apache.camel</groupId>
			<artifactId>camel-cxf</artifactId>
			<version>2.17.1</version>
		</dependency>
		<dependency>
			<groupId>org.apache.camel</groupId>
			<artifactId>camel-quartz</artifactId>
			<version>2.17.1</version>
		</dependency>
		<dependency>
			<groupId>org.apache.camel</groupId>
			<artifactId>camel-quartz2</artifactId>
			<version>2.17.1</version>
		</dependency>
		<dependency>
			<groupId>org.apache.camel</groupId>
			<artifactId>camel-xmljson</artifactId>
			<version>2.17.1</version>
			<!-- Use the same version as camel-core, but remember that this component is only available from 2.10 onwards -->
		</dependency>
		<dependency>
			<groupId>xom</groupId>
			<artifactId>xom</artifactId>
			<version>1.2.5</version>
		</dependency>
		<dependency>
			<groupId>org.apache.camel</groupId>
			<artifactId>camel-stream</artifactId>
			<version>2.17.1</version>
		</dependency>
		<dependency>
			<groupId>org.apache.camel</groupId>
@ -80,11 +110,6 @@
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
		<!--<dependency>-->
			<!--<groupId>org.apache.camel</groupId>-->
			<!--<artifactId>camel-test</artifactId>-->
			<!--<scope>test</scope>-->
		<!--</dependency>-->
		<dependency>
			<groupId>com.yihu.hos.resource</groupId>
			<artifactId>Hos-Framework</artifactId>

+ 3 - 10
hos-broker/src/main/java/com/yihu/hos/HosBrokerApplication.java

@ -1,23 +1,16 @@
package com.yihu.hos;
import com.yihu.hos.listener.ApplicationStartListener;
import com.yihu.hos.common.listener.ApplicationStartListener;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.context.web.SpringBootServletInitializer;
@SpringBootApplication
public class HosBrokerApplication extends SpringBootServletInitializer {
    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(HosBrokerApplication.class);
    }
public class HosBrokerApplication {
    public static void main(String[] args) {
        SpringApplication app = new SpringApplication(HosBrokerApplication.class);
        app.run(args);
        app.addListeners(new ApplicationStartListener());
        app.run(args);
    }
}

+ 67 - 0
hos-broker/src/main/java/com/yihu/hos/common/classLoader/DynamicClassLoader.java

@ -0,0 +1,67 @@
package com.yihu.hos.common.classLoader;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
public class DynamicClassLoader extends ClassLoader {
    public DynamicClassLoader(ClassLoader parent) {
        super(parent);
    }
    @SuppressWarnings("unchecked")
    public Class loadClass(String classPath, String className)
            throws ClassNotFoundException {
        try {
            String url = classPathParser(classPath)
                    + classNameParser(className);
            URL myUrl = new URL(url);
            URLConnection connection = myUrl.openConnection();
            InputStream input = connection.getInputStream();
            ByteArrayOutputStream buffer = new ByteArrayOutputStream();
            int data = input.read();
            while (data != -1) {
                buffer.write(data);
                data = input.read();
            }
            input.close();
            byte[] classData = buffer.toByteArray();
            return defineClass(noSuffix(className), classData, 0,
                    classData.length);
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
    private String pathParser(String path) {
        return path.replaceAll("\\\\", "/");
    }
    private String classPathParser(String path) {
        String classPath = pathParser(path);
        if (!classPath.startsWith("file:")) {
            classPath = "file:" + classPath;
        }
        if (!classPath.endsWith("/")) {
            classPath = classPath + "/";
        }
        return classPath;
    }
    private String classNameParser(String className) {
        return className.substring(0, className.lastIndexOf(".")).replaceAll(
                "\\.", "/")
                + className.substring(className.lastIndexOf("."));
    }
    private String noSuffix(String className) {
        return className.substring(0, className.lastIndexOf("."));
    }
}

+ 1 - 1
hos-broker/src/main/java/com/yihu/hos/configuration/ApplicationConfiguration.java

@ -1,4 +1,4 @@
package com.yihu.hos.configuration;
package com.yihu.hos.common.configuration;
import org.springframework.boot.context.embedded.EmbeddedServletContainerInitializedEvent;
import org.springframework.context.ApplicationListener;

+ 1 - 1
hos-broker/src/main/java/com/yihu/hos/configuration/ArbiterConfiguration.java

@ -1,4 +1,4 @@
package com.yihu.hos.configuration;
package com.yihu.hos.common.configuration;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;

+ 13 - 0
hos-broker/src/main/java/com/yihu/hos/common/constants/Constant.java

@ -0,0 +1,13 @@
package com.yihu.hos.common.constants;
/**
 * Created by Administrator on 2016/4/13.
 */
public class Constant {
    public static String CLASS ="class";
    public static String DOT =".";
    public static String EMPTY ="";
}

+ 59 - 0
hos-broker/src/main/java/com/yihu/hos/common/dao/BrokerDao.java

@ -0,0 +1,59 @@
package com.yihu.hos.common.dao;
import com.yihu.hos.models.SystemServiceFlow;
import com.yihu.hos.models.SystemServiceFlowClass;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
import java.util.*;
@Repository("BrokerDao")
public class BrokerDao {
    public static final String BEAN_ID = "BrokerDao";
    @Autowired
    private JdbcTemplate jdbcTemplate;
    public List<SystemServiceFlow> getSystemServiceFlowList() throws Exception {
        List<SystemServiceFlow> systemServiceFlowList = new ArrayList<SystemServiceFlow>();;
        String sql = "select * from system_service_flow";
        List list = jdbcTemplate.queryForList(sql);
        Iterator iterator = list.iterator();
        SystemServiceFlow systemServiceFlow = null;
        while (iterator.hasNext()) {
            Map map = (Map) iterator.next();
            systemServiceFlow = new SystemServiceFlow();
            systemServiceFlow.setId((Integer) map.get("id"));
            systemServiceFlow.setCode((String) map.get("code"));
            systemServiceFlow.setName((String) map.get("name"));
            systemServiceFlow.setPath((String) map.get("path"));
            systemServiceFlow.setChart((String) map.get("chart"));
            systemServiceFlow.setValid((Integer) map.get("valid"));
            systemServiceFlow.setCreateDate((Date) map.get("create_date"));
            systemServiceFlowList.add(systemServiceFlow);
        }
        return systemServiceFlowList;
    }
    public List<SystemServiceFlowClass> getSystemServiceFlowClassList() throws Exception {
        List<SystemServiceFlowClass> systemServiceFlowClassList = new ArrayList<SystemServiceFlowClass>();;
        String sql = "select * from system_service_flow_class";
        List list = jdbcTemplate.queryForList(sql);
        Iterator iterator = list.iterator();
        SystemServiceFlowClass systemServiceFlowClass = null;
        while (iterator.hasNext()) {
            Map map = (Map) iterator.next();
            systemServiceFlowClass = new SystemServiceFlowClass();
            systemServiceFlowClass.setId((Integer) map.get("id"));
            systemServiceFlowClass.setClassName((String) map.get("class_name"));
            systemServiceFlowClass.setPackageName((String) map.get("package_name"));
            systemServiceFlowClass.setClassPath((String) map.get("class_path"));
            systemServiceFlowClass.setFlowId((Integer) map.get("flow_id"));
            systemServiceFlowClass.setType((String) map.get("type"));
            systemServiceFlowClassList.add(systemServiceFlowClass);
        }
        return systemServiceFlowClassList;
    }
}

+ 124 - 0
hos-broker/src/main/java/com/yihu/hos/common/listener/ApplicationStartListener.java

@ -0,0 +1,124 @@
package com.yihu.hos.common.listener;
import com.yihu.ehr.framework.util.operator.ClassFileUtil;
import com.yihu.ehr.framework.util.operator.CollectionUtil;
import com.yihu.hos.common.dao.BrokerDao;
import com.yihu.hos.models.SystemCamelContext;
import com.yihu.hos.models.SystemPathMapping;
import com.yihu.hos.models.SystemServiceFlow;
import com.yihu.hos.models.SystemServiceFlowClass;
import org.apache.camel.builder.RouteBuilder;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import java.io.File;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class ApplicationStartListener implements ApplicationListener<ContextRefreshedEvent> {
    private static Logger logger = LogManager.getLogger();
    /**
     * 这是一个固定的存储class文件的根路径
     * 正式系统中,这个值可来自于系统的配置文件
     */
    private void camelRouteStart(ContextRefreshedEvent contextRefreshedEvent) throws Exception {
        BrokerDao brokerDao = (BrokerDao) contextRefreshedEvent.getApplicationContext().getBean(BrokerDao.BEAN_ID);
        List<SystemServiceFlow> systemServiceFlowList = brokerDao.getSystemServiceFlowList();
        List<SystemServiceFlowClass> systemServiceFlowClassList = brokerDao.getSystemServiceFlowClassList();
        Map<String, List<SystemServiceFlowClass>> systemServiceFlowClassGroupMap = new HashMap<>();
        for (SystemServiceFlowClass systemServiceFlowClass : systemServiceFlowClassList) {
            Integer flowId = systemServiceFlowClass.getFlowId();
            String type = systemServiceFlowClass.getType();
            if (systemServiceFlowClassGroupMap.containsKey(flowId)) {
                List<SystemServiceFlowClass> classList = systemServiceFlowClassGroupMap.get(type + flowId);
                classList.add(systemServiceFlowClass);
                systemServiceFlowClassGroupMap.put(type + flowId.toString(), classList);
            } else {
                List<SystemServiceFlowClass> classList = new ArrayList<>();
                classList.add(systemServiceFlowClass);
                systemServiceFlowClassGroupMap.put(type + flowId.toString(), classList);
            }
        }
        List<File> systemClassRootPaths = new ArrayList<>();
        List<RouteBuilder> alreadyRouteBuilders = new ArrayList<>();
        for (SystemServiceFlow systemServiceFlow : systemServiceFlowList) {
            Integer flowId = systemServiceFlow.getId();
            String code = systemServiceFlow.getCode();
            // 这是system业务系统在本地存储class的根目录
            File systemClassRootPath = new File(ClassLoader.getSystemResource("").getPath() + "/" + code);
            if (!systemClassRootPath.exists()) {
                systemClassRootPath.mkdirs();
            }
            // 记录到工具类中,以便其它线程需要时进行取用
            SystemPathMapping.getSystemRootPathMapping().put(code, systemClassRootPath.toURI().toURL());
            if (!systemClassRootPaths.contains(systemClassRootPath)) {
                systemClassRootPaths.add(systemClassRootPath);
            }
            List<SystemServiceFlowClass> processesClassList = systemServiceFlowClassGroupMap.get("processor" + flowId);
            List<SystemServiceFlowClass> routesClassList = systemServiceFlowClassGroupMap.get("route" + flowId);
            // 创建processor文件
            if (!CollectionUtil.isEmpty(processesClassList)) {
                for (SystemServiceFlowClass processesClass : processesClassList) {
                    String className = processesClass.getClassName();
                    String packageName = processesClass.getPackageName();
                    String classPath = processesClass.getClassPath();
                    // 创建文件
                    ClassFileUtil.createClassfile(systemClassRootPath.toURI().toURL(), packageName, className, classPath);
                }
            }
            if (!CollectionUtil.isEmpty(routesClassList)) {
                // 创建route文件
                for (SystemServiceFlowClass routesClass : routesClassList) {
                    String className = routesClass.getClassName();
                    String packageName = routesClass.getPackageName();
                    String classPath = routesClass.getClassPath();
                    // 创建文件
                    ClassFileUtil.createClassfile(systemClassRootPath.toURI().toURL(), packageName, className, classPath);
                    RouteBuilder routeBuilder = (RouteBuilder)Class.forName(code + "." + packageName + "." + className).newInstance();
                    alreadyRouteBuilders.add(routeBuilder);
                }
            }
        }
        // 4、=============
        // 首先启动Apache Camel服务
        SystemCamelContext.getDefaultCamelContext().start();
        logger.info("Apache Camel Context 启动完成......");
        // 加载和设置ClassLoader
        List<URL> URLs = new ArrayList<>();
        for (File systemClassRootPath : systemClassRootPaths) {
            URLs.add(systemClassRootPath.toURI().toURL());
        }
        ClassLoader currentClassLoader = Thread.currentThread().getContextClassLoader();
        ClassLoader camelESBClassLoader = new URLClassLoader(URLs.toArray(new URL[]{}) , currentClassLoader);
        Thread.currentThread().setContextClassLoader(camelESBClassLoader);
        SystemCamelContext.getDefaultCamelContext().setApplicationContextClassLoader(camelESBClassLoader);
        // 然后就可以进行RouteBuilder的加载
        for (RouteBuilder routeBuilder : alreadyRouteBuilders) {
            try {
                SystemCamelContext.getDefaultCamelContext().addRoutes(routeBuilder);
            } catch(Exception e) {
                logger.warn(e.getMessage() , e);
            }
        }
    }
    @Override
    public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
        try {
            camelRouteStart(contextRefreshedEvent);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

+ 1 - 1
hos-broker/src/main/java/com/yihu/hos/listener/HosServiceListener.java

@ -1,4 +1,4 @@
package com.yihu.hos.listener;
package com.yihu.hos.common.listener;
/**
 * @created Airhead 2016/8/2.

+ 8 - 2
hos-broker/src/main/java/com/yihu/hos/controllers/ESBCamelController.java

@ -21,6 +21,13 @@ public class ESBCamelController {
    @Resource(name= ESBCamelService.BEAN_ID)
    ESBCamelService esbCamelService;
    @RequestMapping(value = "/test", produces = "application/json;charset=UTF-8", method = RequestMethod.POST)
    @ResponseBody
    @ApiOperation(value = "新增Processor处理器", produces = "application/json", notes = "当外界组件通知一个新的processor处理器被定义时,该事件被触发")
    public Result test() {
      return Result.success("test");
    }
    @RequestMapping(value = "/processor", produces = "application/json;charset=UTF-8", method = RequestMethod.POST)
    @ResponseBody
    @ApiOperation(value = "新增Processor处理器", produces = "application/json", notes = "当外界组件通知一个新的processor处理器被定义时,该事件被触发")
@ -33,8 +40,7 @@ public class ESBCamelController {
            @RequestParam(value = "className") String className,
            @ApiParam(name = "path", value = "class文件路径", required = true)
            @RequestParam(value = "path") String path) {
        return Result.success("成功!");
//        return esbCamelService.onProcessorAdded(serviceFlow, packageName, className, path);
        return esbCamelService.onProcessorAdded(serviceFlow, packageName, className, path);
    }
    @RequestMapping(value = "/processor", produces = "application/json;charset=UTF-8", method = RequestMethod.PUT)

+ 0 - 23
hos-broker/src/main/java/com/yihu/hos/dao/BrokerDao.java

@ -1,23 +0,0 @@
package com.yihu.hos.dao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
import java.util.List;
import java.util.Map;
@Repository("BrokerDao")
public class BrokerDao {
    public static final String BEAN_ID = "BrokerDao";
    @Autowired
    private JdbcTemplate jdbcTemplate;
    public List<Map<String, Object>> getSystemServiceFlowList() throws Exception {
        return jdbcTemplate.queryForList("select * from system_service_flow");
    }
    public List<Map<String, Object>> getSystemServiceFlowClassList() throws Exception {
        return jdbcTemplate.queryForList("select * from system_service_flow_class");
    }
}

+ 0 - 173
hos-broker/src/main/java/com/yihu/hos/listener/ApplicationStartListener.java

@ -1,173 +0,0 @@
package com.yihu.hos.listener;
import com.yihu.ehr.framework.util.operator.ClassFileUtil;
import com.yihu.hos.dao.BrokerDao;
import com.yihu.hos.model.CamelContextQueue;
import com.yihu.hos.model.SystemPathMapping;
import org.apache.camel.CamelContext;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.impl.DefaultCamelContext;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Repository;
import javax.annotation.Resource;
import java.io.File;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.SynchronousQueue;
/**
 * 项目启动执行
 * add by hzp at 2016-01-25
 */
@Repository("ApplicationStartListener")
public class ApplicationStartListener implements ApplicationListener {
    public static final String BEAN_ID = "ApplicationStartListener";
    @Resource(name = BrokerDao.BEAN_ID)
    BrokerDao brokerDao;
    private static Logger logger = LogManager.getLogger();
    /**
     * 这是一个固定的存储class文件的根路径
     * 正式系统中,这个值可来自于系统的配置文件
     */
    private static final String CLASSROOTPATH = "D:/testCamelRoot";
    private void camelRouteStart() throws Exception {
         /*
         * 启动顺序为:
         *
         * 1、首先使用Apache Curator组件进行zookeeper服务端连接,
         *
         * 2、通过Apache Curator组件查询目前已有的业务系统ID信息,
         * 以便依据这些业务系统ID,建立本地ClassLoader的根路径(当然,有就不需要创建了)
         * 并且注册Apache Curator封装层的监听。
         *
         * 3、检查第2步得到的业务系统下,已经存在的processor处理器定义和已有的route定义
         * 以便生成class信息。
         *
         * 4、启动Apache Camel服务,将第三步那些route定义进行动态加载
         *
         * 5、经过以上步骤,整个启动过程完成了。现在主线程需要一直等待从SynchronousQueue队列发来的动态加载请求了。
         * */
        // 1、===============
        // 连接到zookeeper
//        CuratorFramework zkClient = CuratorFrameworkFactory.newClient("192.168.61.140:2181", 30000, 30000, new RetryNTimes(50, 3000));
//        zkClient.start();
//        BootStartup.LOGGER.info("完成zookeeper服务端的连接工作!");
        // 2、===============
        // 取得已存在的系统
//        List<String> systemNames = zkClient.getChildren().forPath("/");
        List<Map<String, Object>> systemServiceFlowList = brokerDao.getSystemServiceFlowList();
        List<Map<String, Object>> systemServiceFlowClassList = brokerDao.getSystemServiceFlowClassList();
        Map<String, List<Map<String, Object>>> systemServiceFlowClassGroupMap = new HashMap<>();
        for (Map<String, Object> systemServiceFlowClassMap : systemServiceFlowClassList) {
            Integer flowId = (Integer) systemServiceFlowClassMap.get("flow_id");
            if (systemServiceFlowClassGroupMap.containsKey(flowId)) {
                List<Map<String, Object>> classList = systemServiceFlowClassGroupMap.get(flowId);
                classList.add(systemServiceFlowClassMap);
                String type = (String) systemServiceFlowClassMap.get("type");
                systemServiceFlowClassGroupMap.put(type + flowId.toString()  , classList);
            } else {
                List<Map<String, Object>> classList = new ArrayList<>();
                classList.add(systemServiceFlowClassMap);
                String type = (String) systemServiceFlowClassMap.get("type");
                systemServiceFlowClassGroupMap.put(type + flowId.toString()  , classList);
            }
        }
        List<File> systemClassRootPaths = new ArrayList<>();
        List<RouteBuilder> alreadyRouteBuilders = new ArrayList<>();
        for (Map<String, Object> systemNameMap : systemServiceFlowList) {
            Integer flowId = (Integer) systemNameMap.get("id");
            String code = (String) systemNameMap.get("code");
            // 这是system业务系统在本地存储class的根目录
            File systemClassRootPath = new File(CLASSROOTPATH + "/" + code);
            if (!systemClassRootPath.exists()) {
                systemClassRootPath.mkdirs();
            }
            Map<String, URL> systemRootPathMapping = SystemPathMapping.getSystemRootPathMapping();
            // 记录到工具类中,以便其它线程需要时进行取用
            systemRootPathMapping.put(code, systemClassRootPath.toURI().toURL());
            if (!systemClassRootPaths.contains(systemClassRootPath)) {
                systemClassRootPaths.add(systemClassRootPath);
            }
            List<Map<String, Object>> processesClassList = systemServiceFlowClassGroupMap.get("processor" + flowId);
            List<Map<String, Object>> routesClassList = systemServiceFlowClassGroupMap.get("route" + flowId);
            // 创建processor文件
            for (Map<String, Object> processesClass : processesClassList) {
                String className = (String) processesClass.get("name");
                String packageName = (String) processesClass.get("package");
                String classPath = (String) processesClass.get("path");
                // 创建文件
                ClassFileUtil.createClassfile(systemClassRootPath.toURI().toURL(), packageName, className, classPath);
            }
            // 创建route文件
            for (Map<String, Object> routesClass : routesClassList) {
                String className = (String) routesClass.get("name");
                String packageName = (String) routesClass.get("package");
                String classPath = (String) routesClass.get("path");
                // 创建文件
                ClassFileUtil.createClassfile(systemClassRootPath.toURI().toURL(), packageName, className, classPath);
                RouteBuilder routeBuilder = (RouteBuilder)Class.forName(packageName + "." + className).newInstance();
                alreadyRouteBuilders.add(routeBuilder);
            }
        }
        // 4、=============
        // 首先启动Apache Camel服务
        CamelContext camelContext = new DefaultCamelContext();
        camelContext.start();
        logger.info("Apache Camel Context 启动完成......");
        // 加载和设置ClassLoader
        List<URL> URLs = new ArrayList<>();
        for (File systemClassRootPath : systemClassRootPaths) {
            URLs.add(systemClassRootPath.toURI().toURL());
        }
        ClassLoader currentClassLoader = Thread.currentThread().getContextClassLoader();
        ClassLoader camelESBClassLoader = new URLClassLoader(URLs.toArray(new URL[]{}) , currentClassLoader);
        Thread.currentThread().setContextClassLoader(camelESBClassLoader);
        camelContext.setApplicationContextClassLoader(camelESBClassLoader);
        // 然后就可以进行RouteBuilder的加载
        for (RouteBuilder routeBuilder : alreadyRouteBuilders) {
            try {
                camelContext.addRoutes(routeBuilder);
            } catch(Exception e) {
                logger.warn(e.getMessage() , e);
            }
        }
        // 5、=============
        // 开始监控CamelContext动态操作队列
        SynchronousQueue<String> camelContextOperateQueue = CamelContextQueue.getCamelCamelContextQueue();
        String mustLoadedClassName = null;
        // 如果没有收到其它线程的加载请求,主线程将停止在这里
        while((mustLoadedClassName = camelContextOperateQueue.take()) != null) {
            Class<RouteBuilder> routeBuilderClass = (Class<RouteBuilder>)camelESBClassLoader.loadClass(mustLoadedClassName);
            if(routeBuilderClass != null) {
                RouteBuilder routeBuilder = routeBuilderClass.newInstance();
                camelContext.addRoutes(routeBuilder);
            }
        }
    }
    @Override
    public void onApplicationEvent(ApplicationEvent applicationEvent) {
        try {
            camelRouteStart();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

+ 0 - 16
hos-broker/src/main/java/com/yihu/hos/model/CamelContextQueue.java

@ -1,16 +0,0 @@
package com.yihu.hos.model;
import java.util.concurrent.SynchronousQueue;
/**
 * Created by lingfeng on 2016/8/4.
 */
public class CamelContextQueue {
    private static SynchronousQueue<String> camelContextOperateQueue;
    public static SynchronousQueue<String> getCamelCamelContextQueue() {
        if (camelContextOperateQueue == null) {
            camelContextOperateQueue = new SynchronousQueue<>(true);
        }
        return camelContextOperateQueue;
    }
}

+ 17 - 0
hos-broker/src/main/java/com/yihu/hos/models/SystemCamelContext.java

@ -0,0 +1,17 @@
package com.yihu.hos.models;
import org.apache.camel.CamelContext;
import org.apache.camel.impl.DefaultCamelContext;
/**
 * Created by lingfeng on 2016/8/9.
 */
public class SystemCamelContext {
    private static CamelContext defaultCamelContext;
    public static CamelContext getDefaultCamelContext() {
        if (defaultCamelContext == null) {
            defaultCamelContext = new DefaultCamelContext();
        }
        return defaultCamelContext;
    }
}

+ 2 - 2
hos-broker/src/main/java/com/yihu/hos/model/SystemPathMapping.java

@ -1,4 +1,4 @@
package com.yihu.hos.model;
package com.yihu.hos.models;
import java.net.URL;
import java.util.HashMap;
@ -8,7 +8,7 @@ import java.util.Map;
 * Created by lingfeng on 2016/8/4.
 */
public class SystemPathMapping {
    private static Map<String, URL> systemRootPathMapping ;
    private static Map<String, URL> systemRootPathMapping;
    public static Map<String, URL> getSystemRootPathMapping() {
        if (systemRootPathMapping == null) {
            systemRootPathMapping = new HashMap<>();

+ 72 - 0
hos-broker/src/main/java/com/yihu/hos/models/SystemServiceFlow.java

@ -0,0 +1,72 @@
package com.yihu.hos.models;
import java.util.Date;
/**
 * Created by lingfeng on 2016/8/8.
 */
public class SystemServiceFlow {
    Integer id;
    String code;
    String name;
    String path;
    String chart;
    Integer valid;
    Date createDate;
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getCode() {
        return code;
    }
    public void setCode(String code) {
        this.code = code;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getPath() {
        return path;
    }
    public void setPath(String path) {
        this.path = path;
    }
    public String getChart() {
        return chart;
    }
    public void setChart(String chart) {
        this.chart = chart;
    }
    public Integer getValid() {
        return valid;
    }
    public void setValid(Integer valid) {
        this.valid = valid;
    }
    public Date getCreateDate() {
        return createDate;
    }
    public void setCreateDate(Date createDate) {
        this.createDate = createDate;
    }
}

+ 61 - 0
hos-broker/src/main/java/com/yihu/hos/models/SystemServiceFlowClass.java

@ -0,0 +1,61 @@
package com.yihu.hos.models;
/**
 * Created by lingfeng on 2016/8/8.
 */
public class SystemServiceFlowClass {
    Integer id;
    String className;
    String packageName;
    String classPath;
    Integer flowId;
    String type;
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getClassName() {
        return className;
    }
    public void setClassName(String className) {
        this.className = className;
    }
    public String getPackageName() {
        return packageName;
    }
    public void setPackageName(String packageName) {
        this.packageName = packageName;
    }
    public String getClassPath() {
        return classPath;
    }
    public void setClassPath(String classPath) {
        this.classPath = classPath;
    }
    public Integer getFlowId() {
        return flowId;
    }
    public void setFlowId(Integer flowId) {
        this.flowId = flowId;
    }
    public String getType() {
        return type;
    }
    public void setType(String type) {
        this.type = type;
    }
}

+ 2 - 2
hos-broker/src/main/java/com/yihu/hos/services/BrokerServerService.java

@ -2,8 +2,8 @@ package com.yihu.hos.services;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.yihu.hos.configuration.ApplicationConfiguration;
import com.yihu.hos.configuration.ArbiterConfiguration;
import com.yihu.hos.common.configuration.ApplicationConfiguration;
import com.yihu.hos.common.configuration.ArbiterConfiguration;
import org.apache.camel.util.InetAddressUtil;
import org.apache.http.Consts;
import org.apache.http.NameValuePair;

+ 68 - 39
hos-broker/src/main/java/com/yihu/hos/services/ESBCamelService.java

@ -3,15 +3,18 @@ package com.yihu.hos.services;
import com.yihu.ehr.framework.model.Result;
import com.yihu.ehr.framework.util.operator.ClassFileUtil;
import com.yihu.ehr.framework.util.operator.StringUtil;
import com.yihu.hos.model.CamelContextQueue;
import com.yihu.hos.model.SystemPathMapping;
import com.yihu.hos.common.classLoader.DynamicClassLoader;
import com.yihu.hos.common.constants.Constant;
import com.yihu.hos.models.SystemCamelContext;
import com.yihu.hos.models.SystemPathMapping;
import org.apache.camel.builder.RouteBuilder;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.stereotype.Service;
import java.io.File;
import java.net.URL;
import java.util.Map;
import java.util.concurrent.SynchronousQueue;
/**
 * Created by lingfeng on 2016/8/4.
@ -64,57 +67,83 @@ public class ESBCamelService {
     * 当外界组件通知一个新的RouteDefine路由被定义时,该事件被触发
     */
    public Result onRouteDefineAdded(String serviceFlow , String packageName , String className , String path) {
/*
         * 当一个新的路由定义事件发生时,要做以下几件事情:
         *
         * 1、根据serviceFlow的信息,在ESB-Broker Server的映射容器中寻
         * 找个业务系统定义的各种Server Class 文件在ESB-Broker Server节点本地存储的根路径
         * 2、然后按照packageName、className、contents的信息将这个class文件写入到正确的位置
         * 3、不能在本线程操作Apache Camel,只能通过一个同步队列通知Apache Camel主线程
         * */
        if(StringUtil.isEmpty(serviceFlow) || StringUtil.isEmpty(packageName)
                || StringUtil.isEmpty(className) || StringUtil.isEmpty(path)) {
            logger.error("必要的入参数据不正确,请检查!");
            return Result.error("必要的入参数据不正确,请检查!");
        }
        // 第1、2两步处理过程,都是在这里完成
        this.createClassfile(serviceFlow, packageName, className, path);
        // 3、===============加载到CamelContext中
        SynchronousQueue<String> camelContextOperateQueue = CamelContextQueue.getCamelCamelContextQueue();
        try {
            camelContextOperateQueue.put(packageName + "." + className);
        } catch (InterruptedException e) {
            logger.error(e.getMessage() , e);
            if(StringUtil.isEmpty(serviceFlow) || StringUtil.isEmpty(packageName)
                    || StringUtil.isEmpty(className) || StringUtil.isEmpty(path)) {
                logger.error("必要的入参数据不正确,请检查!");
                return Result.error("必要的入参数据不正确,请检查!");
            }
            File systemClassRootPath = new File(ClassLoader.getSystemResource("").getPath() + "/" + serviceFlow);
            if (!systemClassRootPath.exists()) {
                systemClassRootPath.mkdirs();
            }
            // 记录到工具类中,以便其它线程需要时进行取用
            SystemPathMapping.getSystemRootPathMapping().put(serviceFlow, systemClassRootPath.toURI().toURL());
            // 第1、2两步处理过程,都是在这里完成
            this.createClassfile(serviceFlow, packageName, className, path);
            // 3、===============加载到CamelContext中
            ClassLoader currentClassLoader = Thread.currentThread().getContextClassLoader();
            Class<RouteBuilder> routeBuilderClass = (Class<RouteBuilder>) currentClassLoader.loadClass(serviceFlow + Constant.DOT + packageName + Constant.DOT + className);
            if(routeBuilderClass != null) {
                RouteBuilder routeBuilder = routeBuilderClass.newInstance();
                SystemCamelContext.getDefaultCamelContext().addRoutes(routeBuilder);
            }
            return Result.success("新增路由成功!");
        } catch (Exception e) {
            logger.error(e);
            return Result.error("新增路由失败!");
        }
        return Result.success("新增路由成功!");
    }
    /**
     * 当外界组件通知一个已有的RouteDefine路由定义被改变时,主要就是路由定义内容被改变时,该事件被触发。
     */
    public Result onRouteDefineChanged(String serviceFlow, String packageName, String className, String path) {
        if(StringUtil.isEmpty(serviceFlow) || StringUtil.isEmpty(packageName)
                || StringUtil.isEmpty(className) || StringUtil.isEmpty(path)) {
            logger.error("必要的入参数据不正确,请检查!");
            return Result.error("必要的入参数据不正确,请检查!");
        try {
            if (StringUtil.isEmpty(serviceFlow) || StringUtil.isEmpty(packageName)
                    || StringUtil.isEmpty(className) || StringUtil.isEmpty(path)) {
                logger.error("必要的入参数据不正确,请检查!");
                return Result.error("必要的入参数据不正确,请检查!");
            }
            SystemCamelContext.getDefaultCamelContext().stopRoute(serviceFlow);
            SystemCamelContext.getDefaultCamelContext().removeRoute(serviceFlow);
            this.updateClassfile(serviceFlow, packageName, className, path);
            // 3、===============加载到CamelContext中
            DynamicClassLoader classLoader = new DynamicClassLoader(DynamicClassLoader.class.getClassLoader());
            Class<RouteBuilder> routeBuilderClass = (Class<RouteBuilder>) classLoader.loadClass(ClassLoader.getSystemResource(Constant.EMPTY).getPath(),
                    serviceFlow + Constant.DOT + packageName + Constant.DOT + className + Constant.DOT + Constant.CLASS);
            if (routeBuilderClass != null) {
                RouteBuilder routeBuilder = routeBuilderClass.newInstance();
                SystemCamelContext.getDefaultCamelContext().addRoutes(routeBuilder);
            }
            return Result.success("修改路由成功!");
        } catch (Exception e) {
            return Result.error("修改路由失败!");
        }
        this.updateClassfile(serviceFlow, packageName, className, path);
        return Result.success("修改路由成功!");
    }
    /**
     * 当外界组件通知一个已有的RouteDefine路由定义被删除时,该事件被触发。
     */
    public Result onRouteDefineDelete(String serviceFlow, String packageName, String className) {
        if(StringUtil.isEmpty(serviceFlow) || StringUtil.isEmpty(packageName)
                || StringUtil.isEmpty(className)) {
            logger.error("必要的入参数据不正确,请检查!");
            return Result.error("必要的入参数据不正确,请检查!");
        try {
            if(StringUtil.isEmpty(serviceFlow) || StringUtil.isEmpty(packageName)
                    || StringUtil.isEmpty(className)) {
                logger.error("必要的入参数据不正确,请检查!");
                return Result.error("必要的入参数据不正确,请检查!");
            }
            SystemCamelContext.getDefaultCamelContext().stopRoute(serviceFlow);
            SystemCamelContext.getDefaultCamelContext().removeRoute(serviceFlow);
            this.deleteClassfile(serviceFlow, packageName, className);
            return Result.success("删除路由成功!");
        } catch (Exception e) {
            return Result.error("删除路由失败!");
        }
        this.deleteClassfile(serviceFlow, packageName, className);
        return Result.success("删除路由成功!");
    }
@ -130,7 +159,7 @@ public class ESBCamelService {
        ClassFileUtil.createClassfile(systemRootURL, packageName, className, path);
        // 完成
        logger.info("===================" + packageName + "." + className + ".class 生成过程结束");
        logger.info("===================" + packageName + Constant.DOT + className + ".class 生成过程结束");
    }
    private void updateClassfile(String serviceFlow, String packageName, String className, String path) {
@ -145,7 +174,7 @@ public class ESBCamelService {
        ClassFileUtil.updateClassfile(systemRootURL, packageName, className, path);
        // 完成
        logger.info("===================" + packageName + "." + className + ".class 修改过程结束");
        logger.info("===================" + packageName + Constant.DOT + className + ".class 修改过程结束");
    }
    private void deleteClassfile(String serviceFlow, String packageName, String className) {
@ -160,6 +189,6 @@ public class ESBCamelService {
        ClassFileUtil.deleteClassfile(systemRootURL, packageName, className);
        // 完成
        logger.info("===================" + packageName + "." + className + ".class 删除过程结束");
        logger.info("===================" + packageName + Constant.DOT + className + ".class 删除过程结束");
    }
}