【问题标题】:How do app servers inject into private fields?应用服务器如何注入私有字段?
【发布时间】:2011-02-04 11:23:44
【问题描述】:

我看到了这个问题

Inject into private, package or public field or provide a setter?

关于如何手动注入带注释的私有字段(方法是添加setter 或通过构造函数)

但是,关键是应用服务器(如 glassfish、axis2、jboss 等)如何做 能够注入最终的私有字段(无需添加设置器或构造器 到用户类)?

引用引用的问题:

public SomeClass {
  @Inject
  private SomeResource resource;
}

他们是否使用允许访问私有字段的定制 JVM(不是标准 JVM)?

谢谢

【问题讨论】:

  • 这是私有的,但不是最终的。你错过了代码块中的 final 吗?因为我认为不可能注入私人最终成员。 (如果我错了,请纠正我。)
  • @Willi:你是对的。在下面的代码示例中,我放置了 final,但即使 doInjection() 方法没有引发错误,该值也没有改变。所以我删除了final。

标签: java dependency-injection annotations


【解决方案1】:

这是一个简单的反射“技巧”。它依靠Field.setAccessible() 方法强制成员以编程方式访问:

为此设置可访问标志 对象指定的布尔值。 值为 true 表示 反射对象应该抑制 Java 语言访问检查 用过的。值为 false 表示 反射对象应该强制执行 Java 语言访问检查。

Reflection API 用于获取字段的句柄,调用setAccessible(),然后可以被注入框架设置。

查看示例here

没有魔法,没有自定义虚拟机。

【讨论】:

    【解决方案2】:

    在 skaffman 的帮助下,我编写了这个关于如何在没有 setter 的情况下进行注入的简单示例。 也许它有帮助(它对我有用)

    //......................................................
    import java.lang.annotation.*;
    import java.lang.reflect.*;
    
    //......................................................
    @Target(value = {ElementType.FIELD})
    @Retention(RetentionPolicy.RUNTIME)
    @interface Inject {
    }
    
    //......................................................
    class MyClass {
    
        @Inject
        private int theValue = 0;
    
        public int getTheValue() {
            return theValue;
        }
    } // class
    
    //......................................................
    public class Example {
    
        //......................................................
        private static void doTheInjection(MyClass u, int value) throws IllegalAccessException {
    
            Field[] camps = u.getClass().getDeclaredFields();
    
            System.out.println("------- fields : --------");
            for (Field f : camps) {
                System.out.println(" -> " + f.toString());
                Annotation an = f.getAnnotation(Inject.class);
                if (an != null) {
                    System.out.println("       found annotation: " + an.toString());
                    System.out.println("       injecting !");
                    f.setAccessible(true);
                    f.set(u, value);
                    f.setAccessible(false);
                }
            }
    
        } // ()
    
        //......................................................
        public static void main(String[] args) throws Exception {
    
            MyClass u = new MyClass();
    
            doTheInjection(u, 23);
    
            System.out.println(u.getTheValue());
    
        } // main ()
    } // class
    

    运行输出:

    ------- fields : --------
     -> private int MyClass.theValue
           found annotation: @Inject()
           injecting !
    23
    

    【讨论】:

      【解决方案3】:

      还值得注意的是,一些框架通过自定义类加载器利用字节码工程来实现相同的结果,而无需反射成本(反射有时可能非常昂贵)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多