Spring @Autowired not working
Asked Answered
R

8

10

I have some problems wth autowire annotation. My app looks like this:

Here is controller:

@Controller
public class MyController {
    @Autowired
    @Qualifier("someService")
    private SomeService someService;

    ....
}

It's a service layer:

public interface SomeService {
    ...
}

@Service
public class SomeServiceImpl implements SomeService{    
    @Autowired
    @Qualifier("myDAO")
    private MyDAO myDAO;

    ....
}

And DAO layer:

public interface MyDAO{
    ....        
}

@Repository
public class JDBCDAOImpl implements MyDAO {    
    @Autowired
    @Qualifier("dataSource")
    private DataSource dataSource;    
    ....
}

This is a app-service.xml file:

....
<bean id="propertyConfigurer"
      class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"
      p:location="/WEB-INF/jdbc.properties" />

<bean id="dataSource"
      class="org.springframework.jdbc.datasource.DriverManagerDataSource"
      p:driverClassName="${jdbc.driverClassName}"
      p:url="${jdbc.url}"
      p:username="${jdbc.username}"
      p:password="${jdbc.password}"/>

<bean id="SomeService" class="com.service.SomeServiceImpl" />    
<bean id="myDAO" class="com.db.JDBCDAOImpl" />    

So... When I'm launching a web-app, MyController Autowires correctly (the someService field correctly injected by SomeServiceImpl class object), but myDAO feild of someService has null value (not injected properly).

Could you help me to find a problem?

P.S. Its interesting, but when I'm changing a "bean id" from myDAO to some another (e.g. myDAO2), system gives me an error, that injecting could not be done, because bean myDAO doesn't exist. So, Spring make an injection, but where it is? And why it's not work correctly?

Rosco answered 26/11, 2010 at 18:48 Comment(6)
Why don't you use @Service annotation in the Service and @Repository in the DAO as you do in with @Controller in the controller?Ailment
yes... I use it. Edited... I forget to write them, because my app more complex, than the code above. But errors in that place.Rosco
if you add the @Repository and @ Service annotation you don't have to define them in the xml as a bean. They will be found with <context:component-scan base-package="org.example"/>Ailment
@Javi: when I'm removing this 2 lines: <bean id="SomeService" class="com.service.SomeServiceImpl" /> <bean id="myDAO" class="com.db.JDBCDAOImpl" /> , my app gives me error: Injection of autowired dependencies failed; nested exception ......Rosco
Can you edit the question and add the log of the injection of autowired dependencies failed?Ailment
I posted an answer... My problems solved, but I still don't know, how to use @Autowire annotation in lower levels of application (when @Repository and @Service annotations needn't).Rosco
R
13

I found the solution. As Javi said (thanks a lot for you, Javi), I have to annotate DAO and Service layer classes with @Repository and @Service annotation. Now I've tried to write like this:

@Service("someService")
public class SomeServiceImpl implements SomeService{    
    @Autowired
    @Qualifier("myDAO")
    private MyDAO myDAO;

    ....
}

and

@Repository("myDAO")
    public class JDBCDAOImpl implements MyDAO {    
    @Autowired
    @Qualifier("dataSource")
    private DataSource dataSource;    
    ....
}

and all works fine!!!

But I still not found an answer for this quesion: if application will be more complex, and will have more complex structure, where @Repositore and @Service annotation are not preferred for some classes, how to inject correctly beans, which located in lower levels (in a fields of classes, or in a field of fields of classes) (with @Autowire annotation, of course)?

Rosco answered 26/11, 2010 at 19:21 Comment(6)
@Component is the one to used for another component which are not controller, service or repositoriesAilment
@Rosco Mark your your answer as the accepted one because it's been you the one who have found it, although you can upvote the comment if you found it interesting as well :)Ailment
@llnur: Note that in this case you also don't need to explicitly declare them as <bean>s.Blissful
@axtavt: but how I can inject concrete classes into fields without declaring beans in xml file (except the @Repository and @Service annotations)?Rosco
@llnur: I mean that the beans declared via annotations don't need to be declared in XML.Blissful
@axtavt: I thinked all day about such method of annotating (using @Repository and @Service). I think usage of them and avoidning of declaring them as <beans>'s make's an application to lose it's power (dependency injection and IOC), because now we couldn't config our application without recompiling.Rosco
B
4

I guess you need <context:annotation-config />.

Blissful answered 26/11, 2010 at 18:59 Comment(1)
It's exist in app-servlet.xml file. Something lke this: <context:annotation-config /> <context:component-scan base-package="com" />Rosco
B
3

You can use

<context:component-scan base-package="PATH OF THE BASE PACKAGE"/>  

entry in your configuration .xml file. This entry will scan/read all the stated type and annotations from the java classes.

Breger answered 23/9, 2013 at 9:11 Comment(0)
I
1

Important points:

  1. Sometimes, @Component may leads to a problem where it might say no default constructor found. The class which is defined as a @Component annotation, it must have a default constructor.
  2. Suppose, we have applied @Autowired annotation at field which is a user defined class reference. Now, if we also apply @Component to that class then it will always be initialized with null. So, a field with @Autowired should not have @Component at its class definition.
  3. By default @Autowired is byType.

Address bean is autowired at Student class. Let’s see what happens if we apply @Component at Address.java.

CollegeApp.java:

package com.myTest
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import com.bean.Address;
import com.bean.Student;
//Component scanning will for only those classes
//which is defined as @Component. But, all the class should not use
//@Component always even if the class is enabled with auto
//component scanning, specially the class which is Autowired
//Or which is a property of another class 
@Configuration
@ComponentScan(basePackages={"com.bean"})
public class CollegeApp {
    @Bean
    public Address getAddress(){
        return new Address("Elgin street");
}
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context=new AnnotationConfigApplicationContext(CollegeApp.class);
        Student student=context.getBean(Student.class);
        System.out.println(student.toString());
        context.close();
    }
}

We want Elgin street to be autowired with Student address.

Address.java:

package com.bean;
import org.springframework.stereotype.Component;
@Component
public class Address {
    private String street;
    public Address()
    {
    }
    public Address(String theStreet)
    {
        street=theStreet;
    }
    public String toString()
    {
        return (" Address:"+street);
    }
}

Student.java:

package com.bean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class Student {
    private String name;
    private int age;
    private Address address;
    public Student()
    {
    }
    public Student(String theName,int theAge)
    {
        name=theName;age=theAge;
    }
    @Autowired
    public void setAddress(Address address) {
        this.address = address;
    }
    public String toString()
    {
        return ("Name:"+name+" Age:"+age+ " "+address);
    }
}

Output: - Name:null Age:0 Address:null //Address not Autowired here.

To resolve the issue, only change the Address.java as below:

Address.java:

package com.bean;
public class Address {
    private String street;
    public Address(String theStreet)
    {
        street=theStreet;
    }
    public String toString()
    {
        return (" Address:"+street);
    }
}

Output:- Name:null Age:0 Address:Elgin street

Ichthyology answered 8/8, 2018 at 16:57 Comment(1)
It's not clear what this has to do with the question.Lithomarge
F
0

You should include this section of XML code in spring-config.xml :

<context:component-scan base-package="Fully.Qualified.Package.Name" />

but you should know the difference between <context:annotation-config> vs <context:component-scan> as most people are suggesting these two :

1) First big difference between both tags is that <context:annotation-config> is used to activate applied annotations in already registered beans in application context. Note that it simply does not matter whether bean was registered by which mechanism e.g. using <context:component-scan> or it was defined in application-context.xml file itself.

2) Second difference is driven from first difference itself. It does register the beans in context + it also scans the annotations inside beans and activate them. So <context:component-scan>; does what <context:annotation-config> does, but additionally it scan the packages and register the beans in application context.

Fishy answered 29/3, 2020 at 18:23 Comment(0)
C
0

There can be two reasons for this.

  1. When you have not annotated the injected object or say service with proper @Service/@Component/@Repository annotations.

  2. Once you have made sure of point 1 ,next check for whether the class package of your annotated service class is included in the class-path for your spring boot application in the main class.You can configure this using the following annotation.

@SpringBootApplication(scanBasePackages = { "com.ie.efgh.somepackage","com.ie.abcd.someotherpackage" })

Doing this you tell spring to look into the packages for the classes during class loading.

Copalite answered 17/12, 2020 at 13:49 Comment(1)
Please edit your answer to: improve code formatting See How to AnswerDisesteem
H
0

My problem is when i want to get unit test, i add @ComponentScan at entry point of Application and @Component for class to mark it so spring can create bean in context but still not run, eventually i forget to annotate the test class with

 @SpringBootTest

so it should be


@SpringBootTest
class FluxDemoTest {


    @Autowired
    private FluxDemo fluxDemo;

    @Test
    public void testFlux() {


        StepVerifier.create(fluxDemo.list_Integer()).expectNextCount(6).verifyComplete();
    }

}

He answered 22/9, 2023 at 12:56 Comment(0)
P
-2
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
       http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <!-- Specifying base package of the Components like Controller, Service, 
        DAO -->
    <context:component-scan base-package="com.jwt" />

    <!-- Getting Database properties -->
    <context:property-placeholder location="classpath:application.properties" />

    <!-- DataSource -->
    <bean class="org.springframework.jdbc.datasource.DriverManagerDataSource"
        id="dataSource">
        <property name="driverClassName" value="${database.driver}"></property>
        <property name="url" value="${database.url}"></property>
        <property name="username" value="${database.user}"></property>
        <property name="password" value="${database.password}"></property>
    </bean>

    <!-- Hibernate SessionFactory -->
    <bean id="sessionFactory"
        class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
        <property name="dataSource" ref="dataSource"></property>
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">${hibernate.dialect}</prop>
                <prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl.auto}</prop>
                <prop key="hibernate.format_sql">${hibernate.format_sql}</prop>
                <prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
            </props>
        </property>
    </bean>

</beans>
Presumable answered 13/4, 2018 at 9:56 Comment(1)
While code is nice, an explanation of how this addresses the question is helpful as well, both to the person who asked and future readers.Larcener

© 2022 - 2024 — McMap. All rights reserved.