Spring AOP, SpringMVC, these two should be domestic interview questions, there are many answers on the Internet, in fact, back to back can be. But today I take you out of the source code, look at his principle. In order to make a deeper impression, the interview time.

Spring AOP principle

A brief description of AOP design:

  1. Each Bean will be proxied by the JDK or Cglib. It depends on whether there is an interface.
  2. Each Bean will have multiple “method interceptors.” Note: Interceptors have two layers. The outer layer is controlled by the Spring kernel, and the inner layer is user-set, or AOP.
  3. When a proxy method is invoked, it passes through the outer interceptor, which determines which “inner interceptors” the method should execute based on various information about the method. The design of the inner interceptor is the design of the responsibility chain.

Is not thief simple. In fact, I have already written a simple example of implementing multiple proxies using Cglib

It’s easier when you’re done.

AOP can be broken down into two parts, oh no, to analyze… First: the creation of the proxy; Second: invocation of the proxy.

Note: we try to paste as little code as possible, try to use words, because the interview, also written, can not ask you to turn over the code… So, keep it a little bit simple here. For details, look at the Interface 21 source code. For more details, look at the Spring Framework’s latest Master branch code.

Code location: com.interface21.aop package.

Begin to analyze:

  1. Proxy creation (step-by-step) :
  • First, you need to create a proxy factory, which requires three important pieces of information: the interceptor array, the target object interface array, and the target object.
  • When a proxy factory is created, one more default interceptor is added to the end of the interceptor array — for the final call to the target method.
  • When the getProxy method is called, a proxy object (JDK or Cglib) is returned based on the condition that the number of interfaces is more than zero.
  • Note: When you create a proxy object, you create an outer interceptor, which is the Spring kernel interceptor. Used to control the entire AOP process.
  1. Invocation of proxy
  • When a proxy object is called, the outer interceptor is triggered.
  • The outer interceptor creates the inner interceptor chain based on the proxy configuration information. During creation, the expression is used to determine whether the current interception matches the interceptor. The interceptor chain design pattern is the chain of responsibility pattern.
  • When the chain ends, the default interceptor on the tail of the proxy is triggered to invoke the target method. Finally return.

Side note: Spring transactions are nothing more than interceptors.

Here’s a less-than-standard UML diagram:

Here is a flow chart for the invocation process:

This is probably the case, for more details, please see the source code, if not very clear words, please consult me, I am not sure whether this picture is drawn very easy to understand – at least the sprout new to understand can be called easy to understand.

Spring MVC process

Here’s a picture:

Code location: com. Interface21. Web. Servlet. DispatcherServlet# doService

(Yes, the code for Spring 1.0 is very simple. Now Spring is too bloated after 15 years of development. Interface 21 is the best code from a learning point of view.)

The code is as follows:

1. Set properties

// 1. Set the properties
// Make web application context available
request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());

// Make locale resolver available
request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);

// Make theme resolver available
request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
Copy the code

2. Obtain the corresponding handler execution chain based on the Request URL, which is actually the interceptor and Controller proxy object.

// 2. Find the handler to return to the chain
HandlerExecutionChain mappedHandler = getHandler(request);
Copy the code

3. Obtain the adapter of the handler

// This will throw an exception if no adapter is found
// 3. Return the adapter to handler
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
Copy the code

What exactly does this adapter do? The HandlerAdapter comment reads: This interface is not intended for application developers. It is available to handlers who want to develop their own web workflow. This interface is not intended for application developers. It is suitable for processors that want to develop their own Web workflow.

Just to say, if you want to do something before you process the handler, you might want to do this, which is adapt the handler. For example, the Spring test program does this:

public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object delegate)
		    throws IOException, ServletException {
                      // You may need doSomething.......
			((MyHandler) delegate).doSomething(request);
			return null;
		}
Copy the code

4. Loop through handler’s Pre interceptor

// 4. Loop through handler's Pre interceptor
for (int i = 0; i < mappedHandler.getInterceptors().length; i++) {
	HandlerInterceptor interceptor = mappedHandler.getInterceptors()[i];
	// Pre interceptor
	if(! interceptor.preHandle(request, response, mappedHandler.getHandler())) {return; }}Copy the code

There’s nothing to talk about, is there?

5. Execute the actual handler and return ModelAndView(Handler is a proxy object that may execute AOP)

// 5. Execute the real handler and return ModelAndView(Handler is a proxy object that may execute AOP)
ModelAndView mv = ha.handle(request, response, mappedHandler.getHandler());
Copy the code

6. Loop through handler’s POST interceptor

// 6. Loop through handler's POST interceptor
for (int i = mappedHandler.getInterceptors().length - 1; i >=0 ; i--) {
	HandlerInterceptor interceptor = mappedHandler.getInterceptors()[i];
	// Post interceptor
	interceptor.postHandle(request, response, mappedHandler.getHandler());
}
Copy the code

7. Obtain View instance according to ModelAndView information

View view = null;
if (mv.isReference()) {
	// We need to resolve this view name
	// 7. Get the View instance according to ModelAndView information
	view = this.viewResolver.resolveViewName(mv.getViewName(), locale);
}
Copy the code

8. Render View returns

// 8. Render View returns
view.render(mv.getModel(), request, response);
Copy the code