【问题标题】:How to autowire an object in spring in an object created with new如何在使用 new 创建的对象中自动装配弹簧中的对象
【发布时间】:2014-08-13 10:38:45
【问题描述】:

我想要做的就是在 NotesPanel 类中自动装配字段 backgroundGray,但我得到的只是下面的异常。

那么,问题是,如何正确地自动接线?这真的让我发疯,因为这可能是我做错了什么非常愚蠢的事情......

感谢您的帮助! 托尔斯滕

Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'notepad' defined in class path resource [Beans.xml]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [notepad.Notepad]: Constructor threw exception; nested exception is java.lang.NullPointerException
Caused by: org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [notepad.Notepad]: Constructor threw exception; nested exception is java.lang.NullPointerException
Caused by: java.lang.NullPointerException
    at notepad.NotesPanel.<init>(NotesPanel.java:23)
    at notepad.Notepad.<init>(Notepad.java:18)

课堂记事本:

package notepad;

import java.awt.BorderLayout;
import java.awt.Dimension;

import javax.swing.JFrame;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Notepad
{

  public Notepad()
  {
    JFrame frame = new JFrame();
    frame.setLayout(new BorderLayout());
    frame.add(new NotesPanel(), BorderLayout.CENTER);

    frame.setPreferredSize(new Dimension(1024, 768));
    frame.pack();
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setVisible(true);
    frame.setLocationRelativeTo(null);
  }

  public static void main(String[] args)
  {

    ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
    context.getBean("notepad");

  }
}

课堂笔记:

package notepad;

import java.awt.BorderLayout;

import javax.swing.JPanel;
import javax.swing.JTextPane;

import org.springframework.beans.factory.annotation.Autowired;

public class NotesPanel
    extends JPanel
{
  JTextPane tPane = new JTextPane();

  @Autowired
  private BackgroundGray backgroundgray;

  public NotesPanel()
  {
//    backgroundgray = new BackgroundGray();
//    backgroundgray.setGray("200");
    setLayout(new BorderLayout());
    tPane.setBackground(backgroundgray.getGrayObject());
    add(tPane, BorderLayout.CENTER);
    tPane.setText("Fill me with notes... ");
  }

}

类背景灰色:

package notepad;

import java.awt.Color;

public class BackgroundGray
{
  String gray;

  public BackgroundGray()
  {
    System.out.println("Background Gray Constructor.");
  }

  public String getGray()
  {
    return gray;
  }

  public void setGray(String gray)
  {
    this.gray = gray;
  }

  public Color getGrayObject()
  {
    int val = Integer.parseInt(gray);
    return new Color(val, val, val);
  }

}

Beans.xml:

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

    <context:annotation-config />

    <bean id="notepad" class="notepad.Notepad"/>

    <bean id="backgroundgray" class="notepad.BackgroundGray" autowire="byName">
        <property name="gray" value="120"></property>
    </bean>
</beans>

【问题讨论】:

  • 为了让 Spring 能够执行自动装配,您的实例必须由 Spring 管理。您也可以自动装配 NotesPanel。
  • new 打破了DIIoC 的概念,使用bean factory 获取bean 实例,一切都应该没问题。

标签: java spring autowired


【解决方案1】:

Spring 支持 @Autowire, ... 仅适用于 Spring Beans。通常,Java Class 在由 Spring 创建时成为 Spring Bean,而不是由 new 创建。

一种解决方法是使用 @Configurable 注释类,但您必须使用 AspectJ(编译时或加载时挥动)!

@请参阅Using Spring's @Configurable in three easy steps 以获得简短的分步说明。

【讨论】:

  • 这会被认为是“不良做法”还是完全“合法”来解决这个问题?
  • 视情况而定。如果这是唯一一个这样做的实例,并且如果有其他方法可以解决问题,那么我会选择另一种方法。 - 但这是一种合法的方式,例如完整的 Spring Roo 架构是基于@Configurable
  • 仅供参考,您所引用的 Using Spring's @Configurable in three easy steps 链接已断开指向示例源代码的链接,这使得参考无法遵循。
【解决方案2】:

当你通过 new 创建对象时,autowire\inject 不起作用...

作为解决方法,你可以试试这个:

创建您的 NotesPanel 模板 bean

<bean id="notesPanel" class="..." scope="prototype">
    <!-- collaborators and configuration for this bean go here -->
</bean>

并以这种方式创建一个istance

context.getBean("notesPanel");

PROTOTYPE :这将单个 bean 定义限定为具有任意数量的对象实例。

【讨论】:

  • 所以,只是为了我的理解:使用 autowire 要求对象创建链仅由 spring 完成才能使用它?
  • 是的,当然.. 自动装配仅在这种情况下有效
【解决方案3】:

问题出在这里:

frame.add(new NotesPanel(), BorderLayout.CENTER);

您正在 Notepad 类的构造函数中为类 NotesPanel 创建一个新对象。

构造函数在main方法之前被调用,所以Spring上下文还没有被加载。

在为 NotesPanel 实例化对象时,它无法自动连接 BackgroundGray,因为此时 Spring 上下文不存在。

【讨论】:

    【解决方案4】:

    我和你分享一个例子。 我希望你喜欢它:)

    public class Main {
        public static void main(String args[]) {
    
    
            java.awt.EventQueue.invokeLater(new Runnable() {
                public void run() {
                    try {
                        UIManager
                                .setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel");
                    } catch (Exception ex) {
                        ex.printStackTrace();
                    }
                    new Ihm().setVisible(true);
                }
            });
        }
    }
    

    我的配置bean:

    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.PropertySource;
    
    @Configuration
    @ComponentScan("com.myproject.configuration")
    @PropertySource("classpath:/application.properties")
    public class Config {
    
        @Bean
        public Configurator configurator() {
            return new Configurator();
        }
    
    }
    

    我的 java swing ihm 使用了我的配置 bean:

    public class Ihm extends JFrame {
    
        private MyConfiguration configuration;
    
        public SmartRailServerConfigurationFileIhm() {
    
            try {
                ApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
                configurator = context.getBean(MyConfiguration.class);
            } catch (Exception ex) {
    
            }
            System.out.println(configuration);
    
            ...
            ...
        }
    }
    

    【讨论】:

      【解决方案5】:

      您可以在任何实例上执行 DI,无论是 Spring 管理的还是使用 new 创建的。

      为此,请使用以下代码...

      AutowireCapableBeanFactory awcbf = applicationContext.getAutowireCapableBeanFactory();
      awcbf.autowireBean(yourInstanceCreatedWithNew);
      

      这也是将 Spring 引入最初没有 Spring 开发的应用程序的好方法 - 因为它允许您在需要的地方使用 Spring 而无需将应用程序中的每个类都转换为 Spring bean(因为通常,你不能在没有 Spring bean 的情况下使用 Spring bean)。

      【讨论】:

        猜你喜欢
        • 2016-09-03
        • 2019-03-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-06-22
        • 2011-04-13
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多