简体   繁体   中英

How do I instantiate an attribute that is declared as a bean in the spring config?

I have a pretty simple solution I'm trying to solve:

I have my DAO object:

package com.me.dao;
@Service
public class JavaNeo4jConnection implements Neo4jConnection {
    private JdbcTemplate jdbcTemplate;

    @Autowired(required = true)
    private DriverManagerDataSource dataSource;

    public void setDataSource(DriverManagerDataSource dataSource) {
        this.dataSource = dataSource;
        this.jdbcTemplate = new JdbcTemplate(this.dataSource);
    }

}

And I have declared the dataSource in my springConfig.xml

<context:annotation-config />
<context:component-scan base-package="com.me.dao" />
<context:component-scan base-package="com.me.servlets" />

<!-- Servlet --> 
<bean id="viewResolver"
    class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="viewClass"
        value="org.springframework.web.servlet.view.JstlView" />
    <property name="prefix" value="/WEB-INF/jsp/" />
    <property name="suffix" value=".jsp" />
</bean>

<!-- dataSource bean-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName" value="org.neo4j.jdbc.Driver" />
    <property name="url" value="${neo4j.dburl}" />
    <property name="username" value="${neo4j.username}" />
    <property name="password" value="${neo4j.password}" />
</bean>

<!-- Config properties file-->
<bean
    class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <property name="locations">
        <list>
            <value>classpath:config.properties</value>
        </list>
    </property>
</bean>

The dao object is being instantiated using Autowiring from my servlet controller:

package com.me.servlets;

@Controller
public class JsonServer {
    @Autowired
    Neo4jConnection neoConn;

    @RequestMapping("/servejson")
    @ResponseBody
    public void serveJson(HttpServletRequest request, HttpServletResponse response
    ) throws IOException {

        OutputStream os = response.getOutputStream();       

        String json =  neoConn.getInfo(request.getParameter("query"));

        os.write(json.getBytes());
        os.close();
        os.flush();

    }

}

But the dataSource is never instantiated, running my code will produce a NullPointerException .

What am I missing here? I'm fairly sure I'm misusing @Autowired .

Given

@Service
public class JavaNeo4jConnection implements Neo4jConnection {

and

<context:component-scan ... />
// or <context:annotation-config /> which is redundant if you have the 'component-scan'

Spring will instantiate your JavaNeo4jConnection bean. During that process, it will scan the members of the class for @Autowired (among other things). If it finds a field annotated with it, it will try to resolve a bean and inject it. If it finds a method annotated with it, it will look at the parameters and try to resolve appropriate beans and use them as arguments when invoking the method.

Since you only have a field annotated

@Autowired
Neo4jConnection neoConn;

Spring will use field injection directly. It will assign the bean it finds to the field. It won't invoke your setter method and therefore won't initialize the JdbcTemplate field.

One solution is to move the annotation to the setter method (method injection).

Another solution, with field injection, is to replace your setter method with a @PostConstruct annotated method

@PostConstruct
public void init() {
    // dataSource has been injected
    this.jdbcTemplate = new JdbcTemplate(this.dataSource);
}

Or use constructor injection

@Autowired
public JavaNeo4jConnection(DriverManagerDataSource dataSource) {
    this.dataSource = dataSource;
    this.jdbcTemplate = new JdbcTemplate(this.dataSource);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM