在Tomcat部署的应用中,我们一般指的是普通应用。每个人能做的操作都是一样的,在同一起跑线上没有区别。但是,对于一些特殊的应用,需要进行一些特殊的操作。例如,官方默认提供的manager应用可以进行应用的启动、停止、部署等一系列操作。这些操作的背后是Tomcat默认包含的ManagerServlet的实现,而manager应用的实现就是对Servlet的调用。那我们是不是可以写一个应用程序来调用这个ManagerServlet呢?答案是否定的,至少不能直接运行,需要配置。这里就是我们今天提到的Tomcat中的特权应用程序(privilegedapp)。manager应用是自带的特权应用,所以可以直接调用ManagerServlet进行容器内部的一些操作。我们单独部署的其他应用会被限制调用这些容器提供的内部组件,比如一些Servlets、Filters、Listeners。检查这些限制资源时,它们有两种类型。1、一种是按类型判断的。例如在Servlet中,ManagerServlet和HTMLManagerServlet被称为ContainerServlet。实现相同的接口。2.另一个类在配置文件中指定,一共有三个文件:RestrictedFilters.propertiesRestrictedListeners.propertiesRestrictedServlets.properties位于org.apache.catalina.core包中。这些内部结构在DefaultInstanceManager初始化时被解析。比如解析servlet的内容后,就是这些:这些内容也是容器提供的一些功能的实现,比如GCI请求处理,JMXProxyServlet会转储JMX属性等等。特权应用的配置那么如何让单独开发的应用成为可以调用这些容器功能的特权应用呢?上一篇介绍了应用的部署描述文件context.xml(Tomcat目录部署和Context描述文件context.xml),这次我们的升级权限操作也需要在这里进行。具体来说,当部署应用程序时,应用程序的Context对象中的特权属性设置为true。例如manager应用的配置如下。该文件位于管理器的META-INF目录中。独立开发时,可以参考:这样配置后,代表应用的StandardContext对象中的privileged属性设置为true,后面会读取使用。特权应用程序如何工作应用程序以DefaultInstanceManager作为它们的instanceManager。该属性在后面加载Servlet、Filter、Listener组件时使用,作为实例管理器来管理newInstance。以Servlet为例,有些loadOnStartupServlet会在应用部署启动时直接生成实例。在loadServlet阶段,会先通过Wrapper获取父容器Context的instanceManager,然后通过instanceManager加载具体的Servlet类。下面是instanceManager执行newInstace时的逻辑publicObjectnewInstance(StringclassName){Class>clazz=loadClassMaybePrivileged(className,classLoader);returnnewInstance(clazz.newInstance(),clazz);}在loadClassMaybePrivileged中,对于catalina包中的类,它会使用ServerClassLoader加载,除了通过不同的classLoader加载外,还会进行上面提到的权限检查。privatevoidcheckAccess(Class>clazz){if(privileged){return;}if(Filter.class.isAssignableFrom(clazz)){checkAccess(clazz,restrictedFilters);}elseif(Servlet.class.isAssignableFrom(clazz)){if(ContainerServlet.class.isAssignableFrom(clazz)){thrownewSecurityException("Restricted(ContainerServlet)"+clazz);}checkAccess(clazz,restrictedServlets);}else{checkAccess(clazz,restrictedListeners);}}//检查配置文件在这里privatevoidcheckAccess(Class>clazz,Propertiesrestricted){while(clazz!=null){if("restricted".equals(restricted.getProperty(clazz.getName()))){thrownewSecurityException("Restricted"+clazz);}clazzclazz=clazz.getSuperclass();}}对于特权应用,后面的checkAccess会直接跳过,否则会判断是否是ContainerServlet,是否在配置文件中限制等,并且只有在所有检查都通过后才能使用。比如一个普通的应用使用HTMLManagerServlet,由于限制检查,会提示500。因此,当后面需要使用容器提供的功能时,可以将应用升级为特权应用,再调用容器提供的高级功能。【本文为专栏作家“侯书城”原创稿件,转载请通过作者微信公众号“Tomcat物语”获得授权】点此查看本作者更多好文