一、soa簡單介紹
1)面向服務的架構(SOA)是一個組件模型,它將應用程序的不同功能單元(稱為服務)通過這些服務之間定義良好的接口和契約聯系起來。SOA是解決復雜業務模塊,提高擴展性,維護性,可伸縮性的最基本方案。我們的業務服務可以根據需求通過網絡對松散耦合的粗粒度應用組件進行分布式部署、組合和使用。服務層是SOA的基礎,可以直接被應用調用,不同的服務通過不同的團隊來維護。
有效的業務分割是soa基礎中的基礎
2)對於大型網站常見的架構模式:
分層:便於維護,各個模塊之間有一定的獨立性,屬於橫向切分,常見的為三層架構
分割:屬於縱向切分,當項目業務復雜,功能越來越多時,可以將業務功能進行拆分,常見的是拆分成項目,部署在不同的服務器上,每個模塊由獨立的團隊進行維護
分布式:分割與分層一個主要目的就是將切分后的模塊進行分布式部署,分布式意味着使用更多機器完成相同的功能,機器多意味着cpu,內存也多,處理計算的能力與並發能力也就越大
集群:集群為了使用更多的機器來處理相同的服務,用以提高性能。
3)常用的分布式方案:
分布式應用和服務:最常見的方式,即將不同的業務服務部署到不同的機器上
分布式靜態資源:動靜分離。將css資源或者圖片獨立進行分布式部署
分布式存儲:最常見的是數據庫分布式部署,來分割海量的數據
分布式計算:比如說hadoop等大數據處理方案
4)分布式帶來的問題:
分布式意味着服務調用必須通過網絡,網絡帶寬的問題是服務之間調用必不可免的問題
多台服務器會存在數據一致性的問題以及分布式事務問題
服務器越多宕機的概率也就越大
維護成本以及開發成本的增加
5)注意分布式一定是根據需求及業務量而定的,切不可為了分布式而分布式
6)注冊中心:管理服務地址,並提供調用者訪問的組件,常見的有zookeeper eureka redis等
二、soa基本架構圖(以spring-cloud為例)
1.注冊中心: 保存服務提供方暴露的服務信息,常見的注冊中心有zookeeper eureka
2.服務提供方:提供服務者
3.消費方:當需要調用遠程服務接口時,必須在注冊中心發現服務找到服務提供者,從而進行遠程方法調用
三、SpringCloud項目構建
Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智能路由,微代理,控制總線)。使用Spring Cloud開發人員可以快速地支持實現這些模式的服務和應用程序。
1、通過訪問http://start.spring.io來構建spring-cloud項目
注意:在Search for dependencies里添加最基本的soa依賴項: web EurekaServer Eureka Discovery
2、通過IDEA工具導入下載好的項目並依次創建一下幾個項目模塊:
這里說明一下:
register-center:注冊中心
service-api:接口契約
service-provider:服務提供方
service-consumer:服務消費方
四.實現步驟
1、實現注冊中心
application.yml配置:

server: port: 8000 eureka: client: register-with-eureka: false fetch-registry: false service-url: defaultZone: http://localhost:8000/eureka/
注意:在默認設置下,Eureka服務注冊中心也會將自己作為客戶端來嘗試注冊它自己,所以我們需要禁用它的客戶端注冊行為。
register-with-eureka: 代表是否向eureka服務注冊
fetch-registry: 是否從eureka注冊中心拉取信息
service-url: eureka的服務地址
編寫程序入口類,通過@EnableEurekaServer 激活Eureka服務器相關配置:

package com.bdqn.springcloud.study.provider; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; @EnableEurekaServer @SpringBootApplication public class RegisterCenterProvider { public static void main(String[] args) { SpringApplication.run(RegisterCenterProvider.class, args); } }
2 實現service-api
定義暴露服務的接口契約

package com.bdqn.springcloud.study.api; import com.bdqn.springcloud.study.dto.UserDTO; /** * UserService測試接口 * * @author chen.nie * @date 2017/11/13 */ public interface UserService { UserDTO findUser(); }
定義DTO

package com.bdqn.springcloud.study.dto; public class UserDTO { private Integer id; private String name; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
3 實現服務提供方:
gradle配置:先依賴service-api

dependencies{ compile project(":service-api") }
application-yml的配置:

server: port: 8001 spring: application: name: "service-provider-demo" eureka: instance: prefer-ip-address: true client: service-url: defaultZone: http://localhost:8000/eureka/
注意:這里面要配置應用名稱 注冊中心的服務地址
接口實現類:

package com.bdqn.springcloud.study.provider.impl; import com.bdqn.springcloud.study.api.UserService; import com.bdqn.springcloud.study.dto.UserDTO; import org.springframework.stereotype.Service; @Service("userService") public class UserServiceImpl implements UserService { @Override public UserDTO findUser() { UserDTO userDTO = new UserDTO(); userDTO.setName("張三豐"); userDTO.setId(10); return userDTO; } }
Controller:

package com.bdqn.springcloud.study.provider.controller; import com.bdqn.springcloud.study.api.UserService; import com.bdqn.springcloud.study.dto.UserDTO; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; @RestController public class UserController { @Resource private UserService userService; @GetMapping("/user") public UserDTO getUser() { return this.userService.findUser(); } }
啟動類:

package com.bdqn.springcloud.study.provider; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; @EnableDiscoveryClient @SpringBootApplication public class ServiceProvider { public static void main(String[] args) { SpringApplication.run(ServiceProvider.class, args); } }
@EnableDiscoveryClient:用於啟用發現客戶端實現的注釋
打來瀏覽器訪問:http://localhost:8000
我們看到剛才的接口服務已經成功注冊至Eureka中心
4.實現服務消費方
gradle配置:先依賴service-api

dependencies{ compile project(":service-api") compile 'org.springframework.cloud:spring-cloud-starter-eureka' }
application.yml配置:

server: port: 8002 spring: application: name: "service-consumer-demo" eureka: instance: prefer-ip-address: true client: service-url: defaultZone: http://localhost:8000/eureka/
編寫Controller:

package com.bdqn.springcloud.study.consumer.controller; import com.bdqn.springcloud.study.dto.UserDTO; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cloud.client.loadbalancer.LoadBalancerClient; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate; @RestController public class ConsumerController { @Autowired private RestTemplate restTemplate; @Autowired private LoadBalancerClient loadBalancerClient; @GetMapping("/getUser") public String getUser() { ResponseEntity<UserDTO> responseEntity = restTemplate.getForEntity("http://SERVICE-PROVIDER-DEMO/user", UserDTO.class); UserDTO userDTO = responseEntity.getBody(); return userDTO.getName(); } }
注意我們通過http://service-provider-demo/user/ 指定service-provider的application name,讓系統從注冊中心去發現服務。
5.編寫啟動項:

package com.bdqn.springcloud.study.consumer; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.client.loadbalancer.LoadBalanced; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; import org.springframework.context.annotation.Bean; import org.springframework.web.client.RestTemplate; @SpringBootApplication @EnableDiscoveryClient public class ServiceConsumer { @Bean @LoadBalanced RestTemplate restTemplate() { return new RestTemplate(); } public static void main(String[] args) { SpringApplication.run(ServiceConsumer.class, args); } }
在啟動項里,我們配置了一個RestTemplate 主意 @LoadBalanced注解修飾的restTemplate,具備負載均衡能力的restTemplate,即每次都會用負載均衡算法,從可用服務列表中,挑一個進行調用。
啟動完畢時,我們發現注冊中心中多了一個服務:
當我們訪問http://localhost:8002/getUser得到如下顯示就說明我們的服務運行成功了:
當停止register-center時,我們發現該訪問地址依然能夠拿到結果,說明消費端本地是有緩存的