Spring @Autowired 不工作

发布于 2024-10-05 00:44:50 字数 1573 浏览 8 评论 0原文

我在自动装配注释方面遇到一些问题。我的应用程序如下所示:

这是控制器:

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

    ....
}

它是一个服务层:

public interface SomeService {
    ...
}

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

    ....
}

DAO 层:

public interface MyDAO{
    ....        
}

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

这是一个 app-service.xml 文件:

....
<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" />    

所以...当我启动 Web 应用程序时,MyController 正确自动连线( someService 字段由 SomeServiceImpl 类对象正确注入),但 someService 的 myDAO 字段具有 null 值(未正确注入)。

你能帮我找出一个问题吗?

PS 这很有趣,但是当我将“bean id”从 myDAO 更改为另一个(例如 myDAO2)时,系统给我一个错误,注入无法完成,因为 bean myDAO 不存在。那么,Spring 进行了注入,但是它在哪里呢?为什么它不能正常工作?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

孤寂小茶 2024-10-12 00:44:50

我找到了解决方案。正如 Javi 所说(非常感谢你,Javi),我必须使用 @Repository@Service 注释来注释 DAO 和 Service 层类。现在我尝试这样写:

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

    ....
}

并且

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

一切正常!

但我仍然没有找到这个问题的答案:如果应用程序会更复杂,并且会有更复杂的结构,其中 @Repositore@Service 注释不是首选一些类,如何正确注入位于较低级别的bean(在类的字段中,或在类的字段中的字段中)(当然使用@Autowire注释)?

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)?

z祗昰~ 2024-10-12 00:44:50

我猜你需要

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

挖个坑埋了你 2024-10-12 00:44:50

您可以使用

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

配置 .xml 文件中的条目。该条目将扫描/读取 java 类中所有指定的类型和注释。

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.

飘落散花 2024-10-12 00:44:50

要点:

  1. 有时,@Component 可能会导致出现找不到默认构造函数的问题。
    定义为@Component注解的类,它必须有一个默认的构造函数。
  2. 假设我们在用户定义的类引用字段上应用了 @Autowired 注释。
    现在,如果我们也将 @Component 应用于该类,那么它将始终使用 null 进行初始化。
    因此,带有 @Autowired 的字段在其类定义中不应包含 @Component。
  3. 默认情况下@Autowired是byType。

地址 bean 在学生类中自动装配。
让我们看看如果我们在 Address.java 中应用 @Component 会发生什么。

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();
    }
}

我们希望 Elgin 街能够自动连接学生地址。

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.java:Address.java

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

输出:-
姓名:null 年龄:0 地址:Elgin street

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

自我难过 2024-10-12 00:44:50

您应该在 spring-config.xml 中包含这部分 XML 代码:

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

但您应该知道 <; 之间的区别context:component-scan> 因为大多数人都建议这两个:

1) 两个标签之间的第一个大区别用于激活应用程序上下文中已注册的 bean 中应用的注释。请注意,bean 是否通过哪种机制注册并不重要,例如使用 或它是在 application-context.xml 文件本身中定义的。

2) 第二个差异是由第一个差异本身驱动的。它确实在上下文中注册了 bean,并且还扫描了 bean 内的注释并激活它们。所以 ;执行 的操作,但此外它还会扫描包并在应用程序上下文中注册 bean。

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.

顾冷 2024-10-12 00:44:50

这可能有两个原因。

  1. 当您没有使用正确的 @Service/@Component/@Repository 注释来注释注入的对象或说服务时。

  2. 一旦您确定了第 1 点,接下来检查您的带注释的服务类的类包是否包含在主类中 Spring Boot 应用程序的类路径中。您可以使用以下注释进行配置。

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

这样做你告诉 spring 在类加载期间查看类的包。

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.

软糖 2024-10-12 00:44:50

我的问题是,当我想要进行单元测试时,我在应用程序的入口点添加@ComponentScan,并在类中添加@Component来标记它,这样spring就可以在上下文中创建bean但仍然无法运行,最终我忘记用

 @SpringBootTest

这样的 方式注释测试类应该是


@SpringBootTest
class FluxDemoTest {


    @Autowired
    private FluxDemo fluxDemo;

    @Test
    public void testFlux() {


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

}

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();
    }

}

于我来说 2024-10-12 00:44:50
<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>
<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>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文