Consul-Proxy:使用netty实现快速服务注册(一)注册服务并提供服务

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

注册服务并提供邮件服务

一、背景

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

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

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

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

本例就使用邮件发送服务作为示例使用consul-proxy。

品茗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>org.slf4j</groupId>
			<artifactId>slf4j-log4j12</artifactId>
			<version>1.7.25</version>
		</dependency>
		<dependency>
		   <groupId>com.sun.mail</groupId>
		   <artifactId>javax.mail</artifactId>
		   <version>1.6.1</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>		              
		<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.MailConfiguration;
import cn.pomit.consulproxy.handler.EmailRestHandler;

@EnableServer(handler = { EmailRestHandler.class})
@InitConfiguration(configurations = { MailConfiguration.class })
public class ConsulApp {
	public static void main(String[] args) {
		ConsulProxyApplication.run(ConsulApp.class, args);
	}

}
3.2 邮件服务的配置读取

consul-proxy工具可以自动读取解析@InitConfiguration注解,并调用注解指定的配置类的initConfiguration方法,这个方法要声明为static方法,并有Properties 参数,consul-proxy会自动将程序的配置传递给这个initConfiguration方法。

这里将Properties 传递给MailConfiguration进行初始化,方便读取配置。

MailConfiguration :

import java.util.Properties;

public class MailConfiguration {
	private static MailConfiguration instance = null;
	private String mailUserName;
	private String mailPassword;
	private String mailFrom;
	private String mailFromName;
	private Properties mailproperties;

	public static void initConfiguration(Properties properties) {
		instance = new MailConfiguration();
		instance.mailUserName = properties.getProperty("mail.username");
		instance.mailPassword = properties.getProperty("mail.password");
		instance.mailFrom = properties.getProperty("mail.from");
		instance.mailFromName = properties.getProperty("mail.fromName");
		instance.mailproperties = new Properties();
		instance.mailproperties.put("mail.smtp.host", properties.getProperty("mail.host"));
		instance.mailproperties.put("mail.smtp.port", properties.getProperty("mail.port"));
		instance.mailproperties.put("mail.smtp.auth", properties.getProperty("mail.properties.mail.smtp.auth"));
		instance.mailproperties.put("mail.smtp.starttls.enable",
				properties.getProperty("mail.properties.mail.smtp.starttls.enable"));
		instance.mailproperties.put("mail.smtp.ssl.enable",
				properties.getProperty("mail.properties.mail.smtp.ssl.enable"));
		instance.mailproperties.put("mail.smtp.starttls.required",
				properties.getProperty("mail.properties.mail.smtp.starttls.required"));
	}

	public static MailConfiguration getInstance() {
		return instance;
	}

	public String getMailUserName() {
		return mailUserName;
	}

	public void setMailUserName(String mailUserName) {
		this.mailUserName = mailUserName;
	}

	public String getMailPassword() {
		return mailPassword;
	}

	public void setMailPassword(String mailPassword) {
		this.mailPassword = mailPassword;
	}

	public String getMailFrom() {
		return mailFrom;
	}

	public void setMailFrom(String mailFrom) {
		this.mailFrom = mailFrom;
	}

	public Properties getMailproperties() {
		return mailproperties;
	}

	public void setMailproperties(Properties mailproperties) {
		this.mailproperties = mailproperties;
	}

	public String getMailFromName() {
		return mailFromName;
	}

	public void setMailFromName(String mailFromName) {
		this.mailFromName = mailFromName;
	}
}
3.3 Handler处理类

下面是EmailRestHandler类,使用json处理相关数据,发送邮件,返回json结果。

EmailRestHandler:


import java.nio.charset.Charset;

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.consul.http.res.ResCode;
import cn.pomit.consul.http.res.ResType;
import cn.pomit.consulproxy.dto.ResultCode;
import cn.pomit.consulproxy.dto.ResultModel;
import cn.pomit.consulproxy.dto.mail.Email;
import cn.pomit.consulproxy.service.mail.MailService;

public class EmailRestHandler extends AbstractResourceHandler {

	@Mapping(value = "/email/code")
	public HttpResponseMessage findUser(HttpRequestMessage httpRequestMessage) {
		ResultModel rm = null;

		try {
			String content = httpRequestMessage.getBody().toString(Charset.defaultCharset());
			Email email = JSONObject.parseObject(content, Email.class);
			if (email == null) {
				rm = new ResultModel(ResultCode.CODE_00003);
			} else {
				MailService.sendHtmlMail(email);
				rm = ResultModel.ok();
			}
		} catch (Exception e) {
			e.printStackTrace();
			rm = ResultModel.error(e.getMessage());
		}
		HttpResponseMessage httpResponseMessage = new HttpResponseMessage();
		httpResponseMessage.setResCode(ResCode.OK.getValue());
		httpResponseMessage.setResType(ResType.JSON.getValue());
		httpResponseMessage.setMessage(JSONObject.toJSONString(rm));
		return httpResponseMessage;
	}

	@Mapping(value = "/health")
	public HttpResponseMessage add(HttpRequestMessage httpRequestMessage) throws Exception {
		HttpResponseMessage httpResponseMessage = new HttpResponseMessage();
		httpResponseMessage.setResCode(ResCode.OK.getValue());
		httpResponseMessage.setResType(ResType.JSON.getValue());
		httpResponseMessage.setMessage("echo");
		return httpResponseMessage;
	}

}
3.4 Service处理逻辑层

由于不是spring环境,Service每次使用需要自己new一个对象了。这里的MailService 是调用javax.mail的逻辑。

MailService :

import java.util.Date;

import javax.mail.Authenticator;
import javax.mail.BodyPart;
import javax.mail.Message;
import javax.mail.Multipart;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;

import cn.pomit.consulproxy.config.MailConfiguration;
import cn.pomit.consulproxy.dto.mail.Email;

public class MailService {

	/**
	 * 发送Html邮件
	 * 
	 * @throws Exception
	 */
	public static void sendHtmlMail(Email email) throws Exception {

		// 根据邮件会话属性和密码验证器构造一个发送邮件的session
		Session sendMailSession = Session.getDefaultInstance(MailConfiguration.getInstance().getMailproperties(),
				new Authenticator() {
					@Override
					protected PasswordAuthentication getPasswordAuthentication() {
						return new PasswordAuthentication(MailConfiguration.getInstance().getMailUserName(),
								MailConfiguration.getInstance().getMailPassword());
					}
				});
		// 根据session创建一个邮件消息
		Message mailMessage = new MimeMessage(sendMailSession);
		// 设置邮件消息的发送者
		mailMessage.setFrom(new InternetAddress(MailConfiguration.getInstance().getMailFrom(),
				MailConfiguration.getInstance().getMailFromName()));
		// 创建邮件的接收者地址,并设置到邮件消息中
		mailMessage.setRecipient(Message.RecipientType.TO, new InternetAddress(email.getTo()));
		// 设置邮件消息的主题
		mailMessage.setSubject(email.getSubject());
		// 设置邮件消息发送的时间
		mailMessage.setSentDate(new Date());

		// MiniMultipart类是一个容器类,包含MimeBodyPart类型的对象
		Multipart mainPart = new MimeMultipart();
		// 创建一个包含HTML内容的MimeBodyPart
		BodyPart html = new MimeBodyPart();
		// 设置HTML内容
		html.setContent(email.getContent(), "text/html; charset=utf-8");
		mainPart.addBodyPart(html);
		// 将MiniMultipart对象设置为邮件内容
		mailMessage.setContent(mainPart);
		// 发送邮件
		Transport.send(mailMessage);
	}
}

3.5 过程中使用到的实体

Email :

public class Email {
	String to;
	String subject;
	String content;
	boolean html = true;
	
	public String getTo() {
		return to;
	}
	public void setTo(String to) {
		this.to = to;
	}
	public String getSubject() {
		return subject;
	}
	public void setSubject(String subject) {
		this.subject = subject;
	}
	public String getContent() {
		return content;
	}
	public void setContent(String content) {
		this.content = content;
	}
	public boolean isHtml() {
		return html;
	}
	public void setHtml(boolean html) {
		this.html = html;
	}
	
}

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

mail.host=smtp.qq.com
mail.username=xxx@qq.com
mail.password=xxxx
mail.port=465
mail.properties.mail.smtp.auth=true
mail.properties.mail.smtp.starttls.enable=true
mail.properties.mail.smtp.ssl.enable=true
mail.properties.mail.smtp.starttls.required=true 

mail.from=916881512@qq.com
mail.fromName=Admin

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

这里面,以mail.开发的配置,是我们在MailConfiguration里面需要的自定义配置。其他配置为consul-proxy需要的配置。

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交流群

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值