Off-topic, the article has a large number of identification 1 Identification 2, you can use Ctrl+f to find.
the class that makes up the cacheThe main is the following two:
Com.opensymphony.xwork2.inject.util.referencecache<k, v> Com.opensymphony.xwork2.inject.util.ReferenceMap <k, v>
The former inherits from the latter.
Let's see Referencemap first.
public class Referencemap<k, v> implements Map<k, V>, Serializable { private static final long Serialversi Onuid = 0; Transient concurrentmap<object, object> delegate; Final Referencetype Keyreferencetype; Final Referencetype Valuereferencetype;}
Of the three instance variables, what weak references are involved in referencetype, soft references We don't care for the moment.
Delegate is where the cache data is stored.
Look at Referencecache again.
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>> ();
For threadlocal knowledge, you can refer to the My book
Deep understanding of Threadlocal
Cached Operating InterfacesOK, now we start to look at the source code of Referencemap, starting from the Get method.
Public V get (final Object key) { ensurenotnull (key); Return Internalget ((K) key); Ensurenotnull look at his name and know what it is. V internalget (K key) { Object valuereference = Delegate.get (Makekeyreferenceaware (key));//ID 1 return Valuereference = = null ? NULL : (V) Dereferencevalue (valuereference); }
As for what Makekeyreferenceaware is, I can only say that it is related to strong references (strong), weak references (WEAK), soft references (SOFT), the last Kind of ghost references (Phanton), what are the differences between them, I'm not sure. But I don't think this is the point.
Identify the code at 1, and everyone sees it as follows OK
Delegate.get (key);
The first time to get a key,delegate is necessarily not, so Internalget returns null,get also returns NULL.
OK, let's take a look at Referencecache's Get method.
@Override public V get (final Object key) { v value = super.get (key); Identify 2 return (value = = null) ? Internalcreate ((K) key)//ID 9 : value; }
Identity 2 is finally called the Referencemap Internalget method, the first time is definitely null, we look at the Internalcreate method.
V internalcreate (K key) {try {futuretask<v> futuretask = new futuretask<v> (New Callablecre Ate (key)); Use a reference so we get the same equality semantics. Object keyreference = Referencekey (key); Referencekey method Everyone should not see future<v> future = Futures.putifabsent (KeyReference, Futuretask); Identifies 4 if (future = = NULL) {//winning thread. try {//localfuture What role to play here//until now I have not seen understand if (localfuture.get () = null) {throw new Illega Lstateexception ("Nested creations within the same cache is not allowed."); } localfuture.set (Futuretask); Futuretask.run (); Identification 3 V value = Futuretask.get (); Identification 5 putstrategy (). Execute (this,//ID 7 keyreference, referencevalue (keyreference, value)); return value; } finally {Localfuture.remove (); Futures.remove (KeyReference); }} else { Wait for winning thread. return Future.get (); }//Omit Catch}}
One of the most important callablecreate is the call method. Call method is called at the above code identification 3.
Another word of crap.
For threads, calling the Run method directly does not have a thread effect, which is equivalent to a function call, whereas for Futuretask, the call to the Run method is to start the thread and invoke the call method.
Identifies the concurrenthashmap that called the putifabsent at 4.
For this method, its effect is equal to
if (!map.containskey (key)) return Map.put (key, value); else return Map.get (key);
See a small example
public class Concurrenthashmaptest {public static void Main (string[] args) { concurrenthashmap<people, String> chm=new Concurrenthashmap<people, string> (); People p=new people (); System.out.println (Chm.putifabsent (P, "1")); System.out.println (Chm.putifabsent (P, "2")); System.out.println (Chm.get (P));} } Class people{ String name; String age;}
Run the result as
Null
1
1
Thus the future of the identity 4 must be null.
To mark 5, we have to look at the call method.
Class Callablecreate implements callable<v> { K key; Public callablecreate (K key) { This.key = key; } Public V Call () { //Try one More time (a previous the future could has come and gone.) V value = Internalget (key); Find if (value! = null) { return value } in the delegate of the parent class; Create value. Value = Create (key); Identify 6 if (value = = null) { throw new NullPointerException ( "Create (K) returned NULL for:" + key); } return value; } }
Internalget is defined in the Referencemap. As already mentioned above. is to look inside the delegate.
So we have to look at the code inside the logo 6.
But create itself is an abstract method.
In fact now in the subclass.
OK, so now we have to introduce the injector in the title of this article.
Injectors is an instance variable in the container Containerimpl in Struts2.
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); return injectors; } ;
OK creat returns all the injectors that exist with this key (which is actually a class).
As for the concrete realization of addinjector
We can see my book.
Storage structure of Struts container
The This.injectors.get (O.getclass ()) in the inject method inside the Containerimpl class begins the call cache. To see the logo 2
void inject (Object O, Internalcontext context) { list<injector> injectors = This.injectors.get (O.getclass ()) ; for (Injector injector:injectors) { injector.inject (context, o);} }
Here is the identity 7.
Putstrategy (). Execute (this,keyreference, Referencevalue (keyreference, value));
policy mode in the cache
Protected interface Strategy {public Object execute (referencemap map, Object KeyReference, Object Valuereferenc e); } Protected Strategy Putstrategy () {return putstrategy.put; Direct put} protected strategy Putifabsentstrategy () {return putstrategy.put_if_absent; Does not exist when put} protected strategy Replacestrategy () {return putstrategy.replace; Replace}//Enumeration class holds data in three ways put put_if_absent REPLACE private enum Putstrategy implements strategy {PUT {public Ob Ject Execute (Referencemap map, Object KeyReference, Object valuereference) {return map.delegate.put (Keyre Ference, valuereference); }}, REPLACE {public Object execute (referencemap map, Object KeyReference, Object valuereference) { Return Map.delegate.replace (KeyReference, valuereference); }}, Put_if_absent {public Object execute (referencemap map, Object KeyReference, Object Valuereferenc e) {return map.delegate.putIfAbsENT (KeyReference, valuereference); } }; };
Thus the identity 7 and so on call
Map.delegate.put (KeyReference, valuereference);
Map is Referencemap.
Look down again, go back, until you identify 9.
Finally to the inject method inside the Containerimpl class. We have all the registrars for a class.
Second SearchOK just for the first time directly inserted, now let's look at the true value of the cache: Second lookup.
The first is the this.injectors.get in the inject method inside the Containerimpl class (O.getclass ())
Then the identity 2 followed by Internalget.
The lookup cache is finished.
In fact, there is another problem:
Internalcreate inside.
future<v> future = Futures.putifabsent (KeyReference, Futuretask);
When is the future not equal to NULL?
In addition this cache inside, if everybody carefully study, can ask the question still many many.
This article can only be said to introduce you to the introduction.
Thanks GLT
References:http://blog.csdn.net/yanlinwang/article/details/8916456
Cache----in STRUTS2 take injector as an example