NacosとZuulの動的ルーティング

16041 ワード

Nacos1.0.0 GAバージョンがやっと出てきました.その中の配置センターはルート情報を配置するのに非常に適しています.私たちはすべてのルート情報をNacosに配置し、変化があればすぐに変更したいと思っています.

サービスプロバイダの構築


このプロジェクトの注釈は簡単にテストインタフェースを提供し、自分を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-serverzuul_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の効果をテストできます.