【问题标题】:Spring application having AnnotationConfigApplicationContext: getting run time exception具有 AnnotationConfigApplicationContext 的 Spring 应用程序:获取运行时异常
【发布时间】:2019-06-02 13:29:24
【问题描述】:

这是我的一个 SO 问题的延续 --> here

我扩展了相同的示例,我希望“正常”工作,但是我得到了 NullPointerException。

这里是完整的源代码:

FirstBean.java

package com.example;

import org.springframework.stereotype.Component;

@Component
public class FirstBean {

    public FirstBean() {

    }

    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "FirstBean [name=" + name + "]";
    }
}

SomeBean.java

package com.example;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;

@Component
@Configuration
@ComponentScan(basePackages = { "com.example" })
public class SomeBean {

    @Autowired
    private FirstBean fb;

    @Bean
    FirstBean instantiateFirstBean() {
        return new FirstBean();
    }

    public SomeBean() {
        // this.fb.setName("Some Name"); -> this was causing problem as 
        // bean isn't still created fully
    }

    public void print() {
        this.fb.toString(); 
    }

    @PostConstruct
    void post() {
        fb.setName("Some name");
    }
}

MainDriver.java

package com.example;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Environment;

@Configuration
@ComponentScan(basePackages = { "com.example" })
@PropertySource(ignoreResourceNotFound = true, value = "classpath:/application.props")
public class MainDriver {

    @Autowired
    private Environment env;

    @Autowired
    private ConfigurableEnvironment cenv;

    @Autowired
    ApplicationContext ctx;

    @Autowired
    private SomeBean sb;

    @Bean
    public SomeBean instantiateSomeBean() {
        return new SomeBean();
    }

    public static void main(String[] args) {

        ApplicationContext ctx = new AnnotationConfigApplicationContext(MainDriver.class);

        MainDriver l = ctx.getBean(MainDriver.class);
        System.out.println("In main() the ctx is " + ctx);
        l.test();
    }

    public void test() {
        System.out.println("hello");
        sb.print();
    }
}

我期待SomeBean 得到Autowiredctxenvcenv 正在完美地自动接线),但它没有得到,而且我得到了运行时异常。

Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'mainDriver': Unsatisfied dependency expressed through field 'sb'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'someBean' defined in file [/Users/vkoul/understand-code/platform/stream-base/trunk/target/classes/com/example/SomeBean.class]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.example.SomeBean$$EnhancerBySpringCGLIB$$fad3571b]: Constructor threw exception; nested exception is java.lang.NullPointerException
Exception in thread "main" org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'mainDriver': Unsatisfied dependency expressed through field 'sb'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'someBean' defined in file [/Users/vkoul/understand-code/platform/stream-base/trunk/target/classes/com/example/SomeBean.class]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.example.SomeBean$$EnhancerBySpringCGLIB$$fad3571b]: Constructor threw exception; nested exception is java.lang.NullPointerException
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:584)
    at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:90)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:370)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1336)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:572)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:495)
    at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:317)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:315)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:759)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:867)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:548)
    at org.springframework.context.annotation.AnnotationConfigApplicationContext.<init>(AnnotationConfigApplicationContext.java:88)
    at com.example.MainDriver.main(MainDriver.java:37)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'someBean' defined in file [/Users/vkoul/understand-code/platform/stream-base/trunk/target/classes/com/example/SomeBean.class]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.example.SomeBean$$EnhancerBySpringCGLIB$$fad3571b]: Constructor threw exception; nested exception is java.lang.NullPointerException
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1228)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1127)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:535)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:495)
    at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:317)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:315)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
    at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:251)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1135)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1062)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:581)
    ... 14 more
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.example.SomeBean$$EnhancerBySpringCGLIB$$fad3571b]: Constructor threw exception; nested exception is java.lang.NullPointerException
    at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:182)
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:87)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1220)
    ... 25 more
Caused by: java.lang.NullPointerException
    at com.example.SomeBean.<init>(SomeBean.java:23)
    at com.example.SomeBean$$EnhancerBySpringCGLIB$$fad3571b.<init>(<generated>)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
    at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:170)
    ... 27 more

我也提到了@Bean,我希望它能告诉我如何创建这些 bean,但仍然会出现异常。

任何人都可以帮助我了解落后的地方以及如何解决它。

【问题讨论】:

    标签: java spring spring-ioc


    【解决方案1】:

    我认为这是因为 Spring 将首先必须实例化您的 SomeBean 类,然后它会尝试通过反射自动连接 FirstBean,因为您将 @Autowired 注释放在字段上。

    您试图在 SomeBean 构造函数中访问 FirstBean 依赖项,但是当调用 SomeBean 的构造函数时,在创建上下文时,FirstBean 依赖项为空,因为 Spring 尚未自动装配依赖项 - 它将尝试在对象创建后通过反射自动装配它。这就是为什么你在那里得到NullPointerException。您的SomeBean 课程也会发生同样的情况 - 决定采用一种方法。

    另外奇怪的是,您创建的类都用@Configuration@Component 注释。请参考this SO question 以查看潜在错误。

    此外,您的配置中存在一些问题。您使用 @Component 注释来注释 FirstBean 并且您仍然创建一个返回此类实例的 @Bean 注释方法。您应该决定一种方法 - 使用 @Bean 注释为应用程序上下文实例化它,或者使用 @Component 注释此类,然后让组件扫描自动为您创建它。

    编辑

    您应该决定是要使用@ComponentScan 还是要通过@Bean 注释为上下文创建bean - 现在您正在混合不同的类型,并且在尝试自动装配时会遇到重复bean 定义的错误类型,因为在您当前的实现中,在您的上下文中,SomeBean 将有 2 个 bean,FirstBean 将有 2 个 bean - 它们只有不同的 id。请注意,我指出的 NPE 预期错误与此无关。我将提出一个使用自动包裹扫描的解决方案:

    FirstBean 类

    @Component
    public class FirstBean {
    
        private String name;
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        @Override
        public String toString() {
            return "FirstBean [name=" + name + "]";
        }
    }
    

    SomeBean 类

    @Component
    public class SomeBean {
    
        private FirstBean fb;
    
        @Autowired
        public SomeBean(FirstBean firstBean) {
            this.fb = firstBean;
            this.fb.setName("Some Name");
        }
    
        public void print() {
            this.fb.toString();
        }
    }
    

    MyConfig 类

    @Configuration
    @ComponentScan(basePackages = { "com.example" })
    public class MyConfig {
    
    }
    

    MainDriver 类

    @Component
    public class MainDriver {
    
        @Autowired
        private Environment env;
    
        @Autowired
        protected ConfigurableEnvironment cenv;
    
        @Autowired
        ApplicationContext ctx;
    
        @Autowired
        private SomeBean sb;
    
    
        public static void main(String[] args) {
    
            ApplicationContext ctx = new AnnotationConfigApplicationContext(MyConfig.class);
    
            MainDriver l = ctx.getBean(MainDriver.class);
            System.out.println("In main() the ctx is " + ctx);
            l.test();
        }
    
        public void test() {
            System.out.println("hello");
            sb.print();
        }
    }
    

    【讨论】:

    • 我正在使用@component,所以它在组件扫描期间被拾取,并且因为它有@Bean,因此它需要用@Configuration注释(它告诉spring它会给出bean 定义,如果我的理解是正确的)。我该如何解决?
    • 您的方法存在各种问题,请参阅我编辑的答案。
    • 感谢您的回复。我相信问题是我试图在 SomeBean() 的构造函数中初始化名称(它可能没有正确初始化);我在设置名称的地方添加了@postConstruct。现在不正常了。
    • 一个小的后续:我的印象是如果有@Autowired注解,那么在创建当前bean之前首先注入依赖。这不正确吗?
    • Spring 上下文是智能的,当它看到它必须为上下文创建 Bean 并且该 bean 的类具有用 @Autowired 注释的构造函数时,它将确保更早创建依赖项 bean 并通过构造函数注入.
    猜你喜欢
    • 1970-01-01
    • 2021-05-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多