【问题标题】:Java EE Singleton Injection by ReflectionJava EE 单例反射注入
【发布时间】:2015-09-09 15:01:49
【问题描述】:

Java EE 让我(又一次)头疼(Wildfly 8+):

首先,想象一些 Singleton POJO,其中使用的实例是由某个属性设置的:

Java SE 单例

public class Singleton
{
    private Singleton instance
    public Singleton getInstance()
    {
        if (instance == null)
        {
            try
            {
                String className = System.getProperty("singletonClass");
                instance = Class.forName(className).getInstance();
            }
            catch(Exception e)
            {
            ...
            }
        }
    return instance;
    }
}

您可能会认为这种方法是糟糕的设计。但这是我们的单例实例“配置”的方式。

现在我在 Java EE 世界中遇到了这种方法。我让它工作了,但它只是臃肿丑陋的注释地狱代码 - 除了我对 Java EE 不太熟悉之外,可能还有更简单的方法:

ProjectManager(应该是抽象的)

@Singleton
@LocalBean
public class ProjectManager
{
...
}

ProjectManager 实施

@Singleton
@LocalBean
public class DefaultProjectManager extends ProjectManager
{
}

生产者注释

@Qualifier
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.TYPE, ElementType.METHOD
})
public @interface DynamicProjectManager
{

}

制片人

@ApplicationScoped
public class ProjectManagerProducer implements Serializable
{
    @Inject
    @Any
    private Instance<ProjectManager> projectManagers;

    @Produces
    @DynamicProjectManager
    private ProjectManager createProjectManager()
    {
        String clazz = System.getProperty("projectManagerType","DefaultProjectManager");
        try
        {
            return projectManagers.select((Class<ProjectManager>) Class.forName(clazz)).get();
        }
        catch(Exception e)
        {
            return projectManagers.select(DefaultProjectManager.class).get();
        }
    }
}

在另一个 Bean 中使用:

@Inject
@DynamicProjectManager
private ProjectManager projectManager;

这行得通!但是我看到很多事情让我晚上睡不好觉。目前我没有使用其他框架(Spring 或类似的)。所以这是我的问题:

  1. 在 Java EE 中是否有更简单的方法来支持单例(或其他 EJB),其中单例的运行时类在编译时是未知的?
  2. 如果不是:是否可以只注入单例实例而无需额外的 @DynamicProjectManager 注释?
  3. 是否可以将 ProjectManager 抽象化?

【问题讨论】:

    标签: java singleton cdi wildfly


    【解决方案1】:

    保持简单,除非绝对需要,否则不要将 EJB 与 CDI 混合使用。应该这样做:

    public interface ProjectManager {
        // add some method signatures
    }
    
    
    @ApplicationScoped
    public class DefaultProjectManager implements ProjectManager {
        // add implementations
    }
    
    public class ProjectManagerClient {
    
        @Inject
        private ProjectManager projectManager;
    
        // work with injected bean
    }
    

    如果周围有多个ProjectManager 实现,您可以使用@Alternative,或者,如果您确实需要在运行时动态选择实现,则使用Instance&lt;ProjectManager&gt; 和@987654325 @ 用于给定的限定符。

    按类名选择是一种不好的做法,违反了松散耦合。最好在每个实现中使用不同的限定符,或者如果您更喜欢共享限定符,则在限定符中添加 @NonBinding 参数,以便您可以通过此参数的值进行选择。

    【讨论】:

    • 这很简单;)谢谢!我在抽象类上苦苦挣扎,从没想过“对接口编程”如此难以执行。使其成为接口而不是抽象类解决了这个问题。
    猜你喜欢
    • 2014-12-24
    • 1970-01-01
    • 2012-11-11
    • 2014-11-23
    • 1970-01-01
    • 1970-01-01
    • 2018-10-25
    • 2021-06-17
    • 2015-03-08
    相关资源
    最近更新 更多