The previous article has introduced some basic concepts about reflection. This article uses an example to describe the reflection process and examples of practical application.
This example is a design concept: Read a string from an attribute file and generate the corresponding class instance object based on the string. Then there is an enhanced version example, you can initialize the member variables (reference type) of the class according to the setter () method in the class, which is implemented by the Spring framework.
The project structure is as follows:
This example includes three types:
1. Reflect. properties file, which contains key-value pairs, as shown below
Name = javax. Swing. jframe
Useraction = com. tgb. Reflect. useraction
2. useraction. Java, action class
<Span style = "font-size: 14px;"> public class useraction {public void adduser () {system. out. println ("Add User") ;}</span>
3. objectpoolfactory. Java, which reads files and instantiates objects
<Span style = "font-size: 14px;"> public class objectpoolfactory {// defines an object pool, use Key-value Key as the object name and value as the object private Map <string, Object> objectpool = new hashmap <> (); // define a method for creating an object, the parameter is the string class name private object Createobject (string clazzname) throws instantiationexception, illegalaccessexception, classnotfoundexception {// obtain the corresponding class Object Class Based on the string <?> Clazz = Class. forname (clazzname); Return clazz. newinstance () ;}// read the key-value initialization class instance from the property file, or use dom4j To Read Public void initpool (string filename) throws instantiationexception, illegalaccessexception, classnotfoundexception {try (fileinputstream FS = new fileinputstream (filename) {properties pros = new properties (); // load the property file pros from the input stream. load (FCM); // The keyfor (string name: Pros. stringpropertynames () {// retrieves the key-value, creates an object based on the value, and puts it in the objectpool of the Object pool. put (name, Createobject (pros. getproperty (name);} catch (exception e) {e. printstacktrace () ;}} public object GetObject (string name) {return objectpool. get (name);} public void test () throws instantiationexception, illegalaccessexception, classnotfoundexception {string Path = This. getclass (). getresource ("/COM/tgb/reflect. properties "). tostring (); Path = path. substring (path. indexof ("/") + 1); system. out. println (PATH); objectpoolfactory OPF = new objectpoolfactory (); OPF. initpool (PATH); useraction = (useraction) OPF. getObject ("useraction"); useraction. adduser ();} public static void main (string [] ARGs) throws instantiationexception, illegalaccessexception, classnotfoundexception {objectpoolfactory OPF = new objectpoolfactory (); OPF. test () ;}</span>
In this class, the Createobject () method is used to create an instance object, and then the forname () method of the class is called. This method returns a Class Object of the class, use the newinstance () of the Class Object to return the instance of the class it represents.
We use a map object to store a created object and use it as an object pool. Class <?> The Type wildcard is used to indicate the type of the Class Object. This time, the class object is unknown, so the type wildcard is used. In fact, the type parameter is also available, such as class <t>, the differences between type parameters and type wildcards will be discussed later.
So what is the relationship with the class loader?
Let's take a look at the JDK source code. The forname () method is overloaded with two. One of them needs to provide the Class Loader parameter, as shown in figure
<span style="font-size:14px;"> @CallerSensitive public static Class<?> forName(String name, boolean initialize, ClassLoader loader) throws ClassNotFoundException { if (loader == null) { SecurityManager sm = System.getSecurityManager(); if (sm != null) { ClassLoader ccl = ClassLoader.getClassLoader(Reflection.getCallerClass()); if (ccl != null) { sm.checkPermission( SecurityConstants.GET_CLASSLOADER_PERMISSION); } } } return forName0(name, initialize, loader); }</span>
This method has the most forname () parameters. It reloads the previous method and provides us with the default Class Loader. There are some security processing judgments in it.
The running result is as follows:
We can see that the adduser () of the above program useraction has been executed and the table name has been created successfully.
Next we will improve this method to assign values to a reference attribute in useraction. Modify useraction and add a setter () method as follows. Here you will know the role of the setter () method, for example, spring injects dependency Attributes Based on Setter.
Useraction. Java
<Span style = "font-size: 14px;"> public class useraction {// dependency attribute private usermanager; Public void adduser () {system. out. println ("adduser () method for executing useraction");} // Set Method of the attribute public void setusermanager (usermanager) {This. usermanager = usermanager; }}</span>
There is mainly one more initialization attribute method in the factory class, and the others are slightly changed but basically similar, as shown below
<Span style = "font-size: 14px;"> // initialize class attributes. You can also use dom4j To Read Public void initproperty () throws instantiationexception, illegalaccessexception, classnotfoundexception {try {// keyfor (string name: Pros. stringpropertynames () {If (name. contains ("%") {string [] namesarray = Name. split ("%"); object target = GetObject (namesarray [0]); Class <?> Targetclass = target. getclass (); string mname = "set" + namesarray [1]. substring (0, 1 ). touppercase () + namesarray [1]. substring (1); // obtain the Set Method of the target object's usermanager attribute. // The first parameter is the method name, and the second is the type of the parameter passed in the set method, that is, usermanager. class = usermanager. getclass () method M = targetclass. getmethod (mname, GetObject (name ). getclass (); // call the Set Method to assign m to the attribute. invoke (target, GetObject (name) ;}} catch (exception e) {e. printstacktrace () ;}</span>
You can also understand it by reading the annotations. Similar to the above, we only find the instance corresponding to the attribute, and then assign the instance to the attribute through the set method.
The property file is changed to the following variable values:
Name = javax. Swing. jframe
Useraction = com. tgb. Reflect. useraction
Useraction % usermanager = com. tgb. Reflect. usermanager
The third sentence is separated by a %. The preceding section indicates the attributes of the class. This attribute is mainly used to concatenate the set method name, because this parameter is required to obtain the set method.
Now, the basic content of reflection has been introduced. I believe you have understood how reflection is implemented through some of the above concepts and simple examples, many frameworks also use this process to instantiate various types through the xml configuration file. The difference is that the framework has made restrictions on labels in XML, and the principle is the same as reading attribute files, XML files contain more information, which makes parsing XML and instantiating objects more complex. You can use configuration files to process various relationships between classes.
We usually come into contact with AOP, IOC, containers, and some annotation principles all rely on reflection implementation. It is good to know more about reflection mechanisms. A lot of content is related internally, so it is better to associate them with each other for learning and application.
In-depth resolution reflection mechanism (2)