IBM websphere经验
1.包的路径
/opt/IBM/WebSphere85/AppServer/profiles/appprofile/installedApps/wascell
2.项目有web service需要的选项
https://blog.csdn.net/keyboardsun/article/details/4359338

然后在点进去application里面会看到webservice有很多的选项。
3.类加载的顺序会导致noclassdefounderror
背景:
发现有些包javax…qname报noclassdefounderror。但是打包的时候是正常的啊,另外这个包是J2ee.jar,应该是自带的。
解决:
首先发现classnotfoundexception和noclassdefounderror是两回事。
前者exception可以try catch的,可以让程序继续执行。类加载器去加载时,在classpath没找到,就会出这个异常。通常就是jar包缺失。
后者则是编译时存在,运行时不存在。errpr发生就退出程序的了。
发现报Noclassdefounderror, javax…qname
然后发现Log的上面还出现了java.lang.linkagerror: loading constraint violation: loader”com/ibm/ws…CompoundClassloader…” previously initiated loading for a different type with name “java…qname” defined by loader “com/ibm/oti/…bootstrapclassloader”
看起来像bootstrap加载器先加载了,后面就不让再加载了。然后就报noclassdefound。那可能是加载出来的类不适用。
最后发现不同的类加载顺序会导致这个问题。我们的推论是同样的class文件如果去到的最后父加载器不同,那最后生成出来的类就是不一样的。
再搜了一下,双亲委派,如果Bootstrap Class Loader也没有加载该类,将尝试进行加载,加载成功则返回;如果失败,抛出ClassNotFoundException,则由子加载器进行加载;
子类加载器捕捉异常后尝试加载,如果成功则返回,如果失败则抛出ClassNotFoundException,直到发起加载的子类加载器。
这种理解对Bootstrap Class Loader,Extention Class Loader,System Class Loader这些加载器是正确的。但一些个性化的加载器则不然,比如,IBM Web Sphere Portal Server实现的一些类加载器就是Parent Last的,是子加载器首先尝试加载,如果加载失败才会请父加载器,这样做的原因是:假如你期望某个版本log4j被所有应用使用,就把它放在WAS_HOME的库里,WAS启动时会加载它。如果某个应用想使用另外一个版本的log4j,如果使用Parent First,这是无法实现的,因为父加载器里已经加载了log4j内的类。但如果使用Parent Last,负责加载应用的类加载器会优先加载另外一个版本的log4j。所以因为我们选了web service选项,所以需要使用websphere版本的qname类,不能用项目的那个,所以选择parent first。唯一性原因,谁的加载器先就用谁的。
Parent_First :在加载类的时候,在从类加载器自身的类路径上查找加载类之前,首先尝试在父类加载器的类路径上查找和加载类。
Parent_Last :在加载类的时候,首先尝试从自己的类路径上查找加载类,在找不到的情况下,再尝试父类加载器类路径。
改的地方:application->manager modules->….war->class loader order
本来默认是:classes loaded with local class loader first(parent last)[优先加载项目中的类](所以websphere默认是打破双亲委派的)
现在改后是:classes loaded with parent class loader first
If you are only deploying the WAR file itself you can’t control this, but if you have your WAR file in an EAR file you can use the deployment.xml solution.
扩展:tomcat不遵守双亲委派
既然 Tomcat 不遵循双亲委派机制,那么如果我自己定义一个恶意的HashMap,会不会有风险呢?(阿里的面试官问)
答: 显然不会有风险,如果有,Tomcat都运行这么多年了,那群Tomcat大神能不改进吗? tomcat不遵循双亲委派机制,只是自定义的classLoader顺序不同,但顶层还是相同的,还是要去顶层请求classloader.
tomcat要解决的问题
要解决什么问题:
- 一个web容器可能需要部署两个应用程序,不同的应用程序可能会依赖同一个第三方类库的不同版本,不能要求同一个类库在同一个服务器只有一份,因此要保证每个应用程序的类库都是独立的,保证相互隔离。
- 部署在同一个web容器中相同的类库相同的版本可以共享。否则,如果服务器有10个应用程序,那么要有10份相同的类库加载进虚拟机,这是扯淡的。
- web容器也有自己依赖的类库,不能于应用程序的类库混淆。基于安全考虑,应该让容器的类库和程序的类库隔离开来。
- web容器要支持jsp的修改,我们知道,jsp 文件最终也是要编译成class文件才能在虚拟机中运行,但程序运行后修改jsp已经是司空见惯的事情,否则要你何用? 所以,web容器需要支持 jsp 修改后不用重启。
tomcat如何设计自己独特的类加载机制
- commonLoader:Tomcat最基本的类加载器,加载路径中的class可以被Tomcat容器本身以及各个Webapp访问;
- catalinaLoader:Tomcat容器私有的类加载器,加载路径中的class对于Webapp不可见;
- sharedLoader:各个Webapp共享的类加载器,加载路径中的class对于所有Webapp可见,但是对于Tomcat容器不可见;
- WebappClassLoader:各个Webapp私有的类加载器,加载路径中的class只对当前Webapp可见;
为了实现隔离性
tomcat 违背了java 推荐的双亲委派模型了吗?答案是:违背了。 我们前面说过:
双亲委派模型要求除了顶层的启动类加载器之外,其余的类加载器都应当由自己的父类加载器加载。
很显然,tomcat 不是这样实现,tomcat 为了实现隔离性,没有遵守这个约定,每个webappClassLoader加载自己的目录下的class文件,不会传递给父类加载器。
我们扩展出一个问题:如果tomcat 的 Common ClassLoader 想加载 WebApp ClassLoader 中的类,该怎么办?
看了前面的关于破坏双亲委派模型的内容,我们心里有数了,我们可以使用线程上下文类加载器实现,使用线程上下文加载器,可以让父类加载器请求
子类加载器去完成类加载的动作。就是虽然用了父,但实际还是用子类加载器完成。