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

Mic*_*vin 3 java spring instance inversion-of-control javabeans

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

谢谢!

Wou*_*rts 6

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

Spring会毫无问题地调用这个非公共构造函数(自Spring 1.1,SPR-174以来).

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

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

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

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

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


oxb*_*kes 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;
    }
}
Run Code Online (Sandbox Code Playgroud)

我真的不建议这样做!

  • 哇,这是"从不这样做"类别中最聪明的春季黑客之一:)为此感到荣幸! (2认同)