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服务:

在这里插入图片描述
web即相当于dubbo的消费端(consumer),service相当于dubbo的服务端(provider),api为dubbo对外暴露的接口(interface)。

api端这里暴露的是接口与常用的配置项的注入:
在这里插入图片描述
先说一下Property的内容,因为自己需要在consumer与provider的@Configuration中使用这些配置类,而很多配置类是通用的,所以这里自己统一定义成了property的bean,然后采用@value的方式将属性值注入进来,这样在各个配置端采用注入的方式将这些配置Bean直接注入到@Configuration的配置类中,直接进行引用即可。
在这里插入图片描述
配置类(@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.zookeeper</groupId>
            <artifactId>zookeeper</artifactId>
            <exclusions>
                <exclusion>
                    <artifactId>log4j</artifactId>
                    <groupId>log4j</groupId>
                </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,问题解决。

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值