Spring:如何确保类仅由spring实例化,而不是由new new实例化

时间:2010-03-19 10:30:23

标签: java spring inversion-of-control instance javabeans

是否可以确保 only spring可以在编译时通过关键字new实例化一个类,? (为避免意外实例化)

谢谢!

7 个答案:

答案 0 :(得分:6)

如果要在编译时检测它,构造函数必须是非公共的。 私有可能过于严格(它使代码分析工具假设它永远不会被调用,甚至可能在某些IDE中引起警告),我会说默认(没有修饰符,包受保护)最好。如果你想在其他包中允许子类(但是如果不允许直接从该子类调用构造函数那是不可能的),你可以使它受到保护。 确保对构造函数进行适当的注释,因此任何读取代码的人都清楚构造函数是这样的。

Spring会毫无问题地调用这个非公共构造函数(从Spring 1.1开始,SPR-174)。

如果这不允许其他任何东西调用你的构造函数的问题,强迫一个类的每个用户使用Spring依赖注入的想法(所以这个问题的整个目标)是一个好主意或不是,是一个整体但不同的事情。

如果这是在库/框架中(通常 与Spring一起使用),限制它的使用方式可能不是一个好主意。但是,如果你知道的类只会用在已经强制使用Spring的已关闭的项目中,那么它确实有意义。

或者,如果您的真正目标只是为了避免某人创建实例而不是使用其依赖项初始化它,则可以使用构造函数依赖注入。

如果您的目标只是为了防止意外使用构造函数(开发人员不知道该类应该由Spring初始化),但不想完全限制可能性,您可以将其设为私有,但也可以添加静态工厂方法(使用明确的名称,如 createManuallyInitializedInstance 或类似的东西)。

糟糕的想法:另一种可能的替代方法是使构造函数公开可用,但弃用它。这样它仍然可以使用(不使用像反射这样的黑客),但任何意外使用都会发出警告。但这并不是很干净:这不是贬值的意思。

答案 1 :(得分:5)

我能想到的唯一明显的方法就是在运行时通过大规模黑客攻击; Spring毕竟使用普通的Java(即可以在Spring中完成的任何事情都必须通过标准Java来实现 - 因此无法实现编译时检查)。所以这是黑客:

//CONSTRUCTOR
public MyClass() {
    try {
         throw new RuntimeException("Must be instantiated from with Spring container!");
    }
    catch (RuntimeException e) {
        StackTraceElement[] els  = e.getStackTrace();
        //NOW WALK UP STACK AND re-throw if you don't find a springframework package
        boolean foundSpring = false;
        for (StackTraceElements el : els) {
            if (el.getDeclaringClass().startsWith("org.springframework")) {
                foundSpring = true; break;
            }
        }
        if (!foundSpring) throw e;
    }
}

我真的不建议这样做

答案 2 :(得分:1)

虽然我可以理解为什么你想要确保只有Spring实例化一个类,但这实际上并不是一个好主意。依赖注入的目的之一是能够在测试期间轻松模拟一个类。那么,在单元测试期间应该可以手动实例化各种依赖项和模拟依赖项。依赖注入是为了让生活更轻松,因此通常使用DI进行实例化很好,但有些情况下使用new是完全合理的,并且应该注意不要将任何设计模式或习惯用于极端。如果您担心您的开发人员会在他们应该使用DI的地方使用新的,那么最好的解决方案就是建立代码审查。

答案 3 :(得分:1)

我会告诉你为什么这样做 - 你将无法模拟你的课程。因此,您将无法进行单元测试。

答案 4 :(得分:0)

不确定Spring是否支持这个,因为我没有尝试过,并且在很长一段时间内都没有使用过Spring,但是对于另一个IOC容器我曾经采取的一个偷偷摸摸的路线是让一个人希望在注入时返回接口一个抽象类,并让IOC容器返回它作为派生类实例。这样,没有人可以创建类的实例(因为它是抽象的),容器可以返回它的派生类。

容器本身将生成派生类的定义,因此不必担心有人试图构建其中一个

答案 5 :(得分:0)

围绕对构造函数的调用编写一个方面,如果不是通过Spring

则中止

答案 6 :(得分:-1)

不了解spring,但如果你想对创建新实例有一些控制权,你应该将构造函数设为私有,并在你的类中创建public static YourClass getInstance()方法,它将处理检查并返回该实例的新实例宾语。然后,您可以使用构造函数创建新类,该函数将调用getInstance()..并将该类交给Spring。很快你就会发现春天以外有“非法”电话的地方......