简体   繁体   English

Spring / Hibernate如何访问私有成员?

[英]How Can Spring/Hibernate Access Private Members?

As you know, Spring can inject values to private instance variables, and Hibernate can access private variables of persistent classes. 如您所知,Spring可以为私有实例变量注入值,而Hibernate可以访问持久化类的私有变量。 However, I can't even call protected methods of a class through reflection! 但是,我甚至无法通过反射调用类的受保护方法! How can Spring and Hibernate blatantly breach security like that? Spring和Hibernate如何公然违反安全性? And more importantly, how do I do it? 更重要的是,我该怎么做? :D :d

When running without prohibitive security manager, you can obtain instance of corresponding method or field trough reflection and call setAccessible() on it. 在没有禁止安全管理器的情况下运行时,您可以通过反射获取相应方法或字段的实例并在其上调用setAccessible()

Using Java security manager you can of course disable that by writing a custom policy. 使用Java安全管理器,您当然可以通过编写自定义策略来禁用它。

You can set private a variable of another object through reflection. 您可以通过反射将private设置为另一个对象的变量。 Here is an example on how to do it. 这是一个如何做到这一点的例子。 Consider the following object with a private variable: 考虑具有私有变量的以下对象:

public class MyBean {
    private String message;
}

Normally the message field wouldn't be accessible from outside MyBean , however, SnoopyClass can set and get its value. 通常,无法从MyBean外部访问消息字段,但是, SnoopyClass可以设置并获取其值。 I wrote two static methods: setValue which can set a value into a private field called fieldName of an Object bean and a getValue method which can get the value of a private variable called fieldName from an Object bean . 我写了两个静态方法: setValue可以将设置到名为字段名对象和的私人领域getValue方法,可以从一个对象称为字段名私有变量的值。

The main method just demonstrates its use by creating an Object of MyBean class, setting the message variable and retrieving it. main方法只是通过创建一个MyBean类的Object,设置消息变量并检索它来演示它的用法。 I've actually tested this code as a standalone application and it works. 我实际上已经将此代码作为一个独立的应用程序进行了测试

import java.lang.reflect.Field;

public class SnoopyClass {

    private static void setValue(Object bean, String fieldName, Object value)
            throws IllegalArgumentException, IllegalAccessException, 
            SecurityException, NoSuchFieldException {
        Field privateVar = bean.getClass().getDeclaredField(fieldName);
        privateVar.setAccessible(true);
        privateVar.set(bean, value);
    }

    private static Object getValue(Object bean, String fieldName) 
            throws IllegalArgumentException, IllegalAccessException,
            SecurityException, NoSuchFieldException {
        Field privateVar = bean.getClass().getDeclaredField(fieldName);
        privateVar.setAccessible(true);
        return privateVar.get(bean);
    }

    public static void main(String[] argv) 
            throws IllegalArgumentException, SecurityException,
            IllegalAccessException, NoSuchFieldException {
         MyBean instance = new MyBean();
         setValue(instance, "message", "Shht! Don't tell anyone!");
         System.out.println("The message is '" + getValue(instance, "message"));
    }

}

The implementation uses getDeclaredField method on the class of the Object, because this method can look for all fields, even private. 该实现在Object的类上使用getDeclaredField方法,因为此方法可以查找所有字段,甚至是私有字段。 In contrast, getField can only access public members. 相比之下, getField只能访问公共成员。 The next step is calling setAccessible on the field to allow reading and writing it. 下一步是在字段上调用setAccessible以允许读取和写入它。 The last step, is simply use the get and set methods provided by the java.lang.reflect.Field class. 最后一步,只需使用java.lang.reflect.Field类提供的getset方法。

This kind of manipulation is allowed only if the security manager allows that. 只有在安全管理器允许的情况下才允许这种操作。 By default Java doesn't install any security manager, so in a standalone program that you launch through your IDE or the command line, you won't have any problems to use this technique. 默认情况下,Java不会安装任何安全管理器,因此在通过IDE或命令行启动的独立程序中,使用此技术不会有任何问题。 I've also tried, in a Spring Application under Tomcat, and it's still working. 我也试过,在Tomcat下的Spring应用程序中,它仍在工作。

The primary application, at least for me, is being able to set private variables in my unit tests, especially for Spring Beans, without polluting the interface with unneeded setters. 主要的应用程序,至少对我来说,能够在我的单元测试中设置私有变量,特别是对于Spring Beans,而不会使用不需要的setter来污染接口。

Hibernate can access private members via the 'field' level access configuration mechanism. Hibernate可以通过“字段”级访问配置机制访问私有成员。 From the documentation, section 5.1.11 从文档的5.1.11

"The access attribute allows you to control how Hibernate accesses the property at runtime. By default, Hibernate will call the property get/set pair. If you specify access="field", Hibernate will bypass the get/set pair and access the field directly using reflection." “访问属性允许您控制Hibernate在运行时访问属性的方式。默认情况下,Hibernate将调用属性get / set对。如果指定access =”field“,Hibernate将绕过get / set对并访问该字段直接用反射。“

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM