【问题标题】:Autowired not working in a Class @EntityAutowired 在 @Entity 类中不起作用
【发布时间】:2026-01-20 18:15:02
【问题描述】:

我有一个名为 Menu 的类,注释为 @Entity 我需要在一个名为 GestoreMessaggi 的类中使用方法

....    
@Component
@Entity
@Table(name="menu")
public class Menu implements Serializable{

@Autowired
@Transient // because i dont' save this field on the DB
private GestoreMessaggi gestoreMessaggi;
.....
public void setCurrentLanguage(){

   /* I got the error both if use gestoreMessaggi
   this way and if I use the autowired istance of GestoreMessaggi*/
   GestoreMessaggi gestoreMessaggi = new GestoreMessaggi();  
   gestoreMessaggi.gest();        
}
.....

这是GestoreMessaggi类的相关代码

 @Component
    public class GestoreMessaggi {    
        @Autowired 
        private ReloadableResourceBundleMessageSource messageSource;

        public void gest(){
        messageSource.doSomething() <--- here messageSource is null
        }
  }

什么时候,我调用 gestoreMessaggi.gest();从 Menu 类中,我收到一个错误,因为 messageSource 为空。 gestoreMessaggi istance 不为空,为空只是 messageSource

重要提示:只有当我从注释为 @Entity 的类中调用 GestoreMessaggi 时,我才会在 messageSource 上得到 null。

在 ds-servlet.xml 中,我告诉 Spring 扫描包含 Menu 和 GestoreMessaggi 类的包:

//Menu package 
<context:component-scan base-package="com.springgestioneerrori.model"/>
//Gestore messaggi package
<context:component-scan base-package="com.springgestioneerrori.internazionalizzazione"/>   

谢谢

【问题讨论】:

  • 请包括您的弹簧配置。您确定 Menu 类是由 Spring 管理的吗?
  • Spring 只会将依赖注入到它自己管理的对象中。 @Entity 注解的类不由 spring 管理(不管 @Component 注解)。
  • 最好在构造函数上使用@Autowired 并设置字段final。如果你这样做,那么你肯定会明白为什么messageSource 为空。
  • 我应该怎么做才能告诉 Spring '管理'我的对象?
  • 恕我直言,您甚至不应该尝试解决此依赖问题。您将太多逻辑放入您的实体中,最好应该是一个简单的 POJO。确定语言(或翻译或您在那里所做的任何事情)不应该在您的实体内部完成;该值应赋予您的实体(例如,通过您的服务、业务对象......)。

标签: java spring spring-mvc


【解决方案1】:

您可以采用两种方法:

  1. 尝试从 @Entity 类的方法中获取 Spring 管理的 bean 的实例
  2. 按照@Stijn Geukens 的建议更改设计,使您的实体成为没有任何逻辑或依赖注入机制的 POJO

如果您选择选项 1,则必须显式访问 Spring 的上下文并检索您需要的 bean 的实例:

@Component
public class Spring implements ApplicationContextAware {

    private static final String ERR_MSG = "Spring utility class not initialized";

    private static ApplicationContext context;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        context = applicationContext;   
    }

    public static <T> T bean(Class<T> clazz) {
        if (context == null) {
            throw new IllegalStateException(ERR_MSG);
        }
        return context.getBean(clazz);
    }

    public static <T> T bean(String name) {
        if (context == null) {
            throw new IllegalStateException(ERR_MSG);
        }
        return (T) context.getBean(name);
    }
}

你需要让 Spring 扫描这个类才能让它工作。

然后,在您的 @EntityClass 中,执行以下操作:

public void setCurrentLanguage(){
    GestoreMessaggi gestoreMessaggi = Spring.bean(GestoreMessaggi.class);
    gestoreMessaggi.gest();        
}

仅此而已。请注意,您不再需要将 GestoreMessaggi 自动连接到您的 @Entity 中。另请注意,Spring 和大多数社区都不推荐这种方法,因为它将您的域类(您的 @Entity 类)与 Spring 类耦合。

如果您选择选项 2,那么您需要做的就是让 Spring 像往常一样解决自动装配,但在您的实体之外(即在 dao 或服务中),并且如果您的实体需要你用一些消息或什么来填充它,只需调用它的设置器。 (然后由您决定是否将@Entitys 属性设为@Transient,具体取决于您的要求)。

【讨论】:

    【解决方案2】:

    Spring 上下文不管理实体(通常不管理使用 new 实例化的对象),这就是为什么您不能在实体中自动装配 bean(来自 Spring 的上下文)。

    最佳实践建议在您的实体中仅保留 getter 和 setter,将业务逻辑留给服务层。

    一种常见的方法是Service &lt;-&gt; DAO &lt;-&gt; Entity。示例:

    服务层:

    @Service
    public interface GestoreMessaggi {
        public void gest();
    }
    
    public class GestoreMessaggiImpl implements GestoreMessaggi {
    
        @Autowired
        private MenuDao menuDao;
    
        @Override
        public void gest() {
            // 1) retrieve your entity instance with menuDao
            // 2) do stuffs with your entity
            // 3) maybe save your entity using menuDao
        }
    }
    

    DAO 层:

    如果你使用 Spring Data Jpa:

    public interface MenuDao extends JpaRepository<Menu, [menu-id-type]> {}
    

    其他:

    public interface MenuDao {
        public Menu findOne([menu-id-type] id);
        public Menu save(Menu menu);
        // other methods for accessing your data
    }
    
    @Repository
    public class MenuDaoImpl {
        // inject EntityManager or Hibernate SessionFactory
        // implement your DAO interface accessing your entities
    }
    

    最后记得在配置中配置 Spring 的 bean,包括您的 @Services 和 @Repositorys(显式地或通过包扫描)。

    使用 Spring MVC,您应该在 @Controller 类中注入(自动装配)您的 @Services,以便控制器可以调用服务方法,这些服务方法调用 DAO 方法来访问您的数据。

    【讨论】: