服务提供和消费脑图
服务提供和消费脑图
v服务提供者
1.服务提供者启动,解析xml文件中配置的服务,这里使用Dom4j解析。
2.将服务的一些相关信息注册到 服务注册中心。
注:服务相关信息:服务中心接口url,接口名称,方法名称,参数信息。
3.提供一个接口,服务消费者通过调用这个接口url来调用相应的服务。
参见: 服务提供和消费脑图, 服务注册中心 (1.注册服务), 服务消费者 (3.调用服务)
v服务消费者
1.服务消费者启动,使用dom4j解析xml获取要消费的服务相关接口。
2.根据接口信息去服务注册中心判断是否有对应的注册信息,如果有则通过jdk动态代理生成相应的代理类并注册到spring中(代理方法中会根据服务中心返回的信息(服务提供者的url)去调用服务提供者对应的服务)。
参见: 服务提供和消费脑图, 服务注册中心 (2.消费服务), 服务提供者 (3.调用服务)
v服务注册中心
1.将来自服务提供者信息存储到redis。
2.将服务信息提供给服务消费者。
参见: 服务提供者 (1.注册服务), 服务消费者 (2.消费服务), 服务提供和消费脑图
v工程示例
注:示例中为了简单,采用rest请求方式来代替socket连接
v 注册中心
@RestController @RequestMapping("index")public class IndexController { @Autowired private RedisCacheTemplate redisCacheTemplate; //注册服务提供者信息,将信息放到redis中 @RequestMapping(value = "register", method = RequestMethod.POST) public SimpleResponse register(@RequestBody RegisterMessage registerMessage) { try { Map<String, Object> map = new HashMap<>(); for (InterfaceMessage interfaceMessage : registerMessage.getInterfaceMessageList()) { interfaceMessage.setProviderUrl(registerMessage.getProviderUrl()); map.put(ToStringBuilder.reflectionToString(interfaceMessage, ToStringStyle.SHORT_PREFIX_STYLE), true); } redisCacheTemplate.batchPut(map); return SimpleResponse.success(map.size()); } catch (Exception e) { e.printStackTrace(); return SimpleResponse.error(e.getMessage()); } } //消费者拿到配置的服务信息到注册中心来匹配,验证是否存在这个服务 @RequestMapping(value = "contains", method = RequestMethod.POST) public SimpleResponse contains(@RequestBody InterfaceMessage interfaceMessage) { try { if(redisCacheTemplate.exist(ToStringBuilder.reflectionToString(interfaceMessage, ToStringStyle.SHORT_PREFIX_STYLE))) { return SimpleResponse.success(true); } else { return SimpleResponse.error(null); } } catch (Exception e) { e.printStackTrace(); return SimpleResponse.error(e.getMessage()); } } @RequestMapping(value = "test", method = {RequestMethod.GET, RequestMethod.POST}) public SimpleResponse test(@RequestParam String providerUrl){ return SimpleResponse.success(providerUrl); } }
v 服务提供者
<?xml version="1.0" encoding="UTF-8"?><services-provider> <service id="testService" interface="com.hjzgg.simulation.api.ITestService"/></services-provider>
自定义xml,配置将要注册的服务id及对应的接口类。
# 内置tomcat服务器配置 server.port=8088 server.context-path=/provider-server #打印彩色日志 spring.output.ansi.enabled=always # 日志打印级别 logging.level.root=debug # serviceservice.xml.path=classpath:service-provider.xml 自定义服务提供者配置文件 位置 service.provider.path=http://localhost:8088/provider-server/index/provider 服务提供者执行相应服务接口 service.register.path=http://localhost:8090/register-server/index/register 调用注册中心 接口
import com.alibaba.fastjson.JSON;import com.alibaba.fastjson.JSONObject;import com.hjzgg.simulation.common.node.InterfaceMessage;import com.hjzgg.simulation.common.node.RegisterMessage;import com.hjzgg.simulation.common.parsexml.BeanNode;import com.hjzgg.simulation.common.parsexml.ParseServiceXML;import com.hjzgg.simulation.common.response.ReturnCode;import com.hjzgg.simulation.common.utils.RestTemplateUtils;import org.apache.commons.lang3.StringUtils;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.support.BeanDefinitionRegistry;import org.springframework.context.EnvironmentAware;import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;import org.springframework.core.env.Environment;import org.springframework.core.type.AnnotationMetadata;import org.springframework.http.MediaType;import org.springframework.util.CollectionUtils;import java.util.ArrayList;import java.util.List;public class Registrar implements ImportBeanDefinitionRegistrar, EnvironmentAware { private static Logger logger = LoggerFactory.getLogger(Registrar.class); private String servicesXmlPath; private String serviceProviderPath; private String serviceRegisterPath; @Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { List<BeanNode> beanNodes = ParseServiceXML.getProviderServices(servicesXmlPath); 解析自定义服务提供配置文件 List<InterfaceMessage> list = new ArrayList<>(); for(BeanNode beanNode : beanNodes) { 根据服务对应id去 寻找实现的 bean if(!registry.containsBeanDefinition(beanNode.getBeanName())) { logger.error("接口" + beanNode.getBeanName() + " " + beanNode.getInterfaceCls().getTypeName() + " 没有对应的实现类"); } else { InterfaceMessage interfaceMessage = new InterfaceMessage(); interfaceMessage.setBeanName(beanNode.getBeanName()); interfaceMessage.setInterfacType(beanNode.getInterfaceCls().getTypeName()); list.add(interfaceMessage); } } if(!CollectionUtils.isEmpty(list)) { 将配置的服务信息发送的注册中心 RegisterMessage registerMessage = new RegisterMessage(); registerMessage.setProviderUrl(this.serviceProviderPath); registerMessage.setInterfaceMessageList(list); try { String result = RestTemplateUtils.post(this.serviceRegisterPath, (JSONObject) JSON.toJSON(registerMessage), MediaType.APPLICATION_JSON_UTF8); JSONObject retJson = JSONObject.parseObject(result); if(retJson.getInteger("code") == ReturnCode.SUCCESS.getValue()) { logger.debug("服务注册成功..."); } else { logger.error("服务注册失败..." + retJson.getString("msg")); } } catch (Exception e) { e.printStackTrace(); logger.error("服务注册失败..." + e.getMessage()); } } } @Override public void setEnvironment(Environment environment) { 获取环境变量 this.servicesXmlPath = environment.getProperty("service.xml.path"); this.serviceProviderPath = environment.getProperty("service.provider.path"); this.serviceRegisterPath = environment.getProperty("service.register.path"); assert(StringUtils.isNotEmpty(this.serviceProviderPath) && StringUtils.isNotEmpty(serviceRegisterPath) && StringUtils.isNotEmpty(this.servicesXmlPath)); } }
import org.springframework.context.annotation.Configuration;import org.springframework.context.annotation.Import;/** * Created by hujunzheng on 2017/7/7. */@Configuration @Import(Registrar.class)public class Config { 注册服务配置启动}
"index" = "invoke", method === ((bean = ContextUtils.getBean(serviceMessage.getBeanName(), serviceMessage.getRequireType())) != <Class<?>> classList = ArrayList<>(serviceMessage.getArgs() != = ReflectionUtils.findMethod(bean.getClass(), serviceMessage.getMethodName(), classList.toArray( Class<?>[0(method != SimpleResponse.error("服务" + serviceMessage.getRequireType().getTypeName() + "中没有对应参数" + ToStringBuilder.reflectionToString(classList) + "的" + serviceMessage.getMethodName() + "方法" SimpleResponse.error("没有名称为" + serviceMessage.getBeanName() + "且类型为" + serviceMessage.getRequireType().getTypeName() + "对应的bean"
v 服务消费者
<?xml version="1.0" encoding="UTF-8"?><services-consumer> <service ref="testService" interface="com.hjzgg.simulation.api.ITestService" url="http://localhost:8088/provider-server/index/provider"/></services-consumer>
自定义服务消费者配置,服务引用名称,接口类型,调用服务提供者URL
# 内置tomcat服务器配置 server.port=8089server.context-path=/consumer-server #打印彩色日志 spring.output.ansi.enabled=always # 日志打印级别 logging.level.root=debug # service xml service.xml.path=classpath:service-consumer.xml 自定义服务消费配置文件位置service.contains.url=http://localhost:8090/register-server/index/contains 注册中心服务查询接口service.invoke.url=http://localhost:8088/provider-server/index/invoke 服务提供者执行相应服务接口
import com.alibaba.fastjson.JSON;import com.alibaba.fastjson.JSONObject;import com.hjzgg.simulation.common.dynamic.JdkDynamicProxy;import
版权声明:本文原创发表于博客园,作者为小眼儿。 本文欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则视为侵权。 工作之余: lintcode简单题目解析lintcode中等题目解析 |
http://www.cnblogs.com/hujunzheng/p/7131212.html