简体   繁体   中英

Spring: Why is setter not called in spite of @Autowired annotation

I am learning Spring. I came around using Spring with JDBC and also read about Autowiring.

So I wrote this

public class JdbcAccess {
    @Autowired
    private DataSource dataSource;

    private JdbcTemplate jdbcTemplate;

    public void setDataSource(DataSource dataSource) {
        System.out.println("setDataSource called");
        this.dataSource = dataSource;
        this.jdbcTemplate = new JdbcTemplate(dataSource);
    }

    public void getCount1() {
        String sql= "SELECT COUNT(*) FROM MYTABLE";
        jdbcTemplate = new JdbcTemplate();
        jdbcTemplate.setDataSource(getDataSource());
        int count = jdbcTemplate.queryForInt(sql);      
        System.out.println("Result is = " + count);
    }

    public void getCount2() {
        String sql= "SELECT COUNT(*) FROM MYTABLE";
        int count = jdbcTemplate.queryForInt(sql);        // Line 66
        System.out.println("Count = " + count);
    }
}

I expect below as output:

setDataSource called
Count = 3

What I get:

Exception in thread "main" java.lang.NullPointerException at playwithspring.JdbcAccess.getCount2(JdbcAccess.java:66)

This means setDataSource(..) , isn't being called by Spring, but Spring framework is setting the data source correctly, because getCount1() , which makes a call to getDataSource() runs fine. So my questions are:

  • Then how is Spring setting dataSource without calling setter ?
  • What I can do in above program to achieve desired output ?

Please note: I run either getCount1() or getCount2()

Instead of

Field Injection

@Autowired
 private DataSource dataSource;

USE Setter Injection instead of Field injection if you want setter to be called.

@Autowired
public void setDataSource(DataSource dataSource) {
        System.out.println("setDataSource called");
        this.dataSource = dataSource;
        this.jdbcTemplate = new JdbcTemplate(dataSource);
}

The reason for the exception is because your setDataSource is not called as Spring uses reflection for setting the data source.

You have two good options to set it, either annotate your setter method with @Autowired or you could leave your current annotation on the dataSource variable and use @PostConstruct annotation to initialize your jdbcTemplate which I think would lead to a cleaner code.

@Autowired
private DataSource dataSource;

private JdbcTemplate jdbcTemplate;

@PostConstruct
private void init() {
    jdbcTemplate = new JdbcTemplate(dataSource);
    System.out.println("jdbTemplate created");
}

public void getCount2() {
   String sql= "SELECT COUNT(*) FROM MYTABLE";
   int count = jdbcTemplate.queryForInt(sql);
   System.out.println("Count = " + count);
}

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