How do app servers inject into private fields?

前端 未结 3 1051
孤城傲影
孤城傲影 2021-02-08 04:13

I saw this question

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

about how to manually inject into annotated private fields (The way is addi

相关标签:
3条回答
  • 2021-02-08 04:59

    It's a simple reflection "trick". It relies on the Field.setAccessible() method to force the member to be accessible programmatically:

    Set the accessible flag for this object to the indicated boolean value. A value of true indicates that the reflected object should suppress Java language access checking when it is used. A value of false indicates that the reflected object should enforce Java language access checks.

    The Reflection API is used to get a handle on the field, setAccessible() is called, and then it can be set by the injection framework.

    See an example here.

    No magic, no custom VM.

    0 讨论(0)
  • 2021-02-08 05:02

    With the help of skaffman I coded this simple example on how to inject without setters. Perhaps it helps (It did to me)

    //......................................................
    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
    

    Run output:

    ------- fields : --------
     -> private int MyClass.theValue
           found annotation: @Inject()
           injecting !
    23
    
    0 讨论(0)
  • 2021-02-08 05:03

    It's also worth noting, that some frameworks utilize bytecode engineering via a custom classloader to achieve the same result without the cost of Reflection (reflection can be pretty expensive at times)

    0 讨论(0)
提交回复
热议问题