【问题标题】:how does spring implement this technology?spring是如何实现这项技术的?
【发布时间】:2013-07-14 15:35:03
【问题描述】:

今天得知可以使用spring的@AutoWired注解来完成自动注入, @AutoWired 可以在很多情况下使用,比如

@AutoWired
public void setInstrument(Instrument instrument){
  this.instrument = instrument;
}

但我们也可以将@AutoWired 放在私有字段上,像这样

@AutoWired
private Instrument instrument;

我想知道,spring 怎么能将对象注入私有字段,我知道我们可以使用 java 的反射来获取一些元数据,当我使用反射在私有字段上设置对象时,问题来了,以下是堆栈跟踪

 java.lang.IllegalAccessException: Class com.wire.with.annotation.Main can not access a member of class com.wire.with.annotation.Performer with modifiers "private"

有人可以解释吗?为什么spring可以将一个对象注入一个没有setter方法的私有字段。非常感谢

【问题讨论】:

  • 反射、BCEL等。

标签: java spring


【解决方案1】:

这是使用反射完成的,您需要通过 Filed.setAccessible(true) 访问 private 字段。

privateField.setAccessible(true);//works ,if java security manager is disable

更新:-

例如-

public class MainClass {
    private String string="Abcd";

    public static void main(String... arr) throws SecurityException, IllegalArgumentException, IllegalAccessException, InvocationTargetException, NoSuchFieldException{
        MainClass mainClass=new MainClass();
        Field stringField=MainClass.class.getDeclaredField("string");
        stringField.setAccessible(true);//making field accessible 
        /*if SecurityManager enable then,  
        java.security.AccessControlException: access denied will be thrown here*/
        stringField.set(mainClass, "Defgh");//seting value to field as it's now accessible
        System.out.println("value of string ="+stringField.get(mainClass));//getting value from field then printing it on console
    }
}

Java 安全管理器(如果启用)还可以防止 Spring 访问私有字段

【讨论】:

  • @Uwe 如果安全管理器禁止,Spring DI 将无法工作。
【解决方案2】:

我猜你忘了在你试图访问的字段上设置setAccessible(true)

public class Main {

    private String foo;

    public static void main(String[] args) throws Exception {
        // the Main instance
        Main instance = new Main();
        // setting the field via reflection
        Field field = Main.class.getDeclaredField("foo");
        field.setAccessible(true);
        field.set(instance, "bar");
        // printing the field the "classic" way
        System.out.println(instance.foo); // prints "bar"
    }

}

也请阅读this related post

【讨论】:

最近更新 更多