Spring+zookeeper+dubbo构建微服务项目框架
整个项目源码我已经提交到Github上面了,大家可以去看一下 :项目源码地址
1、首先上搭建好的项目结构:
分层多模块web项目(微服务架构)
SpringMVC+Spring+mybatis-plus 集成redis
- commons-parent是父级项目管理子项目的maven jar包的版本信息。
- commons-util是项目中一些公共类型的存放模块。
- commons-config是项目中通用配置文件的存放模块
-
commons-manaeger是微服务内聚项目
- commons-mananger-dao dao层代码(持久层代码在这里,mybatis-plus的Mapper也是放在这里)
- commons-manager-interface 接口类的存放模块
- commons-manager-model model和pojo类型的存放路径
- commons-manager-service 服务提供者
- commons-manager-web 服务消费者
整体的项目目录树如上图。
项目创建的具体过程就不在这里贴出来了,使用idea构建这种多模块内聚项目还是很简单。
2、启动相应的前置中间件服务
启动顺序:
因为该项目已经整合了redis,所以在启动服务提供者和服务订阅者之前最好先把redis服务给先启动了
redis服务启动后,还需要把zookeeper注册中心给开启,zookeeper的配置我是使用默认的端口
以上的两个服务启动完成,我们就可以分别启动服务提供者项目和服务订阅者项目了。
3、启动服务提供者和订阅者
服务提供者项目其实就是commons-manager-service,该项目主要就是把项目的服务接口注册到zookeeper上面,所以我这里就使用了main方法的方式来启动。其实也可以使用其他的方式来启动,不过这里为了简单演示,所以就使用了main方法;
我们打开commons-manager-service目录下面test文件下面的dubbo.test.DubboProviderTest类:
启动该类的main方法就可以了。
如果控制台,没有报错就说明项目启动正常1,服务也已经成功注册到了zookeeper上面。
为了验证我们可以使用dubbo-admin项目来查看一下,服务是否已经真的成功注册了。使用tomcat启动dubbo-admin项目。
访问dubbo-admin项目,我们可以看到有服务注册了。
到这里服务提供者就已经启动成功了。
接着我们来启动服务订阅者来访问注册到zookeeper的服务。其实所说的服务订阅者也就是项目commons-manager-web,这是一个web项目来的,我们使用tomcat来启动就行了。
同样的,如果控制台没有报错,就说明启动完成了。我们接着看一下dubbo-admin的消费者信息。
可看到已经有消费者订阅到服务了。
到这里我们就已经把项目完全启动了。并且项目里面已经有通过mybatis-plus的代码生成器根据数据库的一些表生成了代码了。所以我们可以通过在commons-manager-web的controller调用一个服务来验证一下服务是否能够正常通讯并且访问数据库返回数据。
我们以ResourceController这个类,来写一个请求方法来做校验:
重启项目的服务,通过浏览器请求:http://localhost:8080/resource/testResource
可以看到,接口成功的返回了数据库查询到的数据了。
PS:mybatis-plus的代码生成器,我已经放到了项目commons-manager-dao的项目中了,这个代码生成器,我是根据官网给出的代码,做了一下相关的调整的,使得该生成器可以根据多模块项目的目录来对应生成相关的文件,除了xml文件生成后我们需要手动移动到对应的文件夹,其他的文件mapper,model,service,controller这些,我们度可以通过在代码生成器的那个类里面设,这样我们在生成代码后就不用再一个个的手动的移动了。具体的代码大家可以去看一下那个类:
public class MybatisPlusUtils { public static void main(String[] args) { String[] models = {"commons-manager/commons-manager-dao", "commons-manager/commons-manager-pojo", "commons-manager/commons-manager-service", "commons-manager/commons-manager-interface", "commons-manager/commons-manager-web"}; for (String model : models) { shell(model); } } private static void shell(String model) { File file = new File(model); String path = file.getAbsolutePath(); System.out.println(path); //path = path.substring(0, path.lastIndexOf(File.separator)); AutoGenerator mpg = new AutoGenerator(); // 全局配置 GlobalConfig gc = new GlobalConfig(); gc.setOutputDir(path + "/src/main/java"); gc.setFileOverride(true); gc.setActiveRecord(true); gc.setEnableCache(false);// XML 二级缓存 gc.setBaseResultMap(true);// XML ResultMap gc.setBaseColumnList(false);// XML columList gc.setAuthor("ChinPangLung"); // 自定义文件命名,注意 %s 会自动填充表实体属性! gc.setMapperName("%sMapper"); gc.setXmlName("%sMapper"); gc.setServiceName("I%sService"); gc.setServiceImplName("I%sServiceImpl"); gc.setControllerName("%sController"); mpg.setGlobalConfig(gc); // 数据源配置 DataSourceConfig dsc = new DataSourceConfig(); dsc.setDbType(DbType.MYSQL); dsc.setTypeConvert(new MySqlTypeConvert() { // 自定义数据库表字段类型转换【可选】 @Override public DbColumnType processTypeConvert(String fieldType) { System.out.println("转换类型:" + fieldType); // 注意!!processTypeConvert 存在默认类型转换,如果不是你要的效果请自定义返回、非如下直接返回。 return super.processTypeConvert(fieldType); } }); dsc.setDriverName("com.mysql.jdbc.Driver"); dsc.setUsername("root"); dsc.setPassword("root"); dsc.setUrl("jdbc:mysql:///managerDB?characterEncoding=utf8"); mpg.setDataSource(dsc); // 策略配置 StrategyConfig strategy = new StrategyConfig(); // strategy.setCapitalMode(true);// 全局大写命名 ORACLE 注意 // strategy.setTablePrefix(new String[]{"tlog_", "tsys_"});// 此处可以修改为您的表前缀 strategy.setNaming(NamingStrategy.underline_to_camel);// 表名生成策略 strategy.setInclude(new String[]{"resource"}); // 需要生成的表 // strategy.setExclude(new String[]{"test"}); // 排除生成的表 // 自定义实体父类 //strategy.setSuperEntityClass("com.spf.model.Entity"); // 自定义实体,公共字段 //strategy.setSuperEntityColumns(new String[] { "test_id", "age" }); // 自定义 mapper 父类 // strategy.setSuperMapperClass("com.baomidou.demo.TestMapper"); // 自定义 service 父类 //strategy.setSuperServiceClass("com.baomidou.demo.TestService"); // 自定义 service 实现类父类 //strategy.setSuperServiceImplClass("com.baomidou.demo.TestServiceImpl"); // 自定义 controller 父类 strategy.setSuperControllerClass("com.lung.common.controller.SuperController"); // 【实体】是否生成字段常量(默认 false) // public static final String ID = "test_id"; // strategy.setEntityColumnConstant(true); // 【实体】是否为构建者模型(默认 false) // public User setName(String name) {this.name = name; return this;} // strategy.setEntityBuliderModel(true); mpg.setStrategy(strategy); // 包配置 PackageConfig pc = new PackageConfig(); pc.setParent("com.lung.application.test"); pc.setController("controller"); pc.setEntity("entity"); pc.setMapper("mapper"); pc.setService("api"); pc.setServiceImpl("service"); //pc.setModuleName("test"); mpg.setPackageInfo(pc); // 注入自定义配置,可以在 VM 中使用 cfg.abc 【可无】 InjectionConfig cfg = new InjectionConfig() { @Override public void initMap() { Map<String, Object> map = new HashMap<String, Object>(); map.put("abc", this.getConfig().getGlobalConfig().getAuthor() + "-mp"); this.setMap(map); } }; // 自定义 xxList.jsp 生成 List<FileOutConfig> focList = new ArrayList<FileOutConfig>(); // focList.add(new FileOutConfig("/template/list.jsp.vm") { // @Override // public String outputFile(TableInfo tableInfo) { // // 自定义输入文件名称 // return "D://my_" + tableInfo.getEntityName() + ".jsp"; // } // }); // cfg.setFileOutConfigList(focList); // mpg.setCfg(cfg); // 调整 xml 生成目录演示 // focList.add(new FileOutConfig("/templates/mapper.xml.vm") { // @Override // public String outputFile(TableInfo tableInfo) { // return "/develop/code/xml/" + tableInfo.getEntityName() + ".xml"; // } // }); // cfg.setFileOutConfigList(focList); mpg.setCfg(cfg); // 关闭默认 xml 生成,调整生成 至 根目录 TemplateConfig tc = new TemplateConfig(); if ("commons-manager/commons-manager-dao".equals(model)) { tc.setController(null); tc.setEntity(null); tc.setService(null); tc.setServiceImpl(null); // tc.setXml(null); } /*else if ("commons-manager/commons-manager-service/src/main/resources/mapper".equals(model)) { PackageConfig packageInfo = mpg.getPackageInfo(); packageInfo.setParent(null); packageInfo.setXml("xml"); tc.setController(null); tc.setEntity(null); tc.setService(null); tc.setServiceImpl(null); tc.setMapper(null); }*/ else if ("commons-manager/commons-manager-pojo".equals(model)) { tc.setController(null); tc.setService(null); tc.setServiceImpl(null); tc.setMapper(null); tc.setXml(null); } else if ("commons-manager/commons-manager-service".equals(model)) { tc.setController(null); tc.setMapper(null); tc.setService(null); tc.setXml(null); tc.setEntity(null); } else if ("commons-manager/commons-manager-interface".equals(model)) { tc.setController(null); tc.setMapper(null); tc.setServiceImpl(null); tc.setXml(null); tc.setEntity(null); } else if ("commons-manager/commons-manager-web".equals(model)) { tc.setMapper(null); tc.setXml(null); tc.setService(null); tc.setServiceImpl(null); tc.setEntity(null); } mpg.setTemplate(tc); // 自定义模板配置,可以 copy 源码 mybatis-plus/src/main/resources/template 下面内容修改, // 放置自己项目的 src/main/resources/template 目录下, 默认名称一下可以不配置,也可以自定义模板名称 // TemplateConfig tc = new TemplateConfig(); // tc.setController("..."); // tc.setEntity("..."); // tc.setMapper("..."); // tc.setXml("..."); // tc.setService("..."); // tc.setServiceImpl("..."); // 如上任何一个模块如果设置 空 OR Null 将不生成该模块。 // mpg.setTemplate(tc); // 执行生成 mpg.execute(); // 打印注入设置【可无】 System.err.println(mpg.getCfg().getMap().get("abc")); } }
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
优秀互联网高级测试工程师应该具备的能力
概述 在之前写的互联网高级测试工程师至少具备的能力一文中,提到了测试工程师至少具备的能力,但是并没有提到优秀测试工程师应该具备的能力,下文简单的谈一谈。当然这些全部都是我的个人理解。 能发现问题,还能定位问题,而且能给研发解释得清楚 在实际的工作中,你可能会遇到很多测试人员在测试功能模块的时候,一遇到问题,马上就来找开发,由开发来定位问题。测试人员发现功能不对,我们可以理解为【开发人员研发的系统的功能跟产品经理的需求不一致】,属于【发现问题了】。这个没问题,但是测试人员能不能静下心来,自己先研究一下发生问题的原因呢?相信很多开发人员经常会遇到,测试人员提的bug其实跟代码没关系,而是环境问题或者数据问题等。 可能有人会问,怎么定位呀?其实手段多得很,例如,看日志、抓包、看代码、debug代码、分析数据、分析业务流程、分析请求走过的节点等等,进行多方面的求证。如果实在找不到原因,才来找开发。 如果测试人员找到原因后,还能跟开发人员解释清楚,那就非常了不起了。因为这里除了涉及到专业能力外,还涉及到测试人员的沟通表达能力。 提一个自描述的BUG 你没有遇到这种情况,测试人员提的bug单里,只...
- 下一篇
Istio流量管理实践之(1): 通过Istio规则来实现TCP入口流量路由的统一管理
概述 使用Istio的流量管理模型,本质上是将流量与基础设施扩容进行解耦,让运维人员可以通过Pilot指定流量遵循什么规则,而不是指定哪些pods/VM应该接收流量。通过将流量从基础设施扩展中解耦,就可以让 Istio 提供各种独立于应用程序代码之外的流量管理功能。 这些功能都是通过部署的Envoy sidecar代理来实现的。 在一个典型的网格中,通常有一个或多个用于终结外部 TLS 链接,将流量引入网格的负载均衡器(我们称之为 gateway),然后流量通过sidecar gateway流经内部服务。下图描绘了网关在网格中的使用情况: Istio Gateway 为 HTTP/TCP 流量配置了一个负载均衡,多数情况下在网格边缘进行操作,用于启用一个服务的入口(ingress)流量。网格中可以存在任意数量的 Gateway,并且多个
相关文章
文章评论
共有0条评论来说两句吧...