温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

如何解决Spring自动注入失败的问题

发布时间:2021-05-12 14:25:07 来源:亿速云 阅读:762 作者:小新 栏目:开发技术

小编给大家分享一下如何解决Spring自动注入失败的问题,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!

Spring自动注入失败如何解决?

我有一个被Spring @Service注解的类(MileageFeeCalculator),它有一个用@Autowired注入的变量(rateService),但是当我用这个变量的时候,它显示为null。日志显示MileageFeeCalculator bean和MileageRateService bean都被创建了,但是当我调用service上的mileageCharge ()方法时,就会报NullPointerException错误。为什么Spring不能自动注入这个实例?

Controller:

@Controller
public class MileageFeeController {    
    @RequestMapping("/mileage/{miles}")
    @ResponseBody
    public float mileageFee(@PathVariable int miles) {
        MileageFeeCalculator calc = new MileageFeeCalculator();
        return calc.mileageCharge(miles);
    }
}

Service:

@Service
public class MileageFeeCalculator {

    @Autowired
    private MileageRateService rateService; // <--- should be autowired, is null

    public float mileageCharge(final int miles) {
        return (miles * rateService.ratePerMile()); // <--- throws NPE
    }
}

本应被注入Service但是并没有的类

@Service
public class MileageRateService {
    public float ratePerMile() {
        return 0.565f;
    }
}

为什么我调用GET /mileage/3这个请求的时候,会报这样的错误:

java.lang.NullPointerException: null
    at com.chrylis.example.spring_autowired_npe.MileageFeeCalculator.mileageCharge(MileageFeeCalculator.java:13)
    at com.chrylis.example.spring_autowired_npe.MileageFeeController.mileageFee(MileageFeeController.java:14)
    ...

回答

@Autowired注解的字段为null是因为,Spring无法获取你用new关键字创建的类,也无法自动注入它。

Spring Ioc容器有三个主要的逻辑组件:应用程序可以使用的注册表(ApplicationContext);通过把依赖项与上下文中的bean匹配,将依赖的对象注入的配置器系统;以及一个依赖解析器,它可以查看许多不同bean的配置,并确定如何按必要的顺序实例化和配置它们。

Ioc容器并没有魔法,除非你以某种方式通知它,否则它无法获取Java对象。当你调用new创建对象时,JVM实例化新对象,并将其中一个副本交给你——它并不经历Spring的配置过程。有三种方法可以配置bean实例。

注入你的bean

最好的选择是让Spring注入所有的bean;这样的代码量会最少并且也最容易维护。为了使注入如你所愿,需要把MileageFeeCalculator像这样注入。

@Controller
public class MileageFeeController {

    @Autowired
    private MileageFeeCalculator calc;

    @RequestMapping("/mileage/{miles}")
    @ResponseBody
    public float mileageFee(@PathVariable int miles) {
        return calc.mileageCharge(miles);
    }
}

如果你需要为不同的请求都创建一个类的新实例,可以通过Spring注解的scopes实现。

使用@Configurable

如果你真的需要把new出来的对象保存进行注入,那可以使用Spring的@Configurable注解,通过使用AOP在编译时织入你的对象中。这种方法将代码插入到对象的构造函数中,提醒Spring这个对象正在被创建,这样Spring就能够配置新实例了。这需要你添加一些配置信息。并打开Spring的运行时配置处理器。Roo Active Record系统使用这种方法来允许实体的new实例获取注入的必要持久性信息。

@Service
@Configurable
public class MileageFeeCalculator {

    @Autowired
    private MileageRateService rateService;

    public float mileageCharge(final int miles) {
        return (miles * rateService.ratePerMile());
    }
}

手动查找bean:不推荐

这种方法只适用于在特殊情况下与遗留代码对接。创建一个Spring可以自动注入并且遗留代码也能调用的单例适配器总是可取的,但是也许可以直接向spring application context请求bean实例。

为了做到这点,你需要一个类,该类提供了对ApplicationContext对象的引用

@Component
public class ApplicationContextHolder implements ApplicationContextAware {
    private static ApplicationContext context;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        context = applicationContext;   
    }

    public static ApplicationContext getContext() {
        return context;
    }
}

之后你的遗留代码就可以调用getContext()方法获取所需的bean实例了。

@Controller
public class MileageFeeController {    
    @RequestMapping("/mileage/{miles}")
    @ResponseBody
    public float mileageFee(@PathVariable int miles) {
        MileageFeeCalculator calc = ApplicationContextHolder.getContext().getBean(MileageFeeCalculator.class);
        return calc.mileageCharge(miles);
    }
}

以上是“如何解决Spring自动注入失败的问题”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注亿速云行业资讯频道!

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI