Spring学习之SpringMVC与Dubbo集成,消费端@Reference引用为NULL的问题

背景:

之前项目中一直使用dubbox,最近dubbo社区又开始进行维护,公司正好又有一个新项目启动,本来想用spring-boot,正好进行下相关学习,奈何领导这关没过,还是让用最原始的spring-xml的配置方式,但是spring社区已经推荐用java代码配置的方式取代xml,所以应该顺应时代的潮流,采用最新的spring配置dubbo的方式,关于spring-boot的学习只能在课下进行了。但是自己在按照相关教程配置好dubbo的结构后,发现消费端的@Reference注入的service总是为空。一开始自己以为dubbo的服务没有注册上,后来通过在服务端启动日志,查看到服务确确实实是已经注册进了zookeepe人,所以问题就是出在消费端调用上。

javaconfig方式配合dubbo服务:

Spring学习之SpringMVC与Dubbo集成,消费端@Reference引用为NULL的问题_第1张图片
web即相当于dubbo的消费端(consumer),service相当于dubbo的服务端(provider),api为dubbo对外暴露的接口(interface)。

api端这里暴露的是接口与常用的配置项的注入:
Spring学习之SpringMVC与Dubbo集成,消费端@Reference引用为NULL的问题_第2张图片
先说一下Property的内容,因为自己需要在consumer与provider的@Configuration中使用这些配置类,而很多配置类是通用的,所以这里自己统一定义成了property的bean,然后采用@value的方式将属性值注入进来,这样在各个配置端采用注入的方式将这些配置Bean直接注入到@Configuration的配置类中,直接进行引用即可。
Spring学习之SpringMVC与Dubbo集成,消费端@Reference引用为NULL的问题_第3张图片
配置类(@Configuration)中:
首先需要自动将这些Bean注入进来,

@Configuration
@ComponentScan(basePackages = {"com.baheal.drools.property"})

注意我们引入api的方式是在maven中通过dependency的方式引入进来的,所以在更改了api中的property的bean之后,必须重新编译生成,这样各个引用端才可以使用最新的api的jar。而后,配置类中即可正常使用这些配置项:

  @Bean
    public JedisPoolConfig jedisPoolConfig(RedisProperty property){
    }

好了,言归正传,讨论如何采用javaconfig的方式配置dubbo服务。

api端:

暴露接口:

  public interface QuotaEstimateService {
    public String testDubbo();
}

Provider端:

首先需要将接口实现:

 @Service
  public class QuotaEstimateServiceImpl implements QuotaEstimateService {
   @Override
    public String testDubbo() {
        return "dubbo 服务提供者";
    }
}

注意此处的@Service不是采用的Spring自己的注解,而是dubbo的@Service注解。

import com.alibaba.dubbo.config.annotation.Service;

而后需要进行配置类的相关设置:

@Configuration
@EnableDubbo(scanBasePackages = "com.baheal.drools.service.impl")
public class DubboConfig {

    @Bean
    public ProviderConfig providerConfig(){
        return new ProviderConfig();
    }

    @Bean
    public ApplicationConfig applicationConfig(){
        ApplicationConfig applicationConfig = new ApplicationConfig();
        applicationConfig.setName("estimate-service-impl");
        return applicationConfig;
    }

    @Bean
    public RegistryConfig registryConfig(){
        RegistryConfig registryConfig = new RegistryConfig();
        registryConfig.setAddress("zookeeper://127.0.0.1:2181");
        return registryConfig;
    }

    @Bean
    public ProtocolConfig protocolConfig(){
        ProtocolConfig protocolConfig = new ProtocolConfig();
        protocolConfig.setName("dubbo");
        protocolConfig.setPort(20880);
        return protocolConfig;
    }

@EnableDubbo标签负责扫描包下带有@service的类并将其发布到zookeeper之上,下面的4个bean则是dubbo的相关配置,设置好以后先启动本地zookeeper,然后服务端即可启动,然后就会将服务注册到zookeeper之上。
通过查看启动日志就会发现服务以及成功注册(若是显示dubbo没有logappender,则需要将dubbo本身的log4j的jar包剔除掉因为我本地采用的是logback,只要resources文件夹下含有logback.xml,便会自动加载。

<dependency>
            <groupId>org.apache.zookeepergroupId>
            <artifactId>zookeeperartifactId>
            <exclusions>
                <exclusion>
                    <artifactId>log4jartifactId>
                    <groupId>log4jgroupId>
                exclusion>
            exclusions>
        dependency>
2018-09-21 23:27:27 [RMI TCP Connection(127.0.0.1:2181)] INFO  org.apache.zookeeper.ClientCnxn - Socket connection established to 127.0.0.1/127.0.0.1:2181, initiating session
2018-09-21 23:27:27 [RMI TCP Connection(3)-127.0.0.1] INFO  com.alibaba.dubbo.registry.zookeeper.ZookeeperRegistry -  [DUBBO] Register: dubbo://192.168.8.27:20880/com.baheal.drools.service.QuotaEstimateService?anyhost=true&application=estimate-service-impl&dubbo=2.6.2&generic=false&interface=com.baheal.drools.service.QuotaEstimateService&methods=testDubbo,quotaEstimateQuota&pid=3608&revision=1.0-SNAPSHOT&side=provider&timestamp=1537543646427, dubbo version: 2.6.2, current host: 192.168.8.27

Consumer端:

之前自己采用的是如下的配置,将DubboConfig通过Spring的Configuration引入,即在

public class WebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

    private final static Logger logger = LoggerFactory.getLogger(WebAppInitializer.class);

    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class<?>[] { DubboConfig.class };
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class<?>[] { WebConfig.class };
    }

    @Override
    protected String[] getServletMappings() {
        return new String[]{ "/" };
    }

configuration:

@Configuration
@EnableDubbo(scanBasePackages = "com.baheal.drools.controller")
public class DubboConfig {
    @Bean
    public ApplicationConfig applicationConfig(){
        ApplicationConfig applicationConfig = new ApplicationConfig();
        applicationConfig.setName("estimate-web");
        return applicationConfig;
    }

    @Bean
    public ConsumerConfig consumerConfig(){
        ConsumerConfig consumerConfig = new ConsumerConfig();
        consumerConfig.setTimeout(6000);
        return consumerConfig;
    }

    @Bean
    public RegistryConfig registryConfig(){
        RegistryConfig registryConfig = new RegistryConfig();
        registryConfig.setAddress("zookeeper://127.0.0.1:2181");
        return registryConfig;
    }
}

然后在使用的controller里面通过@Reference的方式进行引入:

    @Reference
    QuotaEstimateService quotaEstimateService;

然而在用的过程中发现注入的QuotaEstimateService 一直为null,这个问题困扰了自己很久,在上班的时候一直没有进行解决,加了一会班也是没有思路,后来在公交车上用手机查询相关问题时忽然看见可能是springMVC与Dubbo的注解冲突的问题。@Reference注解实质上是将暴露的服务以@Bean的方式注入进来,而自己的@Reference是通过Spring的componentScan扫描进来的,而SpringMVC的Controller初始化发生在@Reference之前,这就导致注入进来的服务为空的问题。
所以

@EnableDubbo(scanBasePackages = "com.baheal.drools.controller")

这项自动扫描主要是将@Reference注册的dubbo服务以Bean的方式注入进来,所以该项扫描必须改为由WebConfig进行加载进来。

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = "com.baheal.drools.controller")
@Import({DubboConfig.class})
public class WebConfig extends WebMvcConfigurerAdapter {
}




@Configuration
@EnableDubbo(scanBasePackages = "com.baheal.drools.controller")
public class DubboConfig {
.................
}

然后启动Consumer端,Controller端的@Reference已经可以成功注入Dubbo的Service,问题解决。

你可能感兴趣的:(Spring)