Https://www.cnblogs.com/abcwt112/p/7777258.html
Theme
1 problems encountered in the work .... We have defined a controller base class, and all SPRINGMVC custom controller inherit it .... Define a @autowired httpservletrequest request within it; Can you take requestparamters and attributes from this object? Will there be any effect between multithreading?
Thinking
First thought, I think this should not be. Why?
The injection bean is when the spring container starts ... the implementation class for the request is in Tomcat (the servlet container I use is tomcat) .... I didn't configure this bean in spring's container. The injection should be a failure ...
A step back, even if it is successful .... That's 1 objects injected. Each time the servlet receives a request, it regenerates 1 requests ... It's obviously different from the one you started with .... It's impossible to be successful ...
If that's true .... Then there's no such article .... Then practiced a bit. It is possible to find this injection. There is no problem with using it to get data ....
In fact, I had a look at that time debug, basically know why can be taken to the data. But I don't know the principle and spring (SPRINGMVC) process ... So now look at it and write it down ...
Principle
First, let's take a look at the distinction between injecting request as a parameter in the method and injecting the request into the member domain ....
The member domain is injected with 1 proxy objects. is an instance of Autowireutils.objectfactorydelegatinginvocationhandler.
method is to inject the Requestfacade object of the general Tomcat native.
So this is different ...
1/** 2 * Reflective invocationhandler for lazy access to the current target object. 3/4 @SuppressWarnings ("Serial") 5 private static class Objectfactorydelegatinginvocationhandler Implemen
TS Invocationhandler, Serializable {6 7 private final objectfactory<?> objectfactory; 8 9 public Objectfactorydelegatinginvocationhandler (objectfactory<?> objectfactory) {A.
Objectfactory = objectfactory; @Override public Object Invoke (object proxy, Method method, object[] args) throws T hrowable {String methodname = Method.getname (); if (Methodname.equals ("equals")) {17
Only consider equal when proxies are identical.
return (proxy = = Args[0]); /Else if (methodname.equals ("Hashcode")) {//Use hashcode of proxy. 22 Return System.identityhashcode (prOxy); ' Else If ' (Methodname.equals ("toString")) {= return This.objectFactory.toS
Tring (); The try {return Method.invoke (This.objectFactory.getObject (), args) 29 catch (InvocationTargetException ex) {throw ex.gettargetexception (); 32 } 33} 34}
When most of the methods of the proxy object (that is, member domain request) are invoked, Objectfactorydelegatinginvocationhandler uses Objectfactory to get the object (native request), The method on the object is called again.
Then let's take a look at the steps that the Xmlwebapplicationcontext initializes to the request into the controller that has an impact on the injection request member domain.
Refresh method and Postprocessbeanfactory method
ApplicationContext's Abstract implementation class Abstractapplicationcontext (basically all AC's parent classes) defines the AC Refresh method (which includes the process of using beanfactory injection beans).
1 @Override 2 public void Refresh () throws Beansexception, IllegalStateException {3 synchronized (This.sta
Rtupshutdownmonitor) {4//Prepare this context for refreshing.
5//Record start WAC start initialization time, set activation tag, servlet related param set to env (previously done 1 times), verify the Env in the necessary props 6 preparerefresh ();
7 8//Tell the subclass to refresh the internal bean factory. 9//The old BF in the Bean deleted, new 1 BF, set some properties, load XML configuration file configurablelistablebeanfactory Beanfactory = Obtain
Freshbeanfactory ();
One//Prepare The Bean Factory for use in this context. 13//1. Set the BF parsing bean configuration Some objects that need to be used, such as Env. 2. Register some beanpostprocessor such as applicationcontextawareprocessor to set aware required object 14//3. Ignores some specific class injected objects and sets some specific class injected
The object is a specified value of 15//4. The properties map in some env is registered as a bean to the Bf preparebeanfactory (beanfactory); A try {//allows post-processing of the Bean factory in context SubclasSes. 20//1. Set up a beanpostprocess for Servletcontextaware implementation class to inject servlet related objects 21//2. Add Requetsscop in BF E, etc. scope 22//3. Register Servletcontext,config,servletinitparams,servletattribute as a bean to the BF p
Ostprocessbeanfactory (beanfactory);
Factory//Invoke the processors registered as beans in the context.
26//initialization and invocation of Beanfactorypostprocessor invokebeanfactorypostprocessors (beanfactory);
The/Register bean processors that intercept bean creation.
30//Registered Beanpostprocessors and registered to the Bf registerbeanpostprocessors (beanfactory);
The//Initialize message source is for the context.
Initmessagesource ();
//Initialize Event Multicaster for the this context.
Panax Notoginseng initapplicationeventmulticaster (); Special//Initialize other beans on specific context subClasses.
Onrefresh ();
A/Check for listener beans and register them.
Registerlisteners ();
Instantiate all remaining (Non-lazy-init) singletons.
Finishbeanfactoryinitialization (beanfactory);
Step:publish//Last corresponding event.
Finishrefresh (); (Beansexception ex) {Wuyi Logger.warn ("Exception encountered during context Initiali
Zation-cancelling refresh attempt ", ex);
Already//Destroy created singletons to avoid dangling.
Destroybeans ();
Flag/Reset ' active '.
CancelRefresh (ex);
Propagate//exception to caller.
Throw ex; 61} 62} 63}
There are 1 template methods
Postprocessbeanfactory (beanfactory);
This method allows abstractapplicationcontext subclasses to overwrite it and implement a custom for the BF (this time the bean's defination path has been specified, but the bean has not yet loaded).
Abstractrefreshablewebapplicationcontext covered this method.
1/** 2 * Register request/session scopes, a {@link servletcontextawareprocessor}, etc. 3 * 1. Set up a beanpostprocess for Servletcontextaware implementation class to inject servlet-related objects 4 * 2. In the BF, add Requetsscope etc. scope 5 * 3. Put serv Letcontext,config,servletinitparams,servletattribute as Bean registered to BF 6 * 7 * 8 @Override 9 protected VO ID postprocessbeanfactory (configurablelistablebeanfactory beanfactory) {10//Set a beanpostprocess to Servletcontexta Ware implementation classes inject servlet-related objects One beanfactory.addbeanpostprocessor (new Servletcontextawareprocessor (this.servletcontext, th
Is.servletconfig));
Beanfactory.ignoredependencyinterface (Servletcontextaware.class);
Beanfactory.ignoredependencyinterface (Servletconfigaware.class); 14 15//in BF add Requetsscope etc scope webapplicationcontextutils.registerwebapplicationscopes (beanfactory,
This.servletcontext); 17///Servletcontext,config,servletinitparams,servletattribute as Bean Register to BF 18 Webapplicationcontextutils.registerenvironmentbeans (Beanfactory, This.servletcontext, this.servletConfig); 19}
One of them is a step
Webapplicationcontextutils.registerwebapplicationscopes (Beanfactory, This.servletcontext);
Here are some special bean scope settings, such as Request,session,globalsession,application. (This is not the subject of my article, of course.)
Some special autowired beans are set at the same time
Beanfactory.registerresolvabledependency (Servletrequest.class, New Requestobjectfactory ());
Beanfactory.registerresolvabledependency (Servletresponse.class, New Responseobjectfactory ());
Beanfactory.registerresolvabledependency (Httpsession.class, New Sessionobjectfactory ());
Beanfactory.registerresolvabledependency (Webrequest.class, New Webrequestobjectfactory ());
ServletRequest implementation classes (such as HttpServletRequest) are specified to use requestobjectfactory injection.
Requestobjectfactory
Requestobjectfactory is a objectfactory is the objectfactory in front of the objectfactorydelegatinginvocationhandler. So calling a method on a member domain request object is actually Gets the object by Requestobjectfactory and then calls the method.
1 /**
2 * Factory that exposes, the current request object, on demand.
3
/4 @SuppressWarnings ("Serial")
5 private static class Requestobjectfactory implements Objectfactory<servletrequest>, Serializable {
6
7 @Override 8 public ServletRequest GetObject () {
9 return currentrequestattributes (). Getrequest ();
One
@Override public String toString () { HttpServletRequest ";
}
1 /** 2 * Return to the current requestattributes instance as servletrequestattributes.
3 *
4 * @see requestcontextholder#currentrequestattributes ()
5 */
6 private static Servletrequestattributes currentrequestattributes () {
7 requestattributes requestattr = Requestcontextholder.currentrequestattributes ();
8 if (!) ( Requestattr instanceof Servletrequestattributes)) {
9 throw new IllegalStateException ("The current request is Not a servlet request ");
All return (servletrequestattributes) requestattr;
The }
The GetObject method for Requestobjectfactory is simply to invoke the static method
Requestcontextholder.currentrequestattributes (). Getrequest ()
Requestcontextholder
1 public static Requestattributes Currentrequestattributes () throws IllegalStateException {2 Requestattribu
TES attributes = Getrequestattributes (); 3 if (attributes = = null) {4 if (jsfpresent) {5 attributes = Facesrequestattribute
Sfactory.getfacesrequestattributes (); 6} 7 if (attributes = = null) {8 throw new IllegalStateException ("No Thread-bou nd request found: "+ 9" Are you referring to request attributes outside of a actual web request , "+" or processing a request outside of the originally receiving thread? "+ 11 "If you are are actually operating within a Web request and still receive this message," + 12 "Your code is probably running outside of Dispatcherservlet/dispatcherportlet:" + "in" case, use Requestcontextlistener or Requestcontextfilter to ExpoSE the current request. ");
attributes return; 17}
1 /**
2 * Return of the Requestattributes currently bound to the thread.
3 * @return The requestattributes currently bound to the thread,
4 * or {@code null} if none bound
5 * /
6 public static Requestattributes getrequestattributes () {
7 requestattributes attributes = Requestattributesholder.get ();
8 if (attributes = = null) {
9 attributes = Inheritablerequestattributesholder.get ();
All return attributes;
The }
1 private static final threadlocal<requestattributes> Requestattributesholder =
2 New Namedthreadlocal<requestattributes> ("Request attributes");
3
4 private static final threadlocal<requestattributes> Inheritablerequestattributesholder =
5 new Namedinheritablethreadlocal<requestattributes> ("Request context");
There are some key methods.
So ultimately, the request is taken from the threadlocal ...
Frameworkservlet
So when was the request set to the threadlocal?
is operated in the parent class frameworkservlet of the Springmvc Dispatcherservlet.
1 /**
2 * Delegate get requests to processrequest/doservice.
3 * <p>will also is invoked by HttpServlet ' s default implementation of {@code Dohead},
4 * with a {@code Nobodyresponse} that just captures the content length.
5 * @see #doService
6 * @see #doHead
7 /
8 @Override
9 protected Final void Doget (HttpServletRequest request, httpservletresponse response)
throws Servletexception, IOException {
One processrequest (request, response); /** * Delegate POST requests to {@link #processRequest}. * @see #doService
/@Override protected final void DoPost ( HttpServletRequest request, HttpServletResponse response) throws Servletexception, IOException { ProcessRequest (request, response); }
Whether you are doget or Dopost or Doxxx methods are commissioned ProcessRequest method to do.
1/** 2 * Process this request, publishing a event regardless of the outcome.
3 * <p>the actual event handling is performed by the abstract 4 * {@link #doService} template method. 5/6 protected final void ProcessRequest (HttpServletRequest request, httpservletresponse response) 7 Throws Servletexception, IOException {8 9 long starttime = System.currenttimemillis ();
e failurecause = null;
One localecontext Previouslocalecontext = Localecontextholder.getlocalecontext ();
Localecontext Localecontext = buildlocalecontext (request);
Requestattributes previousattributes = Requestcontextholder.getrequestattributes ();
Servletrequestattributes requestattributes = buildrequestattributes (Request, response, previousattributes);
Webasyncmanager Asyncmanager = Webasyncutils.getasyncmanager (request); Asyncmanager.registercallableinterceptor (FramewoRkServlet.class.getName (), New Requestbindinginterceptor ());
Initcontextholders (Request, Localecontext, requestattributes); The try {doservice (Request, response), and catch (Servletexception ex) {27
Failurecause = ex;
Throw ex; The catch (IOException ex) {failurecause = ex; throw ex; 33} 3 4 catch (Throwable ex) {failurecause = ex; throw new Nestedservletexception ("Reques
T processing failed ", ex); Panax resetcontextholders (Request, Previouslocalecontext, Previousattribute
s);
if (requestattributes!= null) {requestattributes.requestcompleted (); 43} if (logger.isdebugenabled ()) {(Failurecause!= null) {The TH Is.logger.debug ("Could not complete requeSt ", Failurecause); M/Else {asyncmanager.isconcurrenthandlingstarted () {51
Logger.debug ("Leaving response open for concurrent processing"); This.logger.debug else {The successfully complete
D request "); The publishrequesthandledevent (Request, RESP
Onse, StartTime, Failurecause); 60} 61}
which calls the
Initcontextholders (Request, Localecontext, requestattributes);
1 private void Initcontextholders (
2 httpservletrequest request, Localecontext Localecontext, Requestattributes requestattributes) {
3
4 if (localecontext!= null) {
5 Localecontextholder.setlocalecontext (Localecontext, this.threadcontextinheritable);
6 }
7 if (requestattributes!= null) {
8 requestcontextholder.setrequestattributes ( Requestattributes, this.threadcontextinheritable);
9 if (logger.istraceenabled ()) {One logger.trace ("Bound request context to Thread:" + request);
}
Is here set to the Requestcontextholder of the threadlocal ...
Summary
1. The request injected in controller is the JDK dynamic proxy object, instance of Objectfactorydelegatinginvocationhandler. When we call the member domain request method, we actually invoke the Objectfactory GetObject () Object. The objectfactory here is requestobjectfactory.
The GetObject of 2.RequestObjectFactory is actually taken from the threadlocal of Requestcontextholder.
3. The request has just entered the SPRINGMVC Dispatcherservlet will be set to the request related objects to Requestcontextholder threadlocal.