代码之家  ›  专栏  ›  技术社区  ›  Mike

通过@Autowired访问时的NPE

  •  0
  • Mike  · 技术社区  · 4 年前

    我的SpringBoot项目中有以下代码,它在提到的特定行中抛出NPE。

    Exception in thread "main" java.lang.NullPointerException
      at com.temp.controller.Controller.triggerJob(Controller.java:15)
      at com.temp.Application.main(Application.java:19)
    

    应用程序.java

    @Configuration
    @SpringBootApplication
    @ImportResource({"classpath:applicationContext.xml"})
    public class Application {
        public static void main(String[] args) {
            SpringApplication.run(Application.class, args);
            
            Controller controller = new Controller();
            controller.triggerJob();
        }
    }
    

    控制器.java

    @Controller
    public class Controller {
        @Autowired
        private Service Service;
        
        public void triggerJob() {
            Service.selectRecords();
        }
    }
    

    服务。selectRecords(); 是投掷NPE的地方

    服务.java

    public interface Service {
        List<VO> selectRecords();
    }
    

    ServiceImpl.java

    @Service
    public class ServiceImpl implements Service {
        @Autowired
        private Dao dao;
    
        @Override
        public List<VO> selectRecords() {
            return dao.selectRecords();
        }
    }
    

    applicationContext.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jdbc="http://www.springframework.org/schema/jdbc"
        xmlns:context="http://www.springframework.org/schema/context"
        xmlns:util="http://www.springframework.org/schema/util" xmlns:mvc="http://www.springframework.org/schema/mvc"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
                                http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
                                http://www.springframework.org/schema/jdbc
                                http://www.springframework.org/schema/jdbc/spring-jdbc-3.2.xsd
                                http://www.springframework.org/schema/util 
                                http://www.springframework.org/schema/util/spring-util-3.2.xsd
                                http://www.springframework.org/schema/context
                                http://www.springframework.org/schema/context/spring-context-3.2.xsd">
    
        <util:properties id="configProperties"
            location="file:${app.config.home}/config/config-${spring.profiles.active}.properties" />
    
        <context:property-placeholder
            location="file:${app.config.home}/config/config-${spring.profiles.active}.properties" />
    
        <bean id="crypt" class="com.temp.util.MyUtil">
            <property name="userId" value="${username}"></property>
            <property name="password" value="${password}"></property>
            <property name="key" value="123456789012345678901234"></property>
        </bean>
    
        <bean id="datasource"
            class="org.springframework.jdbc.datasource.DriverManagerDataSource">
            <property name="driverClassName" value="${driver}" />
            <property name="url" value="${connection}" />
            <property name="username" value="#{crypt.userId}" />
            <property name="password" value="#{crypt.password}" />
        </bean>
    
        <bean id="namedJdbcTemplate"
            class="org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate">
            <constructor-arg ref="datasource" />
        </bean>
    </beans>
    

    我有一个类似的项目,比较了两者的配置,除了两件事外,它们是相同的。

    1. 此项目的春季启动程序版本为2.4.2,其他项目的版本为1.5.3。
    2. 本项目的Java版本为11,其他项目为1.8。

    不知道我哪里做错了。

    我错过了什么吗?请帮忙。

    0 回复  |  直到 4 年前
        1
  •  0
  •   Ali K. Nouri    4 年前

    您正在创建新实例 Controller controller = new Controller(); 手动操作,此实例不在Spring上下文中。因此,注入的(自动连接的)Service实例为空。 @Autowired 仅当实例存在于Spring上下文中时才有效。

    最好的方法是通过构造函数注入来保持控制器的可测试性:

    @Configuration
    @SpringBootApplication
    @ImportResource({"classpath:applicationContext.xml"})
    public class Application {
        public static void main(String[] args) {
            SpringApplication.run(Application.class, args);
            
            Controller controller = new Controller(new ServiceImpl(new DaoImpl()));
            controller.triggerJob();
        }
    }
    

    通过构造函数注入实例:

        @Controller
        public class Controller {
            
            private final Service Service;
        
            public Controller(final Service Service) {
               this.service = service;
            }
            
            public void triggerJob() {
                Service.selectRecords();
            }
        }
    

    并通过构造函数注入Dao依赖:

    @Service
    public class ServiceImpl implements Service {
        
        private final Dao dao;
    
        public ServiceImpl(final Dao dao) {
           this.dao = dao;
        }
    
        @Override
        public List<VO> selectRecords() {
            return dao.selectRecords();
        }
    }
    

    对于4.3以上的Spring版本, @自动接线 Spring会自动扫描注入并通过构造函数注入依赖关系。 对于低于4.3的Spring版本,添加 @自动接线 除施工人员外,即:

    @Controller
    public class Controller {
    
        private final Service Service;
        
        @Autowired
        public Controller(final Service Service) {
           this.service = service;
        }
    
        public void triggerJob() {
            Service.selectRecords();
        }
    }