问题描述
程序执行时报错,异常信息为com.test.input cannot be cast to com.test.input。
问题排查
初看到这个报错信息是很困惑,明明同一个类,为什么会报类型不一致。仔细排查代码发现,这个类被加载了两次,两次分别使用了两个不同的类加载器。判断类型是否一致首先需要在同一个类加载器下,因此程序认为两个类类型不一致。java的双亲委派机制就是为了避免出现这个问题。
其他
最后记录一下类加载顺序,JVM的classloader加载继承关系分为BootstarpClassLoader --> ExtClassLoader --> SystemClassLoader,Tomcat应用的WebAppClassLoader继承自SystemClassLoader,在加载具体某个类时,一般会先委托给父类ClassLoader,当父类ClassLoader无法加载成功时,才会再由子类ClassLoader尝试加载。
如果出现同名类,类的优先级与加载优先级保持一致。如果加载优先级相同,使用先加载的类。
其次,Tomcat在jvm的ClassLoader机制上增加了几个继承层次。
SystemClassLoader --> CommonClassLoader -->(ServerClassLoader | SharedClassLoader --> WebAppClassLoader)。
CommonClassLoader用来加载${CATALINA_HOME}/conf/catalina.properties中common.loader配置目录下的类文件,一般是用来加载${CATALINA_HOME}/lib下的文件。该loader加载的类为tomcat服务器和tomcat下面的所有webApp所共享。
ServerClassLoader用来加载${CATALINA_HOME}/conf/catalina.properties中server.loader配置目录下的类文件,一般是用来加载${CATALINA_HOME}/server下的文件。该loader加载的类为tomcat服务器所独有核心类,tomcat下面的WebApp无法访问。
SharedClassLoader用来加载${CATALINA_HOME}/conf/catalina.properties中shared.loader配置目录下的类文件,一般是用来加载${CATALINA_HOME}/shared下的文件。该loader加载的类为tomcat下面的所有webApp所共享。
WebAppClassLoader用来加载${CATALINA_HOME}/webapps/目录下每个WebApp应用的/WEB-INF/class,/WEB-INF/lib的类文件,每个WebApp对应一个WebAppClassLoader,用来加载其所需要的类文件。
Tomcat配置文件context.xml中<Loader delegate="true" />作用
True,表示tomcat将遵循JVM的delegate机制,即一个WebAppClassLoader在加载类文件时,会先递交给SharedClassLoader加载,SharedClassLoader无法加载成功,会继续向自己的父类委托,一直到BootstarpClassLoader,如果都没有加载成功,则最后由WebAppClassLoader自己进行加载。
False,表示将不遵循这个delegate机制,即WebAppClassLoader在加载类文件时,会优先自己尝试加载,如果加载失败,才会沿着继承链,依次委托父类加载