自动装配不在@Entity类中工作

时间:2015-02-06 11:50:14

标签: java spring spring-mvc

我有一个名为菜单的类,注释为 @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不为null,为null messageSource

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

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

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

谢谢

2 个答案:

答案 0 :(得分:6)

您可以采用以下两种方法:

  1. 尝试从@Entity
  2. 的方法中获取Spring托管bean的实例
  3. 按照@Stijn Geukens的建议更改设计,让您的实体成为没有任何逻辑或依赖注入机制的POJO
  4. 如果你选择选项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或服务中),以及你的实体需要你填写一些消息或其他什么,只需在其上调用一个setter。 (那么您可以根据自己的要求制作@Entity属性@Transient

答案 1 :(得分:2)

Spring上下文不管理实体(通常不管理使用new实例化的对象),这就是为什么你不能在实体中自动装配bean(来自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 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,包括配置中的@Service@Repository(明确地或通过包扫描)。

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