5

I have class NetworkUsageService which uses NetworkUsageMapper to access a database. Mapper class is autowired to the service class.

I need to access the database during the construcion of service class, so I do something like this:

private int someField;    

@Autowired
private NetworkUsageMapper networkUsageMapper;


public NetworkUsageService() {
    someField = networkUsageMapper.getSomeResultFromDB();
}

However, this doesn't seem to work as I get exception while creating the service bean. Is there a way to use an autowired dependency during the construction of an object?

EDIT: this is my beans configuration as requested:

<context:component-scan base-package="mypackage" />
<mybatis:scan base-package="mypackage.mappers" />

<mvc:annotation-driven />

<context:property-placeholder location="classpath:/jdbc.properties"/>

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="dataSource" />
    <property name="mapperLocations" value="classpath:mappers/*.xml" />
    <property name="typeAliasesPackage" value="mypackage.transfer" />
</bean>

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource" />
</bean>

<bean  id="dataSource"
       class="org.springframework.jdbc.datasource.DriverManagerDataSource">

    <property name="driverClassName" value="${jdbc.driverClassName}" />
    <property name="url" value="${jdbc.url}" />
    <property name="username" value="${jdbc.username}" />
    <property name="password" value="${jdbc.password}" />
</bean>
4
  • Can you post your beans configuration? Commented Dec 2, 2013 at 15:20
  • i added my beans configuration to the question Commented Dec 2, 2013 at 15:35
  • where is your networkUsageMapper bean? Commented Dec 2, 2013 at 15:36
  • @KeerthiRamanathan: <mybatis:scan base-package="mypackage.mappers" /> does it for me Commented Dec 2, 2013 at 15:38

4 Answers 4

12

Instead of doing a lot of work in the constructor (and potentially introduce problems because the application tries to go to the database when it isn't fully initialized) it's probably better to do this initialization in a different method and annotate this with @PostConstruct . This way you know for sure your application is completely wired before networkusermapper is called.

Sign up to request clarification or add additional context in comments.

2 Comments

thank you for the answer, this sounds like something I need, I will try that, but can you be sure that dependencies are autowired before @PostConstruct methods are invoked?
Yes, that is part of the contract. The method annotated with @PostConstruct is called after all the beans are (auto)wired.
1

That's correct. The bean is first constructed, then the dependencies are injected. If you need it in your constructor, do this

@Autowired
public NetworkUsageService(NetworkUsageMapper mapper){
// do stuff
}

2 Comments

thank you, just for clarification - if I do as you supposed and leave the autowired dependency as is in my code, does it mean that there will be 2 instances of NetworkUsageMapper constructed?
I'm not actually sure how Spring handles that. I would remove your existing annotation to eliminate ambiguity. That said, you can annotate your NetworkUsageMapper class with the @Singleton annotation and that will guarantee that only one instance is created by spring and used for all dependency injection. Otherwise, multiple instances could be created if more than one class uses the dependency.
1

The other way is to make the setterMethod of NetworkUsageMapper annotated with @Required annotation

@Required
public void setNetworkUsageMapper(NetworkUsageMapper mapper){
this.networkUsageMapper = mapper;
this.someField = this.networkUsageMapper.getSomeResultFromDB();
}

This method would be invoked immediately compulsorily after construction of the object. This is really useful when you have a long list of mandatory properties for the object to work properly. Instead of having the constructor with long parameter list, we can set all the properties using setters with @Required annotation. It seems to be very handy for me.

3 Comments

Thank you for your answer, but as you wrote : "This method would be invoked immediately compulsorily after construction of the object." - I need to use the dependency during the construction of the object, not after it's construction
i need to populate a field of service object with database data before I use it for anything else
I have updated the answer setting the field of the service object. Hope this helps
0

If you can add the exception stack-trace along with your spring configuration that will help to answer more accurately. I am guessing it is because you might have more than one bean instances for NetworkUsageMapper class or its missing.

  1. If its missing just add one :). To avoid exception you can use required attribute:

    @Autowired(required=false) private NetworkUsageMapper networkUsageMapper;

  2. If more than one then you need to use qualifier for example :

then

@Autowired
@Qualifier("networkUsageMapper1")
private NetworkUsageMapper networkUsageMapper;

Hope it helps :Mak

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.