tomcat类加载器WebappClassLoader

类/资源加载优先顺序:web-inf/classes下优先:

这里的类是.class文件,资源是指配置文件,比如在web.xml文件中配置的spring配置文件:

<context-param>
    <param-name>contextConfigLocation</param-name>
        <param-value>
            <!-- classpath:spring/spring-nacos.xml -->
            classpath:spring/spring-dao.xml
            classpath:spring/spring-service.xml
            classpath:spring/spring-dubbo*.xml
            classpath:spring/spring-quartz*.xml
            classpath:cis/spring-nacos.xml
        </param-value>
  </context-param>

 tomcat类加载机制打破了jvm规范中的双亲委托机制,tomcat下各应用下的类而是由WebappClassLoader率先加载。

public class WebappClassLoader extends WebappClassLoaderBase {
.....
}

WebappClassLoader类继承自WebappClassLoaderBase,在WebappClassLoaderBase的getResourceAsStream方法中展现了tomcat的加载机制:

@Override
    public InputStream getResourceAsStream(String name) {

        if (log.isDebugEnabled())
            log.debug("getResourceAsStream(" + name + ")");

        checkStateForResourceLoading(name);

        InputStream stream = null;

        //从缓存加载
        // (0) Check for a cached copy of this resource
        stream = findLoadedResource(name);
        if (stream != null) {
            if (log.isDebugEnabled())
                log.debug("  --> Returning stream from cache");
            return (stream);
        }

        boolean delegateFirst = delegate || filter(name);

        //由父加载器加载
        // (1) Delegate to parent if requested
        if (delegateFirst) {
            if (log.isDebugEnabled())
                log.debug("  Delegating to parent classloader " + parent);
            stream = parent.getResourceAsStream(name);
            if (stream != null) {
                // FIXME - cache???
                if (log.isDebugEnabled())
                    log.debug("  --> Returning stream from parent");
                return (stream);
            }
        }

        //由自己加载
        // (2) Search local repositories
        if (log.isDebugEnabled())
            log.debug("  Searching local repositories");
        URL url = findResource(name);
        if (url != null) {
            // FIXME - cache???
            if (log.isDebugEnabled())
                log.debug("  --> Returning stream from local");
            stream = findLoadedResource(name);
            try {
                if (hasExternalRepositories && (stream == null))
                    stream = url.openStream();
            } catch (IOException e) {
                // Ignore
            }
            if (stream != null)
                return (stream);
        }

        //由父加载器加载
        // (3) Delegate to parent unconditionally
        if (!delegateFirst) {
            if (log.isDebugEnabled())
                log.debug("  Delegating to parent classloader unconditionally " + parent);
            stream = parent.getResourceAsStream(name);
            if (stream != null) {
                // FIXME - cache???
                if (log.isDebugEnabled())
                    log.debug("  --> Returning stream from parent");
                return (stream);
            }
        }
    
        // (4) Resource was not found
        if (log.isDebugEnabled())
            log.debug("  --> Resource not found, returning null");
        return (null);

    }

由上边的源码可以看出:tomcat的WebappClassLoader加载器的加载机制:

①从缓存加载

②缓存找不到时,由父加载器加载(这里也不是全部)

③父加载器加载不到时,由自己加载

④自己加载不到时,再由父加载器加载

在第②种,提到"不是全部",这里有个判断:

 protected final Matcher packageTriggersDeny = Pattern.compile(
            "^javax(\\.|/)el(\\.|/)|" +
            "^javax(\\.|/)servlet(\\.|/)|" +
            "^javax(\\.|/)websocket(\\.|/)|" +
            "^org(\\.|/)apache(\\.|/)(catalina|coyote|el|jasper|juli|naming|tomcat)(\\.|/)"
            ).matcher("");


    /**
     * Regular expression of package names which are allowed to be loaded from a
     * webapp class loader without delegating first and override any set by
     * {@link #packageTriggersDeny}.
     */
    protected final Matcher packageTriggersPermit =
            Pattern.compile("^javax(\\.|/)servlet(\\.|/)jsp(\\.|/)jstl(\\.|/)|" +
                    "^org(\\.|/)apache(\\.|/)tomcat(\\.|/)jdbc(\\.|/)").matcher("");
protected synchronized boolean filter(String name) {

        if (name == null)
            return false;

        // Looking up the package
        String packageName = null;
        int pos = name.lastIndexOf('.');
        if (pos != -1)
            // Package names in the filters include the last '.'
            packageName = name.substring(0, pos + 1);
        else
            return false;

        packageTriggersPermit.reset(packageName);
        if (packageTriggersPermit.lookingAt()) {
            return false;
        }

        packageTriggersDeny.reset(packageName);
        if (packageTriggersDeny.lookingAt()) {
            return true;
        }

        return false;
    }

 以上源码说明:javax.servlet.jsp.jstl包和org.apache.tomcat.jdbc包下的类由WebappClassLoader加载,而javax.el包,javax.servlet包,javax.websocket包,org.apache.(catalina|coyote|el|jasper|juli|naming|tomcat)——(这里包太多不在分开写,“|”表示或)包下的类由其父加载器加载。

 

关于tomcat类加载器的文章:

https://www.cnblogs.com/aspirant/p/8991830.html

https://mp.weixin.qq.com/s/U16h0njbAk6aMC27S_XDZA

 

 

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值