Storage structure of the Xwork container

Source: Internet
Author: User

As we can see, in the default implementation of container, there are two instance variables in Containerimpl. Factoris and Factorynamesbytype.

Object Manufacturing Plant
Class Containerimpl implements Container {final map<key<?>, internalfactory<?>> factories;    Final map<class<?>, set<string>> Factorynamesbytype;        Containerimpl (MAP&LT;KEY&LT;?&GT;, internalfactory<?>> factories) {this.factories = factories;        Map<class<?>, set<string>> map = new Hashmap<class<?>, set<string>> ();            For (key<?> Key:factories.keySet ()) {set<string> names = Map.get (Key.gettype ());                if (names = = null) {names = new hashset<string> ();            Map.put (Key.gettype (), names);        } names.add (Key.getname ()); } for (Entry<class<?>, set<string>> Entry:map.entrySet ()) {Entry.setvalue (Collect        Ions.unmodifiableset (Entry.getvalue ()));    } This.factorynamesbytype = Collections.unmodifiablemap (map); }}


First we look at factories, whose value is passed in by the constructor. Let's look at the type of it.
In the form of map, key is key.
Class Key<t> {  final class<t> type;  Final String name;  final int hashcode;  //...}

Look at this type and name, do you remember anything?

Yes, that's struts-default.xml.

<struts>    <bean class= "com.opensymphony.xwork2.ObjectFactory" name= "struts"/>    <bean type= " Com.opensymphony.xwork2.factory.ResultFactory "name=" struts "class=" Org.apache.struts2.factory.StrutsResultFactory "/>    <bean type=" Com.opensymphony.xwork2.factory.ActionFactory "name=" struts "class=" Com.opensymphony.xwork2.factory.DefaultActionFactory "/>    <bean type=" Com.opensymphony.xwork2.factory.ConverterFactory "name=" struts "class=" Com.opensymphony.xwork2.factory.DefaultConverterFactory "/>     <bean type=" Com.opensymphony.xwork2.ActionProxyFactory "name=" struts "class=" Org.apache.struts2.impl.StrutsActionProxyFactory "/>    <bean type=" Com.opensymphony.xwork2.ActionProxyFactory "name=" prefix "class=" Org.apache.struts2.impl.PrefixBasedActionProxyFactory "/>....<struts>
Type and name can uniquely identify a bean.
And look at internalfactory.
Interface Internalfactory<t> extends Serializable {  /**   * Creates an object to be injected.   *   * @param context of this injection   * @return instance to be injected   *  /T Create (Internalcontext context );}
The method that generates a class is stored in internalfactory, not an instance of this class.


Injection Device
Now let's look at the injector again.
What does the injector do?
Do you remember the example of the man and the car we talked about?
A person simply tells the container that he needs a car and that the container will automatically be injected into a car.
What the hell is automatic? The injector is doing it.
Let's take a slow look.
The inject method for Containerimpl is shown below.    //o is everyone needs a car    . void inject (Object O, Internalcontext context) {            //Get all injectors on the person        list<injector> Injectors = This.injectors.get (O.getclass ());        for (Injector injector:injectors) {            //Call Injector            Injector.inject (context, o);}    }
What injectors are available on the "people".
This.injectors.get (O.getclass ());
In the following example, the person has a "method injector"
public class person{    private car car;    Public person () {    //other code    }    @Inject () public    void Setcar (Car c) {    this.car=c;    }    public void Drive () {    car.drive ();    }}
The injector is divided into two types, the method injector, and the property injector.
Its interface is as follows.
    /**     * Injects a field or method in a given object.     *    /Interface Injector extends Serializable {        void inject (internalcontext context, Object O);    }

Let's look at the property injector, which is similar to the method injector.
Static Class Fieldinjector implements Injector {    final Field field;    Final internalfactory<?> factory;    Final externalcontext<?> Externalcontext;    Public Fieldinjector (Containerimpl container, Field field, String name)    throws Missingdependencyexception {    This.field = field;    ...    }    key<?> key = Key.newinstance (Field.gettype (), name);    Factory = Container.getfactory (key);     Identification 2 ...    public void inject (internalcontext context, Object o) {        externalcontext<?> previous = Context.getexternalcon Text ();        Context.setexternalcontext (externalcontext);        Omit Trycatch        field.set (o, factory.create (context));//Identity 1    }}
ID 2 is the internalfactory of this key from the container.
In the code above the identification 1 out, the injector did the final work is injected.
I believe everyone is curious about the creat method of Internalfactory, how to realize it.
We may as well change the idea, Field.set () 's signature is as follows
public void set (Object obj, object value)        throws IllegalArgumentException, illegalaccessexception
If the field of person P is car c, and the car C2 inside the container,
Its invocation is
C.set (P,C2);
That is to say, the creat of Internalfactory is to produce the object that is managed inside the container.


Let's take a look at this parameter in Containerimpl injectors.
Final map<class<?>, list<injector>> injectors =    new Referencecache<class<?>, List< Injector>> () {        @Override        protected list<injector> Create (class<?> key) {            list< injector> injectors = new arraylist<injector> ();            Addinjectors (key, injectors); Identification 4            return injectors;        }    ;
What's going on, it looks so complicated.
Public abstract class Referencecache<k, v> extends Referencemap<k, v> {  private static final long serialve Rsionuid = 0;  Transient concurrentmap<object, future<v>> futures =      new Concurrenthashmap<object, Future<v >> ();  Transient threadlocal<future<v>> localfuture = new threadlocal<future<v>> ();    Protected abstract V Create (K key);    //... }

The REFERENCEMAP implements the map interface.

With Referencecatch, we operate the map much more efficiently, when we call the Get method, if the key already exists, it will return directly, otherwise call creat generated and cached, the next time no more create.

Also note that this create is an abstract method.

In other words, the injectors in Containerimpl is dynamically built at run time.
OK, let's take a look at the Addinjectors method at Mark 4.
    void Addinjectors (Class clazz, list<injector> injectors) {        if (clazz = = Object.class) {            return;        }        //ADD injectors for superclass first.        Read English, first call the parent class        Addinjectors (Clazz.getsuperclass (), injectors);        TODO (Crazybob): Filter out overridden members.        Addinjectorsforfields (Clazz.getdeclaredfields (), false, injectors);        Addinjectorsformethods (Clazz.getdeclaredmethods (), false, injectors);    }
Let's look at the property injector.
    void Addinjectorsforfields (field[] fields, Boolean statics,        list<injector> injectors) {        Addinjectorsformembers (Arrays.aslist (Fields), statics, injectors,                new injectorfactory<field> () {                    // Identify 5 public                    Injector Create (Containerimpl container, Field field,    String name) throws missingdependencyexception {                        return new Fieldinjector (container, field, name);}}                );    
In Addinjectorsforfields, there is only one line of code, which is called Addinjectorsformembers, whose last type of argument is injectorfactory.
   <m extends Member & annotatedelement> void Addinjectorsformembers (List<m> members, Boolean statics, list<injector> injectors, injectorfactory<m> injectorfactory) {for (M member:m Embers) {if (isStatic (member) = = statics) {//See if this member has inject this annotation I                Nject inject = member.getannotation (Inject.class); if (inject! = null) {try {///call injectorfactory here//See above generation Identification of the Code 5//is to produce a injecter just Injectors.add (Injectorfactory.create (this, member,                    Inject.value ())); } catch (Missingdependencyexception e) {if (inject.required ()) {thro                        W New Dependencyexception (e); }                    }                }            }        }    }

If you look at Addinjectorsformethods again, as long as we add inject to the class method or member variable annotation, the container will inject a corresponding instance into the parameter.


See here first, the next section we look at the implementation mechanism of xwork.

(Analysis struts2 source for me, is still very difficult, the article is not well written, welcome to shoot bricks, common progress)


Thanks GLT


Storage structure of the Xwork container

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.