NacosとZuulの動的ルーティング
16041 ワード
Nacos1.0.0 GAバージョンがやっと出てきました.その中の配置センターはルート情報を配置するのに非常に適しています.私たちはすべてのルート情報をNacosに配置し、変化があればすぐに変更したいと思っています.
このプロジェクトの注釈は簡単にテストインタフェースを提供し、自分をNacosに登録し、Pomファイルは以下の通りです.
プロファイル
メイン実行クラスを作成し、コメントを打つだけでいいです.
これで、サービスプロバイダは完了しました.これから本格的なZuul統合を開始します
EnableZuulProxy注釈はZuulゲートウェイサービスをオープンしました
私たちの構成はnacosに存在し、dataが必要です.idとgroup_id,便利のために,この2つのパラメータを静的クラスの定数に入れ,ここではインタフェースを用いて
nacos構成で構成を確立し、data_idとgroup_idはそれぞれ
コンテンツ領域は
テストは、テストを開始し、nacosの構成を変更して再テストすることができ、動的ルーティングが実現されていることがわかります.
複数のProviderをオンにしてLBの効果をテストできます.
サービスプロバイダの構築
このプロジェクトの注釈は簡単にテストインタフェースを提供し、自分をNacosに登録し、Pomファイルは以下の通りです.
UTF-8
1.8
org.springframework.boot
spring-boot-starter-parent
2.0.3.RELEASE
org.springframework.cloud
spring-cloud-starter-alibaba-nacos-discovery
0.2.1.RELEASE
org.springframework.cloud
spring-cloud-dependencies
Finchley.RELEASE
pom
import
org.springframework.boot
spring-boot-starter-web
org.springframework.cloud
spring-cloud-starter-alibaba-nacos-discovery
プロファイル
application.properties
の作成server.port=18080
spring.application.name=service-provider
spring.cloud.nacos.discovery.server-addr=192.168.5.126:80
メイン実行クラスを作成し、コメントを打つだけでいいです.
@SpringBootApplication
@EnableDiscoveryClient
public class ProviderApplication {
public static void main(String[] args) {
SpringApplication.run(ProviderApplication.class, args);
}
@RestController
class EchoController {
@RequestMapping(value = "/echo/{string}", method = RequestMethod.GET)
public String echo(@PathVariable String string) {
return "receive " + string;
}
}
}
これで、サービスプロバイダは完了しました.これから本格的なZuul統合を開始します
Zuulプロジェクトの構築
Pomファイル
UTF-8
1.8
org.springframework.boot
spring-boot-starter-parent
2.0.3.RELEASE
org.springframework.boot
spring-boot-starter-actuator
org.springframework.boot
spring-boot-starter-web
org.springframework.cloud
spring-cloud-starter-netflix-zuul
com.alibaba
fastjson
1.2.47
org.springframework.cloud
spring-cloud-starter-alibaba-nacos-discovery
0.2.1.RELEASE
com.alibaba.nacos
nacos-client
org.springframework.cloud
spring-cloud-starter-alibaba-nacos-config
0.2.1.RELEASE
com.alibaba.nacos
nacos-client
com.alibaba.nacos
nacos-spring-context
0.2.3-RC1
com.alibaba.nacos
nacos-client
1.0.0
org.springframework.cloud
spring-cloud-dependencies
Finchley.RELEASE
pom
import
spring-milestones
Spring Milestones
https://repo.spring.io/libs-milestone
false
org.springframework.boot
spring-boot-maven-plugin
プロファイルの作成
bootstrap.properties
nacos.address=192.168.5.126:80
spring.cloud.nacos.discovery.server-addr=${nacos.address}
spring.cloud.nacos.config.server-addr=${nacos.address}
spring.application.name: zuul-server
server.port: 8888
メイン実行クラスの作成
@SpringBootApplication
@EnableDiscoveryClient
@EnableZuulProxy
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
EnableZuulProxy注釈はZuulゲートウェイサービスをオープンしました
静的クラス
私たちの構成はnacosに存在し、dataが必要です.idとgroup_id,便利のために,この2つのパラメータを静的クラスの定数に入れ,ここではインタフェースを用いて
public interface Constant {
public static final String NACOS_DATA_ID="zuul-server";
public static final String NACOS_GROUP_ID="zuul_route";
}
構成クラス-nacos構成サーバ
@Configuration
public class NacosServerConfig {
@Value("${spring.cloud.nacos.config.server-addr:127.0.0.1:8848}")
private String serverAddr;
@Autowired
NewZuulRouteLocator routeLocator;
@Autowired
ApplicationEventPublisher publisher;
@Bean
public ConfigService configService(){
Properties properties = new Properties();
properties.put(PropertyKeyConst.SERVER_ADDR, serverAddr);
try {
ConfigService configService = NacosFactory.createConfigService(properties);
configService.addListener(NACOS_DATA_ID, NACOS_GROUP_ID, new Listener() {
@Override
public Executor getExecutor() {
// MQ
return null;
}
@Override
public void receiveConfigInfo(String configInfo) {
System.out.println("Nacos !");
// !!!
RoutesRefreshedEvent routesRefreshedEvent = new RoutesRefreshedEvent(routeLocator);
publisher.publishEvent(routesRefreshedEvent);
}
});
return configService;
} catch (NacosException e) {
e.printStackTrace();
}
return null;
}
}
構成クラス-zul構成
/**
*
*/
@Configuration
public class NewZuulConfig {
@Autowired
private ZuulProperties zuulProperties;
@Autowired
private ServerProperties serverProperties;
/**
*
* :
*
* @param:
* @return:
* @auther: tangshun
* @date: 2019/4/17 20:18
*/
@Bean
public NewZuulRouteLocator routeLocator() {
NewZuulRouteLocator routeLocator = new NewZuulRouteLocator(
this.serverProperties.getServlet().getServletPrefix(), this.zuulProperties);
return routeLocator;
}
@Bean
public ApplicationListener zuulRefreshRoutesListener() {
return new ZuulRefreshListener();
}
}
Zuulリフレッシュリスナー
/**
* @ClassName ZuulRefreshListener
* @Author Tangshun
* @Description //TODO
* @Date 10:42 2019/4/18
* @Version 1.0.0
**/
public class ZuulRefreshListener implements ApplicationListener {
@Autowired
private ZuulHandlerMapping zuulHandlerMapping;
private HeartbeatMonitor heartbeatMonitor = new HeartbeatMonitor();
@Override
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof ContextRefreshedEvent
|| event instanceof RefreshScopeRefreshedEvent
|| event instanceof RoutesRefreshedEvent) {
// , , ,
this.zuulHandlerMapping.setDirty(true);
}else if (event instanceof HeartbeatEvent) {
if (this.heartbeatMonitor.update(((HeartbeatEvent) event).getValue())) {
this.zuulHandlerMapping.setDirty(true);
}
}
}
}
コアクラス
public class NewZuulRouteLocator extends SimpleRouteLocator implements RefreshableRouteLocator {
@Autowired
private ZuulProperties properties;
@Autowired
private PropertiesAssemble propertiesAssemble;
public NewZuulRouteLocator(String servletPath, ZuulProperties properties) {
super(servletPath, properties);
this.properties = properties;
}
@Override
public void refresh() {
doRefresh();
}
@Override
protected Map locateRoutes() {
LinkedHashMap routesMap = new LinkedHashMap();
// application.properties
routesMap.putAll(super.locateRoutes());
// Nacos
routesMap.putAll(propertiesAssemble.getProperties());
//
LinkedHashMap values = new LinkedHashMap<>();
for (Map.Entry entry : routesMap.entrySet()) {
String path = entry.getKey();
// Prepend with slash if not already present.
if (!path.startsWith("/")) {
path = "/" + path;
}
if (StringUtils.hasText(this.properties.getPrefix())) {
path = this.properties.getPrefix() + path;
if (!path.startsWith("/")) {
path = "/" + path;
}
}
values.put(path, entry.getValue());
}
return values;
}
}
エンティティークラス
public class ZuulRouteEntity {
/**
* The ID of the route (the same as its map key by default).
*/
private String id;
/**
* The path (pattern) for the route, e.g. /foo/**.
*/
private String path;
/**
* The service ID (if any) to map to this route. You can specify a
* physical URL or a service, but not both.
*/
private String serviceId;
/**
* A full physical URL to map to the route. An alternative is to use a
* service ID and service discovery to find the physical address.
*/
private String url;
/**
* Flag to determine whether the prefix for this route (the path, minus
* pattern patcher) should be stripped before forwarding.
*/
private boolean stripPrefix = true;
/**
* Flag to indicate that this route should be retryable (if supported).
* Generally retry requires a service ID and ribbon.
*/
private Boolean retryable;
private String apiName;
private Boolean enabled;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path;
}
public String getServiceId() {
return serviceId;
}
public void setServiceId(String serviceId) {
this.serviceId = serviceId;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public boolean isStripPrefix() {
return stripPrefix;
}
public void setStripPrefix(boolean stripPrefix) {
this.stripPrefix = stripPrefix;
}
public Boolean getRetryable() {
return retryable;
}
public void setRetryable(Boolean retryable) {
this.retryable = retryable;
}
public String getApiName() {
return apiName;
}
public void setApiName(String apiName) {
this.apiName = apiName;
}
public Boolean getEnabled() {
return enabled;
}
public void setEnabled(Boolean enabled) {
this.enabled = enabled;
}
}
アセンブリクラス
@Component
public class PropertiesAssemble{
@Autowired
private ConfigService configService;
public Map getProperties() {
Map routes = new LinkedHashMap<>();
List results = listenerNacos(NACOS_DATA_ID,NACOS_GROUP_ID);
for (ZuulRouteEntity result : results) {
if (StringUtils.isBlank(result.getPath())
/*|| org.apache.commons.lang3.StringUtils.isBlank(result.getUrl())*/) {
continue;
}
ZuulRoute zuulRoute = new ZuulRoute();
try {
BeanUtils.copyProperties(result, zuulRoute);
} catch (Exception e) {
}
routes.put(zuulRoute.getPath(), zuulRoute);
}
return routes;
}
private List listenerNacos (String dataId, String group) {
try {
String content = configService.getConfig(dataId, group, 5000);
System.out.println(" Nacos :" + content);
return JSONObject.parseArray(content, ZuulRouteEntity.class);
} catch (NacosException e) {
e.printStackTrace();
}
return new ArrayList<>();
}
}
nacos構成
nacos構成で構成を確立し、data_idとgroup_idはそれぞれ
zuul-server
とzuul_route
[画像アップロード失敗...(image-8 f 511 f-158663873510)]コンテンツ領域は
[
{
"enable":true,
"id":"baidu",
"path":"/baidu/**",
"retryable":false,
"stripPrefix":true,
"url":"http://www.baidu.com"
}, {
"enable":true,
"id":"163",
"path":"/163/**",
"retryable":false,
"stripPrefix":true,
"url":"https://www.163.com"
},
{
"enable":true,
"id":"service-provider",
"serviceId":"service-provider",
"path":"/provider/**",
"retryable":false,
"stripPrefix":true
}
]
テストは、テストを開始し、nacosの構成を変更して再テストすることができ、動的ルーティングが実現されていることがわかります.
複数のProviderをオンにしてLBの効果をテストできます.