简体   繁体   中英

@Inject and @Autowired not working whereas injecting with setter works

I used @Autowired hundreds of time but today I don't get it, neither @Autowired nor @Inject work in a new project I just created, I get the famous error

Invalid property 'jdbcTemplate' of bean class [com.xxx.SomeDAO]: Bean property 'jdbcTemplate' is not writable or has an invalid setter method. Does the parameter type of the setter match the return type of the getter?

When I add a setter for jdbcTemplate in SomeDAO , it works...

applicationContext.xml:

...
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
    <property name="dataSource" ref="dataSource"/>
</bean>

<bean id="com.xxx.SomeDAO" class="com.xxx.SomeDAO">
    <property name="jdbcTemplate" ref="jdbcTemplate"/>
</bean>
...

SomeDAO.java:

import org.springframework.jdbc.core.JdbcTemplate;
import javax.inject.Inject;
//import org.springframework.beans.factory.annotation.Autowired;

public class SomeDAO {

    @Inject // Doesn't work
    //@Autowired // Doesn't work either
    private JdbcTemplate jdbcTemplate;
    ...

    /* Works if I add this setter
    public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }*/
}

What could prevent the injection through the annotation? Thanks!

It is not possible to use field-injection when the bean is created with the XML-context the way you have provided it. Your class is not part of any component-scanning and therefore the annotations does not kick in. Therefore, I can see at least the following options:

1. Use a setter as per your example and remove the @Inject

This is the simplest approach since you got the code and XML prepared. However, this means that your DAO must expose an unnecessary setter-method.

2. Use a constructor that sets your jdbcTemplate field

This is according to me a better alternative but it means that you need to rewrite the XML like this:

<bean id="com.xxx.SomeDAO" class="com.xxx.SomeDAO">
    <constructor-arg ref="jdbcTemplate"/>
</bean> 

And, your constructor like this:

public class SomeDAO {
    private final JdbcTemplate jdbcTemplate;

    public SomeDAO(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }
}

3. Add component-scanning and use @Autowired (or @Inject)

I think that this is the best approach if you fully want to utilize the beauty of Spring's dependency injection capabilities. Add the following to your XML-context:

<context:component-scan base-package="com.xxx"/>

And then the code you previously provided should work. However, you should probably consider avoiding field-injection in favour of constructor-injection. The opinions differ on this matter but I find the code harder to test when field-injection is used.

Constructor injection looks like this:

// The component scanner will find this annotation and create 
// the bean (and inject the dependencies)
@Component
public class SomeDAO {
    private final JdbcTemplate jdbcTemplate;

    @Autowired // enables constructor-injection
    public SomeDAO(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }
}

I personally prefer alternative #3 since it is clean, Java-based (practically no XML required) which also means that it is refactoring friendly , there is no field magic happening and the constructor-based approach makes the code testable and does not expose any unnecessary setter-methods.

A good starting point to learn more about this is the excellent Spring Documentation . There you can find a great explanation for all of the above!

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