Java 不使用@Inject/@EJB从@Entity访问@Singleton

Java 不使用@Inject/@EJB从@Entity访问@Singleton,java,ejb,domain-driven-design,Java,Ejb,Domain Driven Design,我正在使用领域驱动设计(我想!),我需要访问一些全局属性。我的@Singleton是这样的: @Singleton public class MyProperties { private Properties props; @PostConstruct private void initialize() { try { props.load(new FileInputStream("my.properties"));

我正在使用领域驱动设计(我想!),我需要访问一些全局属性。我的@Singleton是这样的:

@Singleton
public class MyProperties {
    private Properties props;

    @PostConstruct
    private void initialize()
    {
        try {
            props.load(new FileInputStream("my.properties"));
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    public String getProperty(String propertyName)
    {
        return props.getProperty(propertyName);
    }
}
我想这样做:

@Entity(name="MYENTITY")
public class MyEntity {
    @Inject private MyProperties props;
    void doSomething()
    {
        String myProp = props.getProperty("my-prop");
        // ...etc...
    }
}
然而,这不起作用-
props
null
,不管怎么说,网站告诉我,我应该这样做,但所有使用JNDI查找的味道都是一样的

我的计划可能是尝试这样的事情:

@WebListener
public class MyServletContextListener implements ServletContextListener{
    @Inject private MyProperties props;
    private MyServletContextListener theInstance;

    @Override
    public void contextInitialized(ServletContextEvent sce) {
        theInstance = this;
    }

    static public MyServletContextListener theInstance() { return theInstance; }
    public MyProperties getProperties() { return props; }
}
这有意义吗,或者我找错了方向,或者我的代码中有一些愚蠢的错误

编辑:请注意,我使用的是香草JavaEE和CDI、JPA等,没有Spring


EDIT2:我看到CDI的最佳实践表明应该这样做。目前,我的应用程序流控制是从一个
@MessageBean
通过一系列
@Entity
s-这是一种设计气味吗?

首先,您的任何实体都不在spring应用程序上下文中,因此,spring的任何bean都不能注入到您的实体中! 第二,如果您确实想这样做,请添加:

<context:spring-configured />


在spring配置中,然后在MyEntity类中添加@Configurable

好吧,我找到了我的尊敬的人,并意识到我这里有一个访客模式,它特别有用,因为我的
@实体构成了一个层次结构。因此,我将添加如下代码:

public class DoSomethingVisitor extends EntityVisitor {
    @Inject private MyProperties props;

    @Override
    void visit(MyEntity entity)
    {
        String myProp = props.getProperty("my-prop");
        if(entity.getValue().equals(myProp))
        //...or whatever...
    }
}
以及:


此解决方案还允许我删除在
doSomething()
调用中传递的
logger
参数,我的业务逻辑现在已经脱离了
@实体
s,进入了一个我可以进行注入的地方。

如果您选择javaee方式,我想在这种情况下,在实体上方使用
@EntityListener
注释将是首选。它是如何工作的。使用一些带有注释的方法定义侦听器类,例如
@PostConstruct
@PrePersist

    public class DoSomethingVisitor {

     @PrePersist  
     void visit(MyEntity entity)
    {
        String myProp = props.getProperty("my-prop");
        if(entity.getValue().equals(myProp))
        //...or whatever...
    }

    }
并在实体的注释中定义此类:

@Entity(name="MYENTITY")
@EntityListeners(value = {DoSomethingVisitor.class})
public class MyEntity {
    void Accept(EntityVisitor visitor)
    {
        visitor.visit(this);
    }
}

javaee-box中已经包含了所有最好的模式

IMHO从实体访问服务是一种有点笨拙的设计,即数据(实体表示)访问业务逻辑(服务表示)。根据您的需要,我很可能会将逻辑移到服务或将数据存储在实体中,例如,通过引用某种配置实体。顺便说一句,服务定位器模式并不是死的,只是不太需要。:)为什么不听听链接blogpost中给出的建议(不要在实体中注入/用户服务查找)?“全局属性”是应用程序级别的问题。应用程序应该在创建实体或实体的生命周期时,使用相应的值(可能包含在属性文件中)初始化实体。我同意@Thomas的观点,即从实体访问
MyProperties
是很尴尬的。请参阅:您可能希望将该注释添加到您的答案中,以便将其保存在一个位置。:)哦,顺便说一句,OP根本没有说他使用了Spring——所以我在这里假设EJB+JPA+CDI,即普通的JavaEE6+。不管是Spring还是EJB,错误根源是:用户的实体不会由Spring或EJB容器管理!这是真的,但如果OP根本不使用Spring,告诉他如何在Spring中实现这一点对他没有帮助。你不能将
props
注入
DoSomethingVisitor
中,原因与你不能将其注入实体相同。
@Entity(name="MYENTITY")
@EntityListeners(value = {DoSomethingVisitor.class})
public class MyEntity {
    void Accept(EntityVisitor visitor)
    {
        visitor.visit(this);
    }
}