Spring @Autowired註解私有屬性(無set方法)
今天看到一個POJO類中的某個私有屬性通過@Autowired自動注入。
按照以前理解的依賴注入需要注入點,可以是set方法也可以是構造方法,但是此屬性並沒有可以通過外部access的方法,他是如何注入的呢?
在網上搜索了一番,答案如下:
stackoverflow.com/questions/4127365/how-can-spring-hibernate-access-private-members/4127403#4127403
You can set private a variable of another object through reflection. Here is an example on how to do it. Consider the following object with a private variable:
1 2 3 |
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. I wrote two static methods: setValue
which can set a value into
a private field called fieldName of an Object bean
getValue
method
which can get the value of a private variable called fieldName from an Object bean.
The main method just demonstrates its use by creating an Object of MyBean class, setting the message variable and retrieving it. I've actually tested this code as a standalone application and it works.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
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. In contrast, getField
can only
access public members. The next step is calling setAccessible
on the field to allow
reading and writing it. The last step, is simply use the get
and set
methods
provided by the java.lang.reflect.Field
class.
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. I've also tried, in a Spring Application under Tomcat, and it's still working.
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.