java Spring 将数据源 bean 注入或自动装配到类

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/17819752/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-01 15:07:10  来源:igfitidea点击:

Spring injecting or autowiring datasource bean to class

javaspringjdbcautowired

提问by Jay Mie

this may be a very novice question, but I have searched and either I have a large gap in my understanding or am doing something incorrectly that I cannot figure out.

这可能是一个非常新手的问题,但我已经搜索过,要么我的理解有很大差距,要么做错了一些我无法弄清楚的事情。

In my context file here is an excerpt

在我的上下文文件中,这里有一个摘录

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

<bean id="myBeanOne" class="a.b.c.myBeanOne">
         <property name="dataSource" ref="dataSource" />
</bean>

Now in myBeanOne I have:

现在在 myBeanOne 我有:

private DataSource dataSource;

private JdbcTemplate jdbcTemplate;

@Autowired
public void setDataSource (DataSource dataSource) {
    this.jdbcTemplate = new JdbcTemplate(dataSource);
}

public void myMethod() {
    String sql = "'My generic SQL update query'";
    try {
        this.jdbcTemplate.update(sql);
    } catch (org.springframework.dao.EmptyResultDataAccessException ex) {
    }
    System.exit(0);
}

when I try to execute this on the line where setDataSource is invoked I get this error:

当我尝试在调用 setDataSource 的行上执行此操作时,出现此错误:

ERROR org.springframework.integration.handler.LoggingHandler 
    org.springframework.integration.MessageHandlingException: 
       java.lang.NullPointerException

on the line: this.jdbcTemplate.update(sql);

在线上: this.jdbcTemplate.update(sql);

I have tried maybe ten different configurations to get this to work, but I cannot seem to do it. Any assistance is appreciated, thank you.

我已经尝试了十种不同的配置来让它工作,但我似乎无法做到。任何帮助表示赞赏,谢谢。

Edit:as per Luiggi's comment:

编辑:根据 Luiggi 的评论:

//in yet another classes run method
myBeanOne bOne = SomeOtherClass.create();   //just returns new myBeanOne
bOne.myMethod();

Neither SomeOtherClass or this class are classified as beans in the context or have any presence in the context.

SomeOtherClass 或此类在上下文中都未归类为 bean 或在上下文中没有任何存在。

I know that this is a very basic question but I am struggling with it.

我知道这是一个非常基本的问题,但我正在努力解决它。

Thank you for your patience.

感谢您的耐心等待。

回答by Luiggi Mendoza

As noted in comments, the problem is that you're manually creating the bean instead of letting Spring container create it. Basically, you're doing this:

如评论中所述,问题在于您手动创建 bean 而不是让 Spring 容器创建它。基本上,你正在这样做:

new MyBeanOne()

So Spring container can't inject any of the fields you have configured thus being nulle.g. jdbcTemplatefield. There are some solutions to this:

因此 Spring 容器无法注入您已配置的任何字段,null例如jdbcTemplate字段。有一些解决方案:

  1. Convert your SomeOtherClassinto a bean managed by Spring container and let it inject the MyBeanOneinstance (probably using @Autowiredannotation).

  2. If latter approach can't be done since you need to manuallycreate the bean, you can create the bean manually as shown here: How to create spring beans dynamically?

    But this implementation makes you hardcode somewherethe spring config file name and use it in your code. So, a better approach would be option 3.

  3. Look at this solution: Creating New Spring Beans on Demand, where you create a client abstract class with a method that Spring will implement to retrieve a new instance of your Spring managed bean.

  1. 将您的转换SomeOtherClass为 Spring 容器管理的 bean 并让它注入MyBeanOne实例(可能使用@Autowired注解)。

  2. 如果后一种方法由于您需要手动创建 bean而无法完成,您可以手动创建 bean,如下所示:如何动态创建 spring bean?

    但是这个实现让你在某个地方硬编码spring 配置文件名并在你的代码中使用它。因此,更好的方法是选项 3。

  3. 看看这个解决方案:Creating New Spring Beans on Demand,您可以在其中创建一个客户端抽象类,其中包含一个 Spring 将实现的方法来检索 Spring 托管 bean 的新实例。



I found another way to handle this by using @Configurableannotation. By decorating your bean with this annotation, you can create a new instance of the bean on demand and Spring will manage the injection of Spring managed beans for you. But to achieve this, Spring needs to use aspects behind the scenes and you should activate usage of aspects for your project. The explanation is quite long, so I provide links that explain in depth this solution:

我找到了另一种使用@Configurable注释来处理这个问题的方法。通过用这个注解装饰你的 bean,你可以按需创建一个 bean 的新实例,Spring 将为你管理 Spring 托管 bean 的注入。但要实现这一点,Spring 需要在幕后使用方面,您应该为您的项目激活方面的使用。解释很长,所以我提供了深入解释这个解决方案的链接:

Note that in order to enable this feature, you have to add a java agentwhen starting the JVM that will weave the class at runtime using aspects.

请注意,为了启用此功能,您必须在启动 JVM 时添加一个 Java 代理,该代理将在运行时使用方面来编织类。

回答by Gray

NullPointerExceptionon the line: this.jdbcTemplate.update(sql);

NullPointerException上线:this.jdbcTemplate.update(sql);

If the NPE is actually on that line, then this.jdbcTemplateis obviously null. If this is true then either:

如果 NPE 实际上在那条线上,那么this.jdbcTemplate显然是null. 如果这是真的,那么要么:

  • The setDataSource(...)method is not being called in Spring, possibly because the @Autowiredis not right somehow. It would be easy to add a System.out.println(...)or put a debugging breakpoint in setDataSourceto see if it is being called.

  • If it isbeing called then maybe there are more than one instance of a.b.c.myBeanOne? Are you for sure getting the instance being called from another class from the Spring context? Put a breakpoint in setDataSourceand notice the thisobject reference id. Then put a breakpoint on the this.jdbcTemplate.update(...)line and make sure that the thisreference-id is the same.

  • setDataSource(...)方法没有在 Spring 中被调用,可能是因为@Autowired不知何故不正确。添加System.out.println(...)或放置调试断点setDataSource以查看是否正在调用它会很容易。

  • 如果它被称为那么也许有超过一个实例a.b.c.myBeanOne?您确定从 Spring 上下文中的另一个类调用实例吗?放置一个断点setDataSource并注意this对象引用 ID。然后this.jdbcTemplate.update(...)在行上放置一个断点,并确保thisreference-id 相同。