运行从springboot项目打包的jar时无法获取bean

时间:2019-07-11 01:26:50

标签: java spring-boot jar

我可以在IDEA中很好地运行springboot项目,但是将其打包到jar中并使用java命令运行时,从spring上下文中获取bean时就得到了java.lang.NullPointerException。

第一次出现错误的课程:

@Service
public class MdspiImpl extends CThostFtdcMdSpi {
public MdspiImpl(CThostFtdcMdApi mdapi) {
        m_mdapi = mdapi;
        logger.info("MdspiImpl is creating...");
        ***mdr = SpringContextUtil.getBean("marketDataRobot");//this is the error code***
    }
}

第二堂课

@Service
public class MarketDataRobot {
}

SpringContextUtil类:

@Component("SpringContextUtil")
public class SpringContextUtil implements ApplicationContextAware {
    private static ApplicationContext applicationContext;
    public static <T> T getBean(String name) {
        return (T) applicationContext.getBean(name);
    }
}

gradle文件:

jar {
    baseName = 'programmingTrading'
    version =  '0.1.0'
    manifest {
        attributes 'Main-Class': 'com.blackHole.programmingTrading'
    }
}

正在运行的异常:

WARN main[AbstractApplicationContext.java:557 Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'mdspiImpl' defined in URL [jar:file:/E:/workspace/simuPrd/programmingTrading-0.0.1-SNAPSHOT.jar!/BOOT-INF/classes!/com/blackHole/programmingTrading/infrastructure/MdspiImpl.class]: Bean instantiation via constructor failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.blackHole.programmingTrading.infrastructure.MdspiImpl]: Constructor threw exception; nested exception is java.lang.NullPointerException] 
[com.blackHole.programmingTrading.infrastructure.MdspiImpl]: Constructor threw exception; nested exception is java.lang.NullPointerException
    at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:184)
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:117)
    at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:300)
    ... 27 common frames omitted
Caused by: java.lang.NullPointerException: null
    at com.blackHole.programmingTrading.SpringContextUtil.getBean(SpringContextUtil.java:35)
    at com.blackHole.programmingTrading.infrastructure.MdspiImpl.<init>(MdspiImpl.java:46)

这也源于另一个问题:@Autowired注释不起作用... 像这样使用时:

@Component
public class Scu{
}

在另一堂课中:

@Autowired
private Scu scu;
logger.info(String.format("MdspiImpl is creating...[%s]", scu.toString()));

将获得java.lang.NullPointerException:空

spring-boot配置如下:

@SpringBootApplication
public class ProgrammingTrading {
    public static void main(String[] args) {
        SpringApplication.run(ProgrammingTrading.class, args);
    }
}

这是使用SpringContextUtil获取Bean的部分原因... 非常感谢!

2 个答案:

答案 0 :(得分:3)

SpringContextUtil不应像您正在做的那样被静态访问...由于将其定义为@Component,因此请执行以下操作;

@Service
public class MdspiImpl extends CThostFtdcMdSpi {

    @Autowired
    private SpringContextUtil springContextUtil;

    public MdspiImpl(CThostFtdcMdApi mdapi) {
        m_mdapi = mdapi;
        logger.info("MdspiImpl is creating...");
        ***mdr = springContextUtil.getBean("marketDataRobot");
    }
}

由于SpringContextUtil不是通过Spring注入的,而是简单地静态访问的,它里面的applicationContext被忽略,在您的情况下为空。

还删除static修饰符;

@Component
public class SpringContextUtil implements ApplicationContextAware {

    private ApplicationContext applicationContext;

    // include getter/setter for applicationContext as well

    public <T> T getBean(String name) {
        return (T) applicationContext.getBean(name);
    }
}

修改

最新示例项目带来的麻烦;

@Service
public class ExampleService {
    @Autowired
    private Logger logger;

    public ExampleService() {
        this.logger=logger;
        logger.info("Im working");
    }
}

在触发Logger构造函数时,ExampleService将为null,因为在注入开始之前调用了该构造函数,但是如果通过所述构造函数合并注入,则可以合并此行为如下;

@Service
public class ExampleService {

    private final Logger logger;

    public ExampleService(Logger logger) {
        this.logger = logger;
        logger.info("Im working");
    }
}

完美运行,没有任何麻烦...

答案 1 :(得分:2)

您永远不应该像使用此SpringContextUtil那样以编程方式访问bean,只需将MarketDataRobot注入MdspiImpl的构造函数中,您就可以使用了(因为它带有{ {1}})。首选方法是使用构造函数注入而不是字段注入,这将使您更容易编写单元测试。如果只有一个构造函数,也可以摆脱@Service