public void createChain(String chainName, String chainDefinition) {
        if (!StringUtils.hasText(chainName)) {
            throw new NullPointerException("chainName cannot be null or empty.");
        }
        if (!StringUtils.hasText(chainDefinition)) {
            throw new NullPointerException("chainDefinition cannot be null or empty.");
        }

        if (LOGGER.isDebugEnabled()) {
            LOGGER.debug("Creating chain [" + chainName + "] with global filters "
                    + globalFilterNames + " and from String definition ["
                    + chainDefinition + "]");
        }

        // first add each of global filters
        if (!CollectionUtils.isEmpty(globalFilterNames)) {
            globalFilterNames.stream().forEach(filterName -> addToChain(chainName, filterName));
        }

        //parse the value by tokenizing it to get the resulting filter-specific config entries
        //
        //e.g. for a value of
        //
        //     "authc, roles[admin,user], perms[file:edit]"
        //
        // the resulting token array would equal
        //
        //     { "authc", "roles[admin,user]", "perms[file:edit]" }
        //
        String[] filterTokens = splitChainDefinition(chainDefinition);

        //each token is specific to each filter.
        //strip the name and extract any filter-specific config between brackets [ ]
        for (String token : filterTokens) {
            String[] nameConfigPair = toNameConfigPair(token);

            //now we have the filter name, path and (possibly null) path-specific config.  Let's apply them:
            addToChain(chainName, nameConfigPair[0], nameConfigPair[1]);
        }
    }
Sets the {@code FilterConfig} provided by the Servlet container at webapp startup.

@param filterConfig the {@code FilterConfig} provided by the Servlet container at webapp startup.
web/src/main/java/org/apache/shiro/web/filter/mgt/DefaultFilterChainManager.java