自动装配在 Class @Entity 中不起作用

Autowired not working in a Class @Entity

我有一个名为 Menu 的 class,注释为 @Entity,我需要在 @Entity 中使用方法 class 调用了 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();        
}
.....

这是class GestoreMessaggi

的相关代码
 @Component
    public class GestoreMessaggi {    
        @Autowired 
        private ReloadableResourceBundleMessageSource messageSource;

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

时,我调用gestoreMessaggi.gest();从菜单 class 中,我得到一个错误,因为 messageSource 为空。 gestoreMessaggi 实例不为空,只是 messageSource

为空

重要:仅当我从注释为 @Entity 的 classes 调用 GestoreMessaggi 时,我才在 messageSource 上得到 null。

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

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

谢谢

您可以采用两种方法:

  1. 尝试从您的 @Entity class
  2. 的方法中获取 Spring-managed bean 的实例
  3. 按照@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 扫描此 class 才能正常工作。

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

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

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

如果您选择选项 2,那么您需要做的就是让 Spring 像往常一样解析自动装配,但是 在您的实体之外(即在dao 或服务),如果您的实体需要您用一些消息或其他内容填充它,只需在其上调用 setter 即可。 (然后由你来决定你的 @Entitys 属性 @Transient 与否,取决于你的要求)。

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

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

一种常见的方法是Service <-> DAO <-> 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数据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,包括您的 @Service@Repository(显式或通过包扫描)。

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