美文网首页Consul
Consul-Proxy:使用netty实现快速服务注册(二)使

Consul-Proxy:使用netty实现快速服务注册(二)使

作者: 逍遥天扬 | 来源:发表于2019-05-09 09:07 被阅读0次

    Consul-Proxy:使用netty实现快速服务注册

    使用mybatis进行数据库操作

    一、背景

    Springcloud+consul作为微服务的注册已经见怪不怪了,试下也很流行,在我个人云服务器上,我也是这样做的。

    然而,我的云服务器内存比较小,很快内存就被cloud全家桶吃光了,没办法部署其他应用了,因此,我觉得将一些服务独立出去,放弃cloud全家桶。

    Consul-proxy使用netty+consul实现服务注册,并提供了若干简单的注解实现了http的mapping映射处理。

    简单来说,没错,是因为穷,才有了这个组件。

    品茗IT-首发

    二、Maven配置

    要使用consul-proxy,只需要加入下面依赖即可。

    <dependency>
        <groupId>cn.pomit</groupId>
        <artifactId>consul-proxy</artifactId>
        <version>1.3</version>
    </dependency>
    

    但是要完整的运行,还是需要其他依赖的,比如netty和json相关的jar包。

    如果想使用mybatis连接数据库,还需要引入mybatis,这里使用了mybatis-proxy工具,mybatis-proxy工具对mybatis做了简单的封装,方便在非spring环境下使用mybatis。

    完整的依赖如下:

    <?xml version="1.0"?>
    <project
        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
        xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
        <modelVersion>4.0.0</modelVersion>
    
        <groupId>cn.pomit</groupId>
        <artifactId>consul-proxy-demo</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <name>consul-proxy-demo</name>
        <url>http://maven.apache.org</url>
        <properties>
            <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
            <dbcp.version>2.4.0</dbcp.version>
        </properties>
        <dependencies>
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>fastjson</artifactId>
                <version>1.2.40</version>
            </dependency>
            <dependency>
                <groupId>cn.pomit</groupId>
                <artifactId>consul-proxy</artifactId>
                <version>1.3</version>
            </dependency>
            <dependency>
                <groupId>cn.pomit</groupId>
                <artifactId>mybatis-proxy</artifactId>
                <version>1.0</version>
            </dependency>
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>5.1.46</version>
            </dependency>
            <dependency>
                <groupId>org.slf4j</groupId>
                <artifactId>slf4j-log4j12</artifactId>
                <version>1.7.25</version>
            </dependency>
            <dependency>
                <groupId>org.apache.commons</groupId>
                <artifactId>commons-dbcp2</artifactId>
                <version>${dbcp.version}</version>
            </dependency>
        </dependencies>
        <build>
            <plugins>
                <plugin>  
                <groupId>org.apache.maven.plugins</groupId>  
                <artifactId>maven-shade-plugin</artifactId>  
                <version>3.1.0</version>  
                <executions>  
                    <execution>  
                        <phase>package</phase>  
                        <goals>  
                            <goal>shade</goal>  
                        </goals>  
                        <configuration>  
                            <transformers>  
                                <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">  
                                    <mainClass>cn.pomit.consulproxy.ConsulApp</mainClass>  
                                </transformer>  
                            </transformers> 
                        </configuration>  
                    </execution>  
                </executions>  
            </plugin>  
    
            </plugins>
        </build>
    </project>
    
    

    以上maven的配置中,除了依赖以外,还有shade插件的配置,方便打包成可执行jar包。

    说到这里,需要提一下的是,如果打包后运行报错:java.lang.SecurityException: Invalid signature file digest for Manifest main attributes 异常,可以在<configuration> 节点下增加<filters>即可。

    <configuration>  
        <filters>                     
            <filter>
                <artifact>*:*</artifact>
                <excludes>
                    <exclude>META-INF/*.SF</exclude>
                    <exclude>META-INF/*.DSA</exclude>
                    <exclude>META-INF/*.RSA</exclude>
                </excludes>
            </filter>
        </filters>
        <transformers>  
            <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">  
                <mainClass>cn.pomit.consulproxy.ConsulApp</mainClass>  
            </transformer>  
        </transformers> 
    </configuration> 
    

    三、使用方法

    3.1 启动类

    启动类要加上@EnableServer,指明被管理的handler,每个被管理的handler就相当于spring中的一个controller。

    import cn.pomit.consul.ConsulProxyApplication;
    import cn.pomit.consul.annotation.EnableServer;
    import cn.pomit.consul.annotation.InitConfiguration;
    import cn.pomit.consulproxy.config.DataSourceConfiguration;
    import cn.pomit.consulproxy.handler.AdviceHandler;
    
    @EnableServer(handler = { AdviceHandler.class })
    @EnableMybatis(mapperScan = "cn.pomit.consulproxy.mapper")
    public class ConsulApp {
        public static void main(String[] args) {
            ConsulProxyApplication.run(ConsulApp.class, args);
        }
    
    }
    

    3.2 Handler处理类

    下面是AdviceHandler类,使用json处理相关数据,并返回json结果。

    AdviceHandler:

    import java.nio.charset.Charset;
    import java.util.List;
    
    import com.alibaba.fastjson.JSONObject;
    
    import cn.pomit.consul.annotation.Mapping;
    import cn.pomit.consul.handler.resource.AbstractResourceHandler;
    import cn.pomit.consul.http.HttpRequestMessage;
    import cn.pomit.consul.http.HttpResponseMessage;
    import cn.pomit.consulproxy.domain.advice.FAdviceInfo;
    import cn.pomit.consulproxy.dto.ResultCode;
    import cn.pomit.consulproxy.dto.ResultModel;
    import cn.pomit.consulproxy.dto.advice.AdviceAuthReq;
    import cn.pomit.consulproxy.service.advice.FAdviceInfoService;
    import cn.pomit.mybatis.util.StringUtil;
    
    public class AdviceHandler extends AbstractResourceHandler {
    
        @Mapping(value = "/advice/submit")
        public HttpResponseMessage submit(HttpRequestMessage httpRequestMessage) {
            try {
                String content = httpRequestMessage.getBody().toString(Charset.defaultCharset());
                FAdviceInfo fAdviceInfo = JSONObject.parseObject(content, FAdviceInfo.class);
                if (StringUtil.isEmpty(fAdviceInfo.getContent()) || StringUtil.isEmpty(fAdviceInfo.getSummary())) {
                    return HttpResponseMessage.responeseBody(ResultModel.error("参数错误"));
                }
                fAdviceInfo.setStatus(1);
                FAdviceInfoService fAdviceInfoService = new FAdviceInfoService();
                fAdviceInfoService.save(fAdviceInfo);
                return HttpResponseMessage.responeseBody(ResultModel.ok());
            } catch (Exception e) {
                e.printStackTrace();
                return HttpResponseMessage.responeseBody(new ResultModel(ResultCode.CODE_00004));
            }
        }
    
        @Mapping(value = "/advice/list")
        public HttpResponseMessage list(HttpRequestMessage httpRequestMessage) {
            FAdviceInfoService fAdviceInfoService = new FAdviceInfoService();
            List<FAdviceInfo> list = fAdviceInfoService.findByStatus(1);
            return HttpResponseMessage.responeseBody(new ResultModel(ResultCode.CODE_00000, list));
        }
    
        @Mapping(value = "/advice/auth")
        public HttpResponseMessage auth(HttpRequestMessage httpRequestMessage) {
            String content = httpRequestMessage.getBody().toString(Charset.defaultCharset());
            AdviceAuthReq adviceAuthReq = JSONObject.parseObject(content, AdviceAuthReq.class);
            FAdviceInfoService fAdviceInfoService = new FAdviceInfoService();
            FAdviceInfo fAdviceInfo = fAdviceInfoService.findById(adviceAuthReq.getId());
            if (fAdviceInfo == null)
                return HttpResponseMessage.responeseBody(ResultModel.error("留言信息不存在!"));
            if (adviceAuthReq.getType() == 0) {
                fAdviceInfo.setStatus(0);
                fAdviceInfoService.update(fAdviceInfo);
            } else {
                fAdviceInfoService.deleteById(adviceAuthReq.getId());
            }
            return HttpResponseMessage.responeseBody(new ResultModel(ResultCode.CODE_00000));
        }
    
    }
    

    3.3 Service处理逻辑层

    由于不是spring环境,Service每次使用需要自己new一个对象了。但是service使用mybatis的时候,要用ProxyHandlerFactory生成代理,作为属性声明即可,无需每次都new。

    FAdviceInfoService:

    import java.util.List;
    
    import cn.pomit.consulproxy.domain.advice.FAdviceInfo;
    import cn.pomit.consulproxy.mapper.advice.FAdviceInfoDao;
    import cn.pomit.mybatis.ProxyHandlerFactory;
    
    public class FAdviceInfoService {
    
        FAdviceInfoDao fAdviceInfoDao = ProxyHandlerFactory.getMapper(FAdviceInfoDao.class);
    
        public void save(FAdviceInfo fAdviceInfo) {
            fAdviceInfoDao.save(fAdviceInfo);
        }
    
        public void deleteById(Integer id) {
            fAdviceInfoDao.deleteById(id);
        }
    
        public void update(FAdviceInfo fAdviceInfo) {
            fAdviceInfoDao.update(fAdviceInfo);
        }
    
        public List<FAdviceInfo> findByStatus(Integer status) {
            return fAdviceInfoDao.findByStatus(status);
        }
    
        public FAdviceInfo findById(int id) {
            return fAdviceInfoDao.findOne(id);
        }
    }
    
    

    3.4 Mapper接口

    FAdviceInfoDao,常规的mybatis写法:

    import java.util.List;
    
    import org.apache.ibatis.annotations.Delete;
    import org.apache.ibatis.annotations.Insert;
    import org.apache.ibatis.annotations.Mapper;
    import org.apache.ibatis.annotations.Options;
    import org.apache.ibatis.annotations.Param;
    import org.apache.ibatis.annotations.Select;
    import org.apache.ibatis.annotations.Update;
    
    import cn.pomit.consulproxy.domain.advice.FAdviceInfo;
    
    @Mapper
    public interface FAdviceInfoDao {
    
        @Select({
            "<script>",
            "select id id,name name,contract contract,",
            "summary summary,content content,status status",
            "from f_advice_info ",
            " where status = #{status, jdbcType=INTEGER}",
            "</script>"
        })
        List<FAdviceInfo> findByStatus(@Param("status") Integer status);
    
        @Insert({"<script>",
            "INSERT INTO f_advice_info(name , contract , summary , content , status )",
            "values ",
            "(#{name},#{contract},#{summary},#{content},#{status})",
            "</script>"})
        @Options(useGeneratedKeys=true, keyProperty="id", keyColumn="id")
        int save(FAdviceInfo fAdviceInfo);
    
        @Update({
            "<script>",
            " update f_advice_info set",
            "<if test='name != null and name != \"\" '> name = #{name, jdbcType=VARCHAR}, </if>",
            "<if test='contract != null and contract != \"\" '> contract = #{contract, jdbcType=VARCHAR}, </if>",
            "<if test='content != null and content != \"\" '> content = #{content, jdbcType=VARCHAR}, </if>",
            "<if test='status != -1 '> status = #{status, jdbcType=INTEGER}, </if>",
            "<if test='summary != null and summary != \"\" '> summary = #{summary, jdbcType=VARCHAR} </if>",
            " where id=#{id}",
            "</script>"
        })
        int update(FAdviceInfo fAdviceInfo);
    
        @Select({
            "<script>",
            "select id id,name name,contract contract,",
            "summary summary,content content,status status",
            "from f_advice_info ",
            " where id = #{id, jdbcType=INTEGER}",
            "</script>"
        })
        FAdviceInfo findOne(@Param("id") int id);
    
        @Delete({
            "<script>",
            " delete from f_advice_info",
            " where id=#{id}",
            "</script>"
        })
        int deleteById(@Param("id") Integer id);
    
    }
    

    3.5 过程中使用到的实体

    FAdviceInfo:

    public class FAdviceInfo {
        private int id;
        private String name;
        private String contract;
    
        private String summary;
    
        private String content;
    
        private Integer status;
    
        public void setId(int id) {
            this.id = id;
        }
    
        public int getId() {
            return id;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public String getName() {
            return name;
        }
    
        public void setContract(String contract) {
            this.contract = contract;
        }
    
        public String getContract() {
            return contract;
        }
    
        public void setSummary(String summary) {
            this.summary = summary;
        }
    
        public String getSummary() {
            return summary;
        }
    
        public void setContent(String content) {
            this.content = content;
        }
    
        public String getContent() {
            return content;
        }
    
        public Integer getStatus() {
            return status;
        }
    
        public void setStatus(Integer status) {
            this.status = status;
        }
    
    }
    

    AdviceAuthReq:

    public class AdviceAuthReq {
        private Integer id;
        private Integer type;
        
        public Integer getId() {
            return id;
        }
        public void setId(Integer id) {
            this.id = id;
        }
        public Integer getType() {
            return type;
        }
        public void setType(Integer type) {
            this.type = type;
        }
    }
    

    ResultCode:

    public enum ResultCode {
    
        /**
         * 通用
         */
        CODE_00000("00000", "操作成功"), 
        CODE_00001("00001", "请求失败"), 
        CODE_00002("00002", "未授权的请求"), 
        CODE_00003("00003", "非法的参数字段"), 
        CODE_00004("00004", "异常抛出"), 
        CODE_00005("00005", "权限不足"), 
        CODE_00006("00006", "分页limit参数错误"), 
        CODE_00007("00007", "分页offset参数错误"), 
        CODE_00009("00009", "未登录或登录状态已失效"), 
        CODE_00010("00010", "数据已存在"), 
        CODE_00011("00011", "数据不存在"), 
        CODE_00012("00012", "参数缺失"), 
        CODE_00013("00013", "系统维护中"), 
        CODE_00014("00014", "登录失败"), 
        CODE_00015("00015", "token失效"), 
        CODE_00016("00016", "签名错误"),
    
        CODE_99999("99999", "签名无效");
    
        private String code;
        private String desc;
    
        ResultCode(String code, String desc) {
            this.code = code;
            this.desc = desc;
        }
    
        public String getCode() {
            return code;
        }
    
        public String getDesc() {
            return desc;
        }
    
        /**
         * 根据code匹配枚举
         * 
         * @param code
         * @return
         */
        public static ResultCode getResultCodeByCode(String code) {
            for (ResultCode resultCode : ResultCode.values()) {
                if (code.equals(resultCode.getCode())) {
                    return resultCode;
                }
            }
            return null;
        }
    
        public static ResultCode getResultCodeByDesc(String desc) {
            for (ResultCode resultCode : ResultCode.values()) {
                if (desc.equals(resultCode.getDesc())) {
                    return resultCode;
                }
            }
            return null;
        }
    }
    

    ResultModel :

    public class ResultModel {
    
        private String errorCode;
        private String message;
        private Object remark;
        private Object data;
    
        public ResultModel(String errorCode, String message) {
            this.errorCode = errorCode;
            this.message = message;
        }
    
        public ResultModel() {
        }
    
        public ResultModel(String errorCode, String message, Object data) {
            this.errorCode = errorCode;
            this.message = message;
            this.data = data;
        }
    
        public ResultModel(ResultCode resultCodeEnum, Object data) {
            this.errorCode = resultCodeEnum.getCode();
            this.message = resultCodeEnum.getDesc();
            this.data = data;
        }
    
        public ResultModel(ResultCode resultCodeEnum, Object data, Object remark) {
            this.errorCode = resultCodeEnum.getCode();
            this.message = resultCodeEnum.getDesc();
            this.data = data;
            this.remark = remark;
        }
    
        public ResultModel(ResultCode resultCodeEnum) {
            this.errorCode = resultCodeEnum.getCode();
            this.message = resultCodeEnum.getDesc();
        }
    
        public String getErrorCode() {
            return errorCode;
        }
    
        public void setErrorCode(String errorCode) {
            this.errorCode = errorCode;
        }
    
        public String getMessage() {
            return message;
        }
    
        public void setMessage(String message) {
            this.message = message;
        }
    
        public Object getData() {
            return data;
        }
    
        public void setData(Object data) {
            this.data = data;
        }
    
        public static ResultModel ok() {
            return new ResultModel(ResultCode.CODE_00000);
        }
    
        public static ResultModel ok(Object data) {
            return new ResultModel(ResultCode.CODE_00000, data);
        }
    
        public static ResultModel unAuth() {
            return new ResultModel(ResultCode.CODE_00002);
        }
    
        public static ResultModel unAuth(Object data) {
            return new ResultModel(ResultCode.CODE_00002, data);
        }
    
        public static ResultModel error(String message) {
            return new ResultModel(ResultCode.CODE_00001.getCode(), message);
        }
    
        public Object getRemark() {
            return remark;
        }
    
        public void setRemark(Object remark) {
            this.remark = remark;
        }
    
    }
    

    四、配置文件

    4.1 application.properties

    在classpath下添加application.properties

    spring.profiles.active=loc
    application.name=consulProxy
    application.port=8999
    

    这个指定了带环境的配置文件可以读取classpath下的application-loc.properties

    application-loc.properties:

    consul.host=127.0.0.1
    consul.port=8500
    #consul.instanceId=cunsul-proxy-8888
    #consul.scheme=https
    #consul.healthCheckUrl=/health
    consul.healthCheckPath=/health
    #consul.healthCheckInterval=10s
    #consul.healthCheckTimeout=100s
    consul.preferIpAddress=true
    
    mybatis.configuration=cn.pomit.mybatis.configuration.MybatisConfiguration
    #mybatis.mapper.scan=cn.pomit.consulproxy.mapper
    mybatis.transation.scan=cn.pomit.consulproxy.service
    mybatis.datasource.type=POOLED
    mybatis.datasource.driver=com.mysql.jdbc.Driver
    mybatis.datasource.url=jdbc:mysql://127.0.0.1:3306/boot?useUnicode=true&characterEncoding=utf8&serverTimezone=UTC
    mybatis.datasource.username=cff
    mybatis.datasource.password=123456
    
    

    如果不带环境,直接把application-loc.properties的配置写在application.properties也是一样的。

    这里面,以mybatis.开发的配置,可以自动加载并配置成mybatis自己定义的数据库连接池,这里面的参数不能多,只能是mybatis要的那几个参数。按照mybatis的config的xml要求的那些参数。

    如果我们想自定义数据源,可以参考《Consul-Proxy:使用netty实现快速服务注册(三)使用第三方数据源》一篇。

    4.2 log4j.properties

    使用log4j,log4j的配置文件写在classpath下即可:

    # DEBUG,INFO,WARN,ERROR,FATAL
    LOG_LEVEL=DEBUG
    
    log4j.rootLogger=${LOG_LEVEL},CONSOLE,FILE
    
    log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
    log4j.appender.CONSOLE.Encoding=utf-8
    log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
    #log4j.appender.CONSOLE.layout.ConversionPattern=[%-5p] %d{yyyy-MM-dd HH:mm:ss} %C{8}@(%F:%L):%m%n 
    log4j.appender.CONSOLE.layout.ConversionPattern=[%-5p] %d{yyyy-MM-dd HH:mm:ss} %C{1}@(%F:%L):%m%n
    
    log4j.appender.FILE=org.apache.log4j.DailyRollingFileAppender
    log4j.appender.FILE.File=logs/workorder.log
    log4j.appender.FILE.Encoding=utf-8
    log4j.appender.FILE.DatePattern='.'yyyy-MM-dd
    log4j.appender.FILE.layout=org.apache.log4j.PatternLayout
    #log4j.appender.FILE.layout=org.apache.log4j.HTMLLayout
    log4j.appender.FILE.layout.ConversionPattern=[%-5p] %d{yyyy-MM-dd HH\:mm\:ss} %C{8}@(%F\:%L)\:%m%n 
    

    喜欢这篇文章么,喜欢就加入我们一起讨论netty技术吧!


    品茗IT交流群

    相关文章

      网友评论

        本文标题:Consul-Proxy:使用netty实现快速服务注册(二)使

        本文链接:https://www.haomeiwen.com/subject/bwjioqtx.html