如何从类名称获取单例实例作为字符串 [英] How to get singleton instance from a class name as string

查看:272
本文介绍了如何从类名称获取单例实例作为字符串的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我遇到一个奇怪的问题。我有一个接口,其实现往往是无状态的。所以,我希望他们是单身人士。



我将实现类名称作为字符串。例如

  String clazz =com.foo.Bar; 

我有一个规则工厂来获取 IRule 实现。

  public class RulesFactory {

private static final Logger logger = LoggerFactory.getLogger(RulesFactory.class) ;

@SuppressWarnings(unchecked)
public static< T extends IRule> T getRuleInstance(String clazz){
try {
Class<?> ruleObject = Class.forName(clazz);
方法factoryMethod = ruleObject.getMethod(getInstance);
return(T)factoryMethod.invoke(null);
} catch(ClassNotFoundException e){
logger.error(ClassNotFoundException,e);
} catch(IllegalAccessException e){
logger.error(IllegalAccessException,e);
} catch(SecurityException e){
logger.error(SecurityException,e);
} catch(NoSuchMethodException e){
logger.error(NoSuchMethodException,e);
} catch(IllegalArgumentException e){
logger.error(IllegalArgumentException,e);
} catch(InvocationTargetException e){
logger.error(InvocationTargetException,e);
}
返回null;
}
}

上面的代码抛出 NullPointerException 如果该类没有静态的 getInstance()方法。在Java 6中,我不能在接口中使用静态方法。我不想创建多个实例的 IRule 实现。如果我可以强制执行静态方法并调用该静态方法,我将获得兑现实例。但我无法做到这一点。如何解决这个问题?

解决方案

有几种解决方案有不同的优点和缺点:


  1. 不要使用 static 方法。如果方法不是静态的,您可以将其添加到 IRule 中,因此强制该方法存在。

  2. 检查限制符 factoryMethod ,并在它们不是时抛出一个描述性异常static

对于解决方案#1,您需要一个 Map< String,IRule> 。调用 getRuleInstance()时,请检查映射的实例。如果没有,请使用界面中的方法创建一个并将其放入地图中。这样,您可以使实例单例。



同时,您可以获取实例的所有字段,并确保所有这些都是最终来执行无状态。



如果您的应用程序是多线程的,请确保使用并发映射并正确同步。 p>

示例代码:

  private Map< String,IRule> rules = Maps.newHashMap(); 

public static< T extends IRule> T getRuleInstance(String clazz){
try {
synchronized(rules){
IRule result = rules.get(clazz);
if(null == result){
result = clazz.newInstance();
rules.put(clazz,result);
}
@SuppressWarnings(未选中)
T tmp =(T)结果;
return tmp;
}
} catch(异常e){
log(无法为{}创建IRule,clazz);
}
}


I am running into a strange problem. I have an interface, whose implementations tend to be stateless. So, I want them to be singletons.

I get the implementation class names as strings. For example

String clazz = "com.foo.Bar";

I have a rules factory to obtain instances of IRule implementations.

public class RulesFactory {

    private static final Logger logger = LoggerFactory.getLogger(RulesFactory.class);

    @SuppressWarnings("unchecked")
    public static <T extends IRule> T getRuleInstance(String clazz) {
        try {
            Class<?> ruleObject = Class.forName(clazz);
            Method factoryMethod = ruleObject.getMethod("getInstance");
            return (T) factoryMethod.invoke(null);
        } catch (ClassNotFoundException e) {
            logger.error("ClassNotFoundException", e);
        } catch (IllegalAccessException e) {
            logger.error("IllegalAccessException", e);
        } catch (SecurityException e) {
            logger.error("SecurityException", e);
        } catch (NoSuchMethodException e) {
            logger.error("NoSuchMethodException", e);
        } catch (IllegalArgumentException e) {
            logger.error("IllegalArgumentException", e);
        } catch (InvocationTargetException e) {
            logger.error("InvocationTargetException", e);
        }
        return null;
    }
}

The above code throws NullPointerException if the class doesn't have a static getInstance() method. In Java 6 i can't use static methods in interfaces. I don't want to create multiple instances of IRule implementations. If I can enforce a static method and invoke that static method I will get the cashed instance. But I am unable to do this. How to solve this problem?

解决方案

There are several solutions with different pros and cons:

  1. Don't use static methods. If the method isn't static, you can add it to IRule and therefore enforce that the method exists.
  2. Check the qualifiers of factoryMethod and throw a descriptive exception when they aren't static

For solution #1, you need a Map<String,IRule>. When getRuleInstance() is called, check the map for an instance. If there is none, use the method from the interface to create one and put it into the map. This way, you can make the instances singletons.

At the same time, you can get all fields of the instance and make sure all of them are final to enforce the statelessness.

If your application is multi-threaded, make sure you use a concurrent map and synchronize properly.

Example code:

private Map<String, IRule> rules = Maps.newHashMap();

public static <T extends IRule> T getRuleInstance(String clazz) {
    try {
        synchronized( rules ) {
            IRule result = rules.get(clazz);
            if(null == result) {
                result = clazz.newInstance();
                rules.put(clazz, result);
            }
            @SuppressWarnings("unchecked")
            T tmp = (T) result;
            return tmp;
        }
    } catch (Exception e) {
        log( "Unable to create IRule for {}", clazz );
    }
}

这篇关于如何从类名称获取单例实例作为字符串的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆