Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/jquery-ui/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 为什么我的Spring@Autowired字段为空?_Java_Spring_Null_Nullpointerexception_Autowired - Fatal编程技术网

Java 为什么我的Spring@Autowired字段为空?

Java 为什么我的Spring@Autowired字段为空?,java,spring,null,nullpointerexception,autowired,Java,Spring,Null,Nullpointerexception,Autowired,注意:这是一个常见问题的标准答案 我有一个Spring@Service类(MileageFeeCalculator),它有一个@Autowired字段(rateService),但当我尝试使用它时,该字段是null。日志显示,mileageFeeCaulatorbean和mileageGateServicebean都在创建中,但是每当我尝试在我的服务bean上调用mileageCharge方法时,我都会得到一个NullPointerException。为什么Spring没有在现场自动布线 控制器

注意:这是一个常见问题的标准答案

我有一个Spring
@Service
类(
MileageFeeCalculator
),它有一个
@Autowired
字段(
rateService
),但当我尝试使用它时,该字段是
null
。日志显示,
mileageFeeCaulator
bean和
mileageGateService
bean都在创建中,但是每当我尝试在我的服务bean上调用
mileageCharge
方法时,我都会得到一个
NullPointerException
。为什么Spring没有在现场自动布线

控制器类:

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

@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
    }
}
当我尝试
获取/里程/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
创建的
mileAgeCalculator
的副本,也不知道如何自动连线它

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

IoC容器并不神奇,除非您以某种方式通知它,否则它无法了解Java对象。当您调用
new
时,JVM会实例化新对象的一个副本,并直接将其交给您——它从未经历过配置过程。有三种方法可以配置bean

我已经发布了所有这些代码,使用SpringBoot启动,在;您可以查看每种方法的完整运行项目,以了解使其工作所需的一切标记为
NullPointerException

注射你的豆子 最好的选择是让Spring自动连接所有bean;这需要最少的代码,并且是最容易维护的。要使自动布线按您所希望的方式工作,还可以像下面这样自动布线
mileagefeeculator

@Controller
public class MileageFeeController {

    @Autowired
    private MileageFeeCalculator calc;

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

    @Autowired
    private MileageRateService rateService; // <--- will be autowired when constructor is called

    public MileageFeeCalculator() {
        SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this)
    }

    public float mileageCharge(final int miles) {
        return (miles * rateService.ratePerMile()); 
    }
}
MyBean myBean = (MyBean)SpringUtils.ctx.getBean(MyBean.class);
ApplicationContext context =
    new ClassPathXmlApplicationContext(new String[] {
        "common.xml",
        "token.xml",
        "pep-config.xml" });
    TokenInitializer ti = context.getBean(TokenInitializer.class);
如果您需要为不同的请求创建服务对象的新实例,您仍然可以使用注入

通过注入
@mileageCalculator
服务对象工作的标记:

使用@Configurable 如果确实需要使用
new
创建的对象进行自动连接,则可以插入对象。这种方法将代码插入到对象的构造函数中,提醒Spring正在创建它,以便Spring可以配置新实例。这需要在构建中进行一些配置(例如使用
ajc
进行编译)并启用Spring的运行时配置处理程序(
@enablespringconfigulated
,使用JavaConfig语法)。Roo活动记录系统使用这种方法来允许实体的
新的
实例获得必要的持久性信息

@Service
@Configurable
public class MileageFeeCalculator {

    @Autowired
    private MileageRateService rateService;

    public float mileageCharge(final int miles) {
        return (miles * rateService.ratePerMile());
    }
}
通过在服务对象上使用
@Configurable
工作的标记:

手动bean查找:不推荐 这种方法仅适用于在特殊情况下与遗留代码接口。几乎总是最好创建一个单例适配器类,Spring可以自动连接,遗留代码可以调用,但也可以直接向Spring应用程序上下文请求bean

为此,您需要一个类,Spring可以向该类提供对
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上下文中手动查找服务对象来工作:

如果您没有编写web应用程序,请确保完成@Autowiring的类是Springbean。通常,spring容器不会知道我们可能认为是Springbean的类。我们必须告诉Spring容器我们的Spring课程

这可以通过在appln Context或中配置来实现。更好的方法是将类注释为@Component,请不要使用新操作符创建注释类。 请确保您从以下Appln上下文中获取它

@Component
public class MyDemo {


    @Autowired
    private MyService  myService; 

    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
            System.out.println("test");
            ApplicationContext ctx=new ClassPathXmlApplicationContext("spring.xml");
            System.out.println("ctx>>"+ctx);

            Customer c1=null;
            MyDemo myDemo=ctx.getBean(MyDemo.class);
            System.out.println(myDemo);
            myDemo.callService(ctx);


    }

    public void callService(ApplicationContext ctx) {
        // TODO Auto-generated method stub
        System.out.println("---callService---");
        System.out.println(myService);
        myService.callMydao();

    }

}

另一个解决方案是打电话:
SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this)

要像这样创建里程数计算器构造函数,请执行以下操作:

@Controller
public class MileageFeeController {

    @Autowired
    private MileageFeeCalculator calc;

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

    @Autowired
    private MileageRateService rateService; // <--- will be autowired when constructor is called

    public MileageFeeCalculator() {
        SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this)
    }

    public float mileageCharge(final int miles) {
        return (miles * rateService.ratePerMile()); 
    }
}
MyBean myBean = (MyBean)SpringUtils.ctx.getBean(MyBean.class);
ApplicationContext context =
    new ClassPathXmlApplicationContext(new String[] {
        "common.xml",
        "token.xml",
        "pep-config.xml" });
    TokenInitializer ti = context.getBean(TokenInitializer.class);
@服务
公共类里程数计算器{
@自动连线
private MilWangerateService rateService;//我是Spring新手,但我发现了这个有效的解决方案。请告诉我这是一种不可取的方法

我在这个bean中使用Spring inject
applicationContext

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

@Component
public class SpringUtils {

    public static ApplicationContext ctx;

    /**
     * Make Spring inject the application context
     * and save it on a static variable,
     * so that it can be accessed from any point in the application. 
     */
    @Autowired
    private void setApplicationContext(ApplicationContext applicationContext) {
        ctx = applicationContext;       
    }
}
如果需要,也可以将此代码放在主应用程序类中

其他类可以这样使用它:

@Controller
public class MileageFeeController {

    @Autowired
    private MileageFeeCalculator calc;

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

    @Autowired
    private MileageRateService rateService; // <--- will be autowired when constructor is called

    public MileageFeeCalculator() {
        SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this)
    }

    public float mileageCharge(final int miles) {
        return (miles * rateService.ratePerMile()); 
    }
}
MyBean myBean = (MyBean)SpringUtils.ctx.getBean(MyBean.class);
ApplicationContext context =
    new ClassPathXmlApplicationContext(new String[] {
        "common.xml",
        "token.xml",
        "pep-config.xml" });
    TokenInitializer ti = context.getBean(TokenInitializer.class);
通过这种方式,应用程序中的任何对象都可以获得任何bean(也可以通过
new
)和静态方式

您的问题是新的(java风格的对象创建)

通过注释
@服务
@组件
@配置
bean在
当服务器启动时Spring的应用程序上下文。但是当我们创建对象时 使用新操作符时,对象未在已创建的应用程序上下文中注册。例如,我使用的Employee.java类

看看这个:

public class ConfiguredTenantScopedBeanProcessor implements BeanFactoryPostProcessor {

@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
    String name = "tenant";
    System.out.println("Bean factory post processor is initialized"); 
    beanFactory.registerScope("employee", new Employee());

    Assert.state(beanFactory instanceof BeanDefinitionRegistry,
            "BeanFactory was not a BeanDefinitionRegistry, so CustomScope cannot be used.");
    BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;

    for (String beanName : beanFactory.getBeanDefinitionNames()) {
        BeanDefinition definition = beanFactory.getBeanDefinition(beanName);
        if (name.equals(definition.getScope())) {
            BeanDefinitionHolder proxyHolder = ScopedProxyUtils.createScopedProxy(new BeanDefinitionHolder(definition, beanName), registry, true);
            registry.registerBeanDefinition(beanName, proxyHolder.getBeanDefinition());
        }
    }
}

}

我曾经遇到过同样的问题,当时我还不太习惯国际奥委会的生活。我的一个bean的
@Autowired
字段在运行时为空

根本原因是,没有使用Spring IoC容器维护的自动创建bean(其
@Autowired
字段确实正确
@Autowired private Settings settings;
<context:component-scan base-package="some.shit"/>
//import org.junit.Test; // JUnit4
import org.junit.jupiter.api.Test; // JUnit5

@SpringBootTest
public class MyTests {
    ....
@SpringBootApplication
public class Application {
    @Autowired MyComponent comp;
}
@Component
public class MyComponent {
    @Autowired ComponentDAO dao;

    public MyComponent() {
        // dao is null here
    }

    @PostConstruct
    public void init() {
        // dao is initialized here
    }
}
    private OrderingClient orderingClient;
    private Sales2Client sales2Client;
    private Settings2Client settings2Client;

    @Autowired
    public BrinkWebTool(OrderingClient orderingClient, Sales2Client sales2Client, Settings2Client settings2Client) {
        this.orderingClient = orderingClient;
        this.sales2Client = sales2Client;
        this.settings2Client = settings2Client;
    }