基于SOA架构的Dubbox服务中间件和Zookeeper注册中心

什么是SOA架构

SOA是Service-Oriented Architecture的首字母简称,它是一种支持面向服务的架构样式(根据应用程序的不同功能单元进行拆分)。从服务、基于服务开发和服务的结果来看,面向服务是一种思考方式。其实SOA架构更多应用于互联网项目开发。
为什么互联网项目会采用SOA架构呢?随着互联网的发展,网站应用的规模不断扩大,常规的垂直应用架构已无法应对,分布式服务架构以及流动计算架构势在必行,迫切需一个治理系统确保架构有条不紊的演进。
注:对于大型互联网项目,垂直应用架构已经不适应需求(所谓垂直架构就是MVC三层架构:Model --> view–>Controller),那么就需要使用SOA架构进行分布式架构
“面向服务的架构”:他是一种设计方法,其中包含多个服务, 服务之间通过相互依赖最终提供一系列的功能。一个服务 通常以独立的形式存在与操作系统进程中。各个服务之间 通过网络调用。
在这里插入图片描述
服务方:service 层(暴露接口) , 消费方:controller层(远程注入)
**逻辑详解:**服务方类似房东有房出租,消费方类似租客要租房,房东出租房子找到中介(注册中心),告诉中介自己的房子地址大小等信息,租客找中介租房,中介会根据租客请求等信息,找到房东

节点角色说明:

  • Provider: 暴露服务的服务提供方。
  • Consumer: 调用远程服务的服务消费方。(通过订阅服务–>找到注册中心)
  • Registry:服务注册与发现的注册中心。(Registry本身时一个应用,服务方启动时会把自己的信息在注册中心注册,dubbox推荐使用zookeeper做为注册中心)
  • Monitor: 统计服务的调用次调和调用时间的监控中心。
  • Container: 服务运行容器。

调用关系说明:

  1. 服务容器负责启动,加载,运行服务提供者。
  2. 服务提供者在启动时,向注册中心注册自己提供的服务。(服务方启动时会把自己的信息在注册中心注册)
  3. 服务消费者在启动时,向注册中心订阅自己所需的服务。(通过订阅服务–>找到注册中心)
  4. 注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推
    送变更数据给消费者。
  5. 服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,
    如果调用失败,再选另一台调用。
  6. 服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计
    数据到监控中心。

Dubbo+zookeeper环境配置,请分别参考以下博客:

Zookeeper集群环境搭建
Dubbo

搭建服务提供者

服务提供者Dubbo配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:dubbo="http://code.alibabatech.com/schema/dubbo" xmlns:mvc="http://www.springframework.org/schema/mvc"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
        http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
	<!--服务提供方:当前应用名称,一般同项目名(此名称给注册中心识别) -->
	<dubbo:application name="dubboxdemo-service" />
	<!--配置registry注册中心,protocol="注册中心为zookeeper";address=zookeeper协议地址,(zookeeper配置的)Ip地址加默认端口号2181, 服务端向注册中心暴露注册自己提供的服务,如果zookeeper集群用逗号分隔 -->
	<dubbo:registry protocol="zookeeper" address="192.168.79.130:2181,192.168.79.131:2181,192.168.79.128:2181" />
	<!-- 服务端暴露接口配置: interface:接口全定类名 ref:指定接口实现类 check:检查服务提供者是否存在,true报错,false忽略 timeout:连接超时(毫秒)-->
	<dubbo:service interface="com.dubbox.service.DubboxService"
		id="dubboxService" ref="dubboxServiceImpl" cache="false" timeout="2000"/>
	<bean id="dubboxServiceImpl" class="com.dubbox.service.impl.DubboxServiceImpl"></bean>
	
	<!--dubbo配置包扫描,使用alibaba的@service 注解,这里包扫描会自动对外暴露service接口,给消费方调用 (不推荐使用,这样会暴露所有service,但是实际并不需要暴露所有service) -->
	<!-- <dubbo:annotation package="cn.itcast.dubboxdemo.service" /> -->
	
	<!-- spring 注解扫描 -->
	<context:component-scan base-package="com.dubbox"></context:component-scan>
</beans>

服务提供者暴露服务接口

package com.dubbox.service;

public interface DubboxService {

	public String getUsername();

}

服务具体实现类

package com.dubbox.service.impl;

import com.alibaba.dubbo.config.annotation.Service;
import com.dubbox.service.DubboxService;

@Service
public class DubboxServiceImpl implements DubboxService {

	@Override
	public String getUsername() {
		// TODO Auto-generated method stub
		return "zhangsan";
	}

}

在服务方的dubbo配置,其中使用alibaba.dubbox注解的@service,是具体服务逻辑的执行(service.impl),其接口serivice需要对外暴露,通过配置相同的注册中心地址,服务方会自动注册地址到zookeeper,同时对外暴露service接口,消费方通过配置的注册地址,和远程注入的service接口,就可以调用服务费为其提供服务!
当启动多个dubbox服务,会有端口冲突,需要自定义端口

<!--自定义访问dubbox端口,不能重复,默认端口20880 -->
<dubbo:protocol name="dubbo" port="20881"></dubbo:protocol>
服务调用者Dubbo配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:p="http://www.springframework.org/schema/p" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
	xsi:schemaLocation="
    http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.2.xsd
    http://www.springframework.org/schema/mvc
    http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
    http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd">


	<mvc:annotation-driven>
		<mvc:message-converters register-defaults="false">
			<bean class="org.springframework.http.converter.StringHttpMessageConverter">
				<constructor-arg value="UTF-8" />
			</bean>
		</mvc:message-converters>
	</mvc:annotation-driven>

	<!--服务提供方:当前应用名称,一般同项目名(此名称给注册中心识别) -->
	<dubbo:application name="dubboxdemo-web" />
	<!--配置registry注册中心,protocol="注册中心为zookeeper";address=zookeeper协议地址,(zookeeper配置的)Ip地址加默认端口号2181, 
		服务提供者向注册中心暴露注册自己提供的服务,如果zookeeper集群用逗号分隔 -->
	<dubbo:registry protocol="zookeeper"
		address="192.168.79.130:2181,192.168.79.131:2181,192.168.79.128:2181" />

<!--reference:服务调用者,interface:服务接口全路径, check:检查服务提供者是否存在,true报错,false忽略;loadbalance:负载均衡策略(轮询) cluster:集群容错配置(failover:默认设置,失败自动切换,重试其它服务) -->
	<dubbo:reference id="dubboxServiceImpl" interface="com.dubbox.service.DubboxService"
		check="true" loadbalance="roundrobin" cluster="failfast"/>
	
		<!-- 扫描dubbo注解  识别spring中dubbo注解-->
	<dubbo:annotation package="com.dubbox.controller" />
<!-- 	<bean id="dubboxController" class="com.dubbox.controller.DubboxController"> -->
<!-- 		<property name="dubboxService" ref="dubboxServiceImpl"></property> -->
<!-- 	</bean> -->

	<!-- spring 注解扫描 -->
	<context:component-scan base-package="com.dubbox.controller"></context:component-scan>

</beans>

dubbo配置如果放在spring监听的Listener中会出现的问题

问题:会出现Service接口远程注入为null的情况
原因:因为Spring容器和SpringMVC容器是父子关系

  1. Spring监听对象ContextLoaderListener是ServletContextListener(监听ServletContext创建和销毁)接口的实现类,当tomcat启动,为每一个项目分配ServletContext,Spring会把WebApplicationContext保存ServletContext域中,从而实现项目启动开始加载Spring配置
  2. Spring容器和Springmvc是父子容器关系,服务启动开始加载Spring容器配置的Bean,然后加载SpringMvc中配置的Bean,那么当@Reference 注解在 带有 @Controller 的类中使用的时候,默认@Controller的Bean 被加载到SpringMVC容器中,因为Spingmvc容器没有加载dubbo 的配置文件,而是被Spring容器加载了,从而导致@Reference 在SpringMVC容器中不能被解析,所以被@Reference 修饰的远程服务变量不能被注入成功,才会使引用的服务为空。@Reference 相当于给Controller 去 Set 一个属性。
    解决:
  3. 将@Reference远程注入接口对象,在Service层中引入,从而避免Springmvc无法识别
  4. 去掉web.xml中listener,将全部配置文件都放到springmvc中加载,这样只生成一个上下文。
  5. 在spring-mvc.xml和ApplicationContext都加入duboo的配置,这样虽然有了冗余,但是可以保证两个上下文。

服务调用方controller远程调用服务

package com.dubbox.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import com.alibaba.dubbo.config.annotation.Reference;
import com.dubbox.service.DubboxService;

@Controller
@RequestMapping("/test")
public class DubboxController {

	// 远程调用
	@Reference
	private DubboxService dubboxService;

	@RequestMapping("/getUname")
	@ResponseBody
	public String getUname() {
		if (dubboxService == null) {
			System.out.println("no");
		} else {
			System.out.println("yes");
		}

		String username = dubboxService.getUsername();
		return username;
	}

}

服务调用方Service接口(同服务提供者接口)

package com.dubbox.service;

public interface DubboxService {

	public String getUsername();

}

注:服务提供者/服务消费者需要相同的Service,可以把Service以jar包的形式在两个项目利用中mavenxxx传递依赖

发布了32 篇原创文章 · 获赞 53 · 访问量 2477

猜你喜欢

转载自blog.csdn.net/qq_41714882/article/details/103957898
今日推荐