struts2 framework for the implementation process and parse the source code

struts2 overall implementation process

A core filter initialization
web.xml configuration filter core StrutsPrepareAndExecuteFilter, loads web.xml filter configured servlet container launches, init method for performing a filter, and instantiate the object (filter TUTORIAL own knowledge please ).
The core is the init method dispatcher = init.initDispatcher (config);
proceed to:

public Dispatcher initDispatcher( HostConfig filterConfig ) {
        Dispatcher dispatcher = createDispatcher(filterConfig);
        dispatcher.init();
        return dispatcher;
    }

Entering dispatcher.init ();
see the following block of code:

	init_DefaultProperties(); // [1]
    init_TraditionalXmlConfigurations(); // [2]
    init_LegacyStrutsProperties(); // [3]
    init_CustomConfigurationProviders(); // [5]
    init_FilterInitParameters() ; // [6]
    init_AliasStandardObjects() ; // [7]

Here will be loaded configuration file to initialize struts2 framework, also marks the struts2 order to load the configuration file.
1, init_DefaultProperties (); // [
1] Load org / apache / struts2 / default.properties file
Click to view the source code:

private void init_DefaultProperties() {
    configurationManager.addContainerProvider(new DefaultPropertiesProvider());
}

Continue to click to enter:

public void register(ContainerBuilder builder, LocatableProperties props) throws ConfigurationException {
    try {
        PropertiesSettings defaultSettings = new PropertiesSettings("org/apache/struts2/default");
        loadSettings(props, defaultSettings);
    } catch (Exception e) {
        throw new ConfigurationException("Could not find or error in org/apache/struts2/default.properties", e);
    }
}

Continue to click new PropertiesSettings ( "org / apache / struts2 / default") to enter:

public PropertiesSettings(String name) {
    URL settingsUrl = ClassLoaderUtil.getResource(name + ".properties", getClass());
    略......
}

Here it has been very obvious to find the path to org / apache / struts2 / default.properties file.
The configuration file is actually a bit constants. Free to view.

2.init_TraditionalXmlConfigurations(); // [2]
加载
struts-default.xml
struts-plugin.xml
struts.xml

View source code:

private void init_TraditionalXmlConfigurations() {
    String configPaths = initParams.get("config");
    if (configPaths == null) {
        configPaths = DEFAULT_CONFIGURATION_PATHS;
    }
    String[] files = configPaths.split("\\s*[,]\\s*");
    for (String file : files) {
        if (file.endsWith(".xml")) {
            if ("xwork.xml".equals(file)) {
                configurationManager.addContainerProvider(createXmlConfigurationProvider(file, false));
            } else {
                configurationManager.addContainerProvider(createStrutsXmlConfigurationProvider(file, false, servletContext));
            }
        } else {
            throw new IllegalArgumentException("Invalid configuration file name");
        }
    }
}

Where: DEFAULT_CONFIGURATION_PATHS is defined as:

private static final String DEFAULT_CONFIGURATION_PATHS = "struts-default.xml,struts-plugin.xml,struts.xml";

Here is evident that this sentence is loaded configuration file:
Struts-default.xml
Struts-the plugin.xml
struts.xml

  • struts-default.xml

Struts2 file for the core package.

  • struts-plugin.xml

Struts2 plug-in package, allows you to customize struts2 multiple plug-ins, each plug-in jar package has a struts-plugin.xml configuration file.

  • struts.xml
    to a user-defined configuration files, stored in the resource directory.

3.init_LegacyStrutsProperties (); // [3]
Load struts2.propertoes custom files can be used to customize the core value of the constant coverage struts2 defined struts2.properties inside the jar.

Click to view source code

   private void init_LegacyStrutsProperties() {
        configurationManager.addContainerProvider(new PropertiesConfigurationProvider());
    }

Continue to enter:

public void register(ContainerBuilder builder, LocatableProperties props) throws ConfigurationException {
    final DefaultSettings settings = new DefaultSettings();
    loadSettings(props, settings);
}

carry on:

    public DefaultSettings() {

        ArrayList<Settings> list = new ArrayList<Settings>();

        // stuts.properties, default.properties
        try {
            list.add(new PropertiesSettings("struts"));
        } catch (Exception e) {
            LOG.warn("DefaultSettings: Could not find or error in struts.properties", e);
        }
略.....
    }

Enter new PropertiesSettings ( "struts"), you can see:

URL settingsUrl = ClassLoaderUtil.getResource(name + ".properties", getClass());

Looking struts2.properties configuration file in the resource directory.
4, init_CustomConfigurationProviders (); // [
5] user-defined configuration, substantially do not have access, not expand in detail.
5, init_FilterInitParameters (); // [
6] Load web.xml file.
It should be noted here:
web.xml file will be loaded at boot time servlet container, and other operations such as initialization of the filter, where loading refers framework struts2 struts2 own tags defined web.xml file parsing.
Specific principle is unknown.
6, init_AliasStandardObjects (); // [
7] Load bean configuration.
Code below (removal of only a portion of self-inspection):

    private void init_AliasStandardObjects() {
            configurationManager.addContainerProvider(new DefaultBeanSelectionProvider());
        }
点击进入:

    public void register(ContainerBuilder builder, LocatableProperties props) {
        alias(ObjectFactory.class, StrutsConstants.STRUTS_OBJECTFACTORY, builder, props);
略...
        /** Checker is used mostly in interceptors, so there be one instance of checker per interceptor with Scope.DEFAULT **/
        alias(ExcludedPatternsChecker.class, StrutsConstants.STRUTS_EXCLUDED_PATTERNS_CHECKER, builder, props, Scope.DEFAULT);
        alias(AcceptedPatternsChecker.class, StrutsConstants.STRUTS_ACCEPTED_PATTERNS_CHECKER, builder, props, Scope.DEFAULT);
    
        switchDevMode(props);
    
        // Convert Struts properties into XWork properties
        convertIfExist(props, StrutsConstants.STRUTS_LOG_MISSING_PROPERTIES, XWorkConstants.LOG_MISSING_PROPERTIES);
        略...   
        LocalizedTextUtil.addDefaultResourceBundle("org/apache/struts2/struts-messages");
        loadCustomResourceBundles(props);
    }

To summarize, struts2 framework configuration files to load order:

  • default.properties in the core package
  • struts-default.xml in the core package
  • struts-plugin.xml in plugin package
  • struts.xml custom resource directory under
  • struts.properties custom resource directory under
  • web.xml

Second, the interceptor
Struts2 interceptor is intercepted prior embodiment of a method of accessing an Action or Action, or after a field, and is pluggable Struts2 interceptor, the interceptor is an implementation of AOP.
Source Analysis:

        public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {

    HttpServletRequest request = (HttpServletRequest) req;
    HttpServletResponse response = (HttpServletResponse) res;

    try {
        if (excludedPatterns != null && prepare.isUrlExcluded(request, excludedPatterns)) {
            chain.doFilter(request, response);
        } else {
            prepare.setEncodingAndLocale(request, response);
            prepare.createActionContext(request, response);
            prepare.assignDispatcherToThread();
            request = prepare.wrapRequest(request);
            ActionMapping mapping = prepare.findActionMapping(request, response, true);
            if (mapping == null) {
                boolean handled = execute.executeStaticResourceRequest(request, response);
                if (!handled) {
                    chain.doFilter(request, response);
                }
            } else {
                execute.executeAction(request, response, mapping);
            }
        }
    } finally {
        prepare.cleanupRequest(request);
    }
}

Enter execute.executeAction method:

public void serviceAction(HttpServletRequest request, HttpServletResponse response, ActionMapping mapping)
        throws ServletException {

    Map<String, Object> extraContext = createContextMap(request, response, mapping);

    // If there was a previous value stack, then create a new copy and pass it in to be used by the new Action
    ValueStack stack = (ValueStack) request.getAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY);
    boolean nullStack = stack == null;
    if (nullStack) {
        ActionContext ctx = ActionContext.getContext();
        if (ctx != null) {
            stack = ctx.getValueStack();
        }
    }
    if (stack != null) {
        extraContext.put(ActionContext.VALUE_STACK, valueStackFactory.createValueStack(stack));
    }

    String timerKey = "Handling request from Dispatcher";
    try {
        UtilTimerStack.push(timerKey);
        String namespace = mapping.getNamespace();
        String name = mapping.getName();
        String method = mapping.getMethod();

        ActionProxy proxy = getContainer().getInstance(ActionProxyFactory.class).createActionProxy(
                namespace, name, method, extraContext, true, false);

        request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, proxy.getInvocation().getStack());

        // if the ActionMapping says to go straight to a result, do it!
        if (mapping.getResult() != null) {
            Result result = mapping.getResult();
            result.execute(proxy.getInvocation());
        } else {
            proxy.execute();
        }

        // If there was a previous value stack then set it back onto the request
        if (!nullStack) {
            request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, stack);
        }
    } catch (ConfigurationException e) {
        logConfigurationException(request, e);
        sendError(request, response, HttpServletResponse.SC_NOT_FOUND, e);
    } catch (Exception e) {
        if (handleException || devMode) {
            sendError(request, response, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e);
        } else {
            throw new ServletException(e);
        }
    } finally {
        UtilTimerStack.pop(timerKey);
    }
}

Here you can see the Action created the proxy object. Create a proxy object into the internal view:

public ActionProxy createActionProxy(ActionInvocation inv, String namespace, String actionName, String methodName, boolean executeResult, boolean cleanupContext) {

    DefaultActionProxy proxy = new DefaultActionProxy(inv, namespace, actionName, methodName, executeResult, cleanupContext);
    container.inject(proxy);
    proxy.prepare();
    return proxy;
}

Proceed to prepare method, and then enter the init method:

public void init(ActionProxy proxy) {
    this.proxy = proxy;
    Map<String, Object> contextMap = createContextMap();

    // Setting this so that other classes, like object factories, can use the ActionProxy and other
    // contextual information to operate
    ActionContext actionContext = ActionContext.getContext();

    if (actionContext != null) {
        actionContext.setActionInvocation(this);
    }

    createAction(contextMap);

    if (pushAction) {
        stack.push(action);
        contextMap.put("action", action);
    }

    invocationContext = new ActionContext(contextMap);
    invocationContext.setName(proxy.getActionName());

    // get a new List so we don't get problems with the iterator if someone changes the list
    List<InterceptorMapping> interceptorList = new ArrayList<InterceptorMapping>(proxy.getConfig().getInterceptors());
    interceptors = interceptorList.iterator();
}

Here to get the set of interceptors and returned as an iterator, the iterator here interceptor is the default set of struts-default.xml defined in the document, a total of 18.

After generating the proxy object continues, Execute method, as follows:

public String execute() throws Exception {
    ActionContext nestedContext = ActionContext.getContext();
    ActionContext.setContext(invocation.getInvocationContext());

    String retCode = null;

    String profileKey = "execute: ";
    try {
        UtilTimerStack.push(profileKey);

        retCode = invocation.invoke();
    } finally {
        if (cleanupContext) {
            ActionContext.setContext(nestedContext);
        }
        UtilTimerStack.pop(profileKey);
    }

    return retCode;
}

Here is the core of the implementation of interceptors, to enter invoke method, as follows:

    public String invoke() throws Exception {
        String profileKey = "invoke: ";
        try {
            UtilTimerStack.push(profileKey);

            if (executed) {
                throw new IllegalStateException("Action has already executed");
            }

            if (interceptors.hasNext()) {
                final InterceptorMapping interceptor = interceptors.next();
                String interceptorMsg = "interceptor: " + interceptor.getName();
                UtilTimerStack.push(interceptorMsg);
                try {
                                resultCode = interceptor.getInterceptor().intercept(DefaultActionInvocation.this);
                            }
                finally {
                    UtilTimerStack.pop(interceptorMsg);
                }
            } else {
                resultCode = invokeActionOnly();
           }
略.....
    }

intercept method is to actually perform interception, you can easily find a blocker into the view, as ExceptionMappingInterceptor (one of the default of 18 interceptors), as follows:

public String intercept(ActionInvocation invocation) throws Exception {
    String result;

    try {
        result = invocation.invoke();
    } catch (Exception e) {
        if (isLogEnabled()) {
            handleLogging(e);
        }
        List<ExceptionMappingConfig> exceptionMappings = invocation.getProxy().getConfig().getExceptionMappings();
        ExceptionMappingConfig mappingConfig = this.findMappingFromExceptions(exceptionMappings, e);
        if (mappingConfig != null && mappingConfig.getResult()!=null) {
            Map parameterMap = mappingConfig.getParams();
            // create a mutable HashMap since some interceptors will remove parameters, and parameterMap is immutable
            invocation.getInvocationContext().setParameters(new HashMap<String, Object>(parameterMap));
            result = mappingConfig.getResult();
            publishException(invocation, new ExceptionHolder(e));
        } else {
            throw e;
        }
    }

    return result;
}

Found inside the interceptor to intercept method calls another method, will return to the front if (interceptors.hasNext ()) judgment, the iterator if there is the next element, indicating that 18 interceptors default not all executed, so recursively repeated.

Routine and spring AOP interceptors are very similar, technique is the use of dynamic proxy, the request for specific processing. struts2 interceptors can also customize the means to intercept for the implementation of certain methods, methods using reflection of the target execution, and to do certain things before and after execution to dynamically change or enhance their functions.

Released six original articles · won praise 0 · Views 125

Guess you like

Origin blog.csdn.net/li210530/article/details/99167943