Reflection (Refection) in a programming language refers to the ability to dynamically load a class at program run time. It is related to introspection (introspection), which means that the program can get a description of a type, such as getting all the interface definitions of a class, all the parameters of an interface. When the programming language has these language features, it can solve the problem of code coupling to a large extent, so in the Java world, you can see that many libraries/frameworks use reflection technology.
A spring-like bean container implementation is a huge use of the reflection mechanism. The bean container maintains some bean objects, which are simply some common objects. The bean container can create these objects from the configuration, and when created, the bean container is responsible for injecting the dependent objects into the target object, known as Dependency injection (dependence injection), if the objects depend on other objects. In the module design, it also derives the concept of inversion of control (IoC, inverse of controls), which describes the application to control the framework when using a framework, not a framework to control/limit the application's architectural pattern.
This article simply describes how the bean container is implemented using reflection, and the final code references GitHub ioc-sample
Dynamic loading of classes
You can simply use Class.forName
it to pass in the full name of a class:
Public class<?> loadclass (String fullName) throws ClassNotFoundException { return class.forname (fullName); }
The loading of classes involves class loader, which can be further deepened. Once you have loaded the class, you can create an instance of the class, but you have not yet completed the dependency injection function:
class<?> C = loadclass ("Com.codemacro.bean.test.Test1"); Object o = c.newinstance ();
Injection via set interface
Our class can contain set
interfaces for setting up a member:
public class Test2 {public Test1 test1; public void SetTest1 (Test1 t) { test1 = t; } }
Then the setXXX
interface will be Test1
injected into Test2
:
props specifies which members need to be injected, for example {"Test1", "test1"},test1 means settest1,test1 refers to the bean name public Object Buildwithsetters (String Name, class<?> C, map<string, string> props) { try { //Classsetmethods class get class<?> All setxx in this interface classsetmethods setmethods = new Classsetmethods (c); Object obj = c.newinstance (); For (map.entry<string, string> entrys:props.entrySet ()) { String pname = Entrys.getkey (); String beanname = Entrys.getvalue (); Get Setxxx This method m = Setmethods.get (pname); Object val = Getbean (beanname); Call M.invoke (obj, Val); } Beans.put (name, obj); return obj; } catch (Exception e) { throw new RuntimeException ("Build bean Failed", e); } }
ClassSetMethod
Introspect all the interfaces in a class setXXX(xx)
:
Public Classsetmethods (class<?> c) { method[] methods = C.getmethods (); for (Method m:methods) { String mname = M.getname (); class<?>[] Ptypes = M.getparametertypes (); if (Mname.startswith ("set") && ptypes.length = = 1 && m.getreturntype () = = Void.type) { String name = M Name.substring ("set". Length ()); This.methods.put (name, M);}}}
Above, you can see the ability of introspection in Java, for example, Class<?>.getMethods
Method.getReturnType
Method.getParameterTypes
.
Inject by constructor function
Similar to the following in spring:
<bean id= "Examplebean" class= "examples. Examplebean "> <constructor-arg type=" int "value=" 2001 "/> <constructor-arg type=" Java.lang.String "value=" Zara "/>
You can inject dependent beans through constructor parameters into the target object:
list<string> params = new arraylist<string> (); Params.add ("Test1"); Bf.buildwithconstructor ("Test2", Test2.class, params);
Its implementation:
Public Object Buildwithconstructor (String name, class<?> C, list<string> beannames) { try { constructor<?>[] ctors = C.getconstructors (); Get class constructor list assert ctors.length = = 1; constructor<?> cc = ctors[0]; class<?>[] Ptypes = Cc.getparametertypes (); Get constructor parameter Type list assert ptypes.length = = Beans.size (); object[] args = new Object[ptypes.length]; for (int i = 0; i < beannames.size (); ++i) { Args[i] = Getbean (Beannames.get (i));//construct the argument list of the call constructor } objec T obj = cc.newinstance (args); Creates an object beans.put (name, obj) through a constructor; return obj; } catch (Exception e) { throw new RuntimeException ("Build bean Failed", e); } }
The use Convention for this interface beanNames
is to save the bean name and correspond to the constructor parameter one by one.
through annotation injection
We can annotate a data member with an annotation that needs to be injected automatically. Here I simply get the member type of the annotation callout and find the bean that corresponds to that type as the injected object. Of course, complex points can also specify the name of the bean to inject, or a derived class implementation that automatically finds the type.
An empty annotation can:
@Retention (retentionpolicy.runtime) @Target (elementtype.field) public @interface Inject { }
Realize:
Public Object Buildwithinject (String name, class<?> c) { try { Object obj = c.newinstance (); field[] fields = C.getdeclaredfields (); Gets the member for all definitions of the class for (Field f:fields) { Inject Inject = f.getannotation (Inject.class);//Gets the annotated if of the data member (Inject ! = NULL) {//If annotated with inject annotation Object bean = Getbeanbytype (F.gettype ());//Find the corresponding bean f.set (obj, Bean) based on the type of the member;//Inject } else { throw new RuntimeException ("Not Found Bean" + f.getname ())} } Beans.put (name, obj); return obj; } catch (Exception e) { throw new RuntimeException ("Build bean Failed", e); } }
getBeanByType
is to Class
match all the beans. When used:
public class Test2 { @Inject public Test1 test1; ... }
Finish.
Original address: http://codemacro.com/2015/05/31/java-refect-ioc/
Written by Kevin Lynx posted athttp://codemacro.com
Reflection in Java and implementation of bean container