问题描述:作为菜鸟,在学习SpringBoot过程中,想着看一遍老师的视频,自己手敲,能够让自己印象深刻一点,结果问题就来了。@Reference注解的引用报空指针异常。折磨了两个多小时,查阅了无数资料,最终发现自己对IOC理解还不够透彻,导致了此次这种本可以避免的错误。
本文便是将过程记录下来,警醒自己,如果有大神发现描述有误,请纠正,谢谢。
使用的环境如下:
- JDK1.8
- SpringBoot 2.2.5
- Dubbo 0.2.0(Alibaba)
- Zookeeper Docker中拉取的最新版(3.5.6)
先附上服务提供者和服务消费者目录结构

注意:由于消费者中使用@Reference注解,这个注解是通过全限定类名通过反射机制创建相应的实例对象,所以在消费者目录结构中必须有与提供者提供服务接口一致的目录结构。
附上服务提供者的代码
- 启动类
//@EnableDubbo等价于在配置文件中配置dubbo.scan.base-packages
//如果不配置可能报错: No provider available from registry
@EnableDubbo
@SpringBootApplication
public class ProviderTicketApplication {
public static void main(String[] args) {
SpringApplication.run(ProviderTicketApplication.class, args);
}
}
- 服务提供的接口和接口实现类
public interface TicketService {
public String getTicket();
}
//这里一定要引入dubbo的Service注解,Dubbo会将此注解实现类的接口类注册以全限定类名到zookeeper中
import com.alibaba.dubbo.config.annotation.Service;
import com.ittx.ticket.service.TicketService;
import org.springframework.stereotype.Component;
@Component//Dubbo的Service不具有将此类配置为Bean对象的功能,所以需要加此注解
@Service(version = "${dubbo.application.version}")
public class TicketServiceImpl implements TicketService {
@Override
public String getTicket() {
return "《厉害了,我的国》";
}
}
- 服务提供者配置文件
# 名字必须与项目名一致
dubbo.application.name=provider-ticket
# 下面两条其实可以写成一条:dubbo.registry.address=zookeeper://192.168.160.128:2181
dubbo.registry.address=192.168.160.128:2181
dubbo.registry.protocol=zookeeper
dubbo.protocol.name=dubbo
dubbo.protocol.port=20880
# 扫描需要注册服务的接口的包名,这个包名+接口名就组成了全限定类名
dubbo.scan.base-packages=com.ittx.ticket.service
dubbo.consumer.check=false
dubbo.application.version=3
消费者代码:
==消费者代码中的TickerService与提供者代码一样 ==
- 消费者服务
import com.alibaba.dubbo.config.annotation.Reference;
import com.ittx.ticket.service.TicketService;
import org.springframework.stereotype.Service;
@Service
public class ConsumerService {
@Reference(check = false, version = "3")//远程调用,默认使用TicketService这个注册名。远程服务里有这个服务
TicketService ticketService;
public void hello(){
String ticket = ticketService.getTicket();
System.out.println("买到票了" + ticket);
}
}
- 消费者配置文件
dubbo.registry.address=192.168.160.128:2181
dubbo.application.name=comsumer
dubbo.registry.protocol=zookeeper
# server.port=8081
- 测试代码(问题就出在这里)
@SpringBootTest
class ComsumerApplicationTests {
@Autowired
ConsumerService consumerService;
@Test
void contextLoads() {
//问题出现在下面这行代码:
//ConConsumerService service = new ConsumerService();
//service.hello();
consumerService.hello();
}
}
上面由于我按照传统的创建对象的思想,没有使用依赖注入,导致新创建了一个ConsumerService对象,这种方式是在SpringBoot框架之外的,完全避开了IOC容器,而@Reference又属于SpringBoot框架内。新创建的service里面并执行@Reference注解,里面的ticketService成员变量其实就是null。
收获:
- 今天查阅资料的时候看见很多不错的博客,解释了SpringMVC中可能真正存在@Reference为空的情况。请查阅dubbo在controller中reference注解为空的问题深度解析,dubbo 使用zookeeper 出现 Dubbo客户端调用报错NullPointerException
- 学会了查看zookeeper文件查看注册的服务:
docker exec -it 容器ID /bin/bash #进入相应文件
./bin/zkCli.sh #查看文件
ls /dubbo #可以查看注册的服务

- 如果控制台有报错:Will not attempt to authenticate using SASL (unknown error)。也有可能是zookeeper地址映射的问题。可以去hosts文件中加入映射:服务器IP docker中的容器名(这样消费者和提供者相应的地址的属性值需要将IP地址改为容器名)
版权声明:本文为taxi1993原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。