实例
接下来,我们用一个实例来说明针对特定的模块依赖关系应当如何设置WebSphere Classloader的装载策略(policy)以及如何将各个模块部署到合适的位置。
有一个应用程序里有三个互相依赖的模块,其调用关系如下:
图二、模块关系图
其中,WAR模块中的SampleServlet类调用了UTILITY模块中SampleUtility类,如代码一所示:
代码一、SampleServlet.java
2
3 public void doGet(HttpServletRequest req, HttpServletResponse resp)
4
5 throws ServletException, IOException {
6
7 System.out.println("SampleServlet invokes SampleUtility");
8
9 new SampleUtility().callSampleSessionBean();
10
11 }
12
13 public void doPost(HttpServletRequest req, HttpServletResponse resp)
14
15 throws ServletException, IOException {
16
17 }
18
19 }
20
21
UTILITY模块中SampleUtility类调用了EJB模块中的SampleSessionBean类(通过callSampleSessionBean方法),如代码二所示:
代码二、SampleUtility.java
2
3 public void callSampleSessionBean() {
4
5 try{
6
7 Context initCtx = new InitialContext();
8
9 Object result = initCtx.lookup("ejb/sample/SampleSessionHome");
10
11 SampleSessionHome ssh = (SampleSessionHome)
12
13 PortableRemoteObject.narrow(
14
15 result, SampleSessionHome.class);
16
17 SampleSession ss = ssh.create();
18
19 System.out.println("SampleUtility invokes SampleSessionBean");
20
21 ss.callSampleUtility();
22
23 }catch(Exception e){
24
25 e.printStackTrace();
26
27 }
28
29 }
30
31 public void finish() {
32
33 System.out.println("The process has been finished");
34
35 }
36
37 }
38
39
SampleSessionBean类又调用了UTILITY模块中的SampleUtility类,如代码三所示:
代码三、SampleSessionBean.java
2
3 private javax.ejb.SessionContext mySessionCtx;
4
5 public javax.ejb.SessionContext getSessionContext() {
6
7 return mySessionCtx;
8
9 }
10
11 public void setSessionContext(javax.ejb.SessionContext ctx) {
12
13 mySessionCtx = ctx;
14
15 }
16
17 public void ejbCreate() throws javax.ejb.CreateException {
18
19 }
20
21 public void ejbActivate() {
22
23 }
24
25 public void ejbPassivate() {
26
27 }
28
29 public void ejbRemove() {
30
31 }
32
33 public void callSampleUtility() {
34
35 System.out.println("SampleSessionBean invokes SampleUtility");
36
37 new SampleUtility().finish();
38
39 }
40
41 }
42
43
这三个类之间的调用关系如下图所示:
图三、顺序图
下面我们通过不同的部署策略来深入探讨WebSphere Classloader是如何影响应用程序运行的。1、如果将Utility模块(JAR文件)拷贝到Web 模块的 WEB-INF/lib 文件夹中,那么,Utility模块将会被视为War模块的一部分,如图所示:
图四、Utility模块(JAR文件)在Web 模块中
如果我们将WAR Classloader Policy设置为MODULE(默认设置),如图五所示:
图五、WAR Classloader Policy设置
那么WebSphere应用服务器会使用WAR Classloader来装载WAR模块的类文件。而EJB模块始终是通过Application Classloader进行装载,由于Application Classloader处于WAR classloader的上层,EJB模块无法引用War模块的类文件。这样,当SampleSessionBean调用SampleUtility时,会抛出异常:
SystemOut O SampleServlet invokes SampleUtility
SystemOut O SampleUtility invokes SampleSessionBean
SystemOut O SampleSessionBean invokes SampleUtility
ExceptionUtil E CNTR0020E: 在 bean"BeanId(Sample#SampleEJB.jar#SampleSession, null)"上处理方法"callSampleUtility"时发生非应用程序异常。异常数据:
java.lang.NoClassDefFoundError: sample/SampleUtility
at sample.SampleSessionBean.callSampleUtility(SampleSessionBean.java:41)
如果我们将WAR Classloader Policy设置为APPLICATION,那么WebSphere应用服务器会使用Application Classloader来装载WAR模块和EJB模块的类文件。由于两个模块使用了相同的Classloader进行装载,所以两个模块间的类可以相互引用应用服务器输出的结果如下:
SystemOut O SampleServlet invokes SampleUtility
SystemOut O SampleUtility invokes SampleSessionBean
SystemOut O SampleSessionBean invokes SampleUtility
SystemOut O The process has been finished
2、如果将Utility模块拷贝到%was_root%\lib\ext , Websphere应用服务器会使用WebSphere Extensions Classloader加载Utility模块中的类文件,由于WebSphere Extensions Classloader处于Application classloader和WAR classloader的上层,所以SampleServlet和SampleSessionBean可以引用到SampleUtility,但是SampleUtility引用不到SampleSessionBean,因此,当SampleUtility调用SampleSessionBean时会抛出异常。