Analyze the eclipse Class Loader

Source: Internet
Author: User
Tags finally block
-10-11 <> Analysis of eclipse class loaders

Keyword: classloaderEclipse provides a powerful development platform, and more applications are developed based on Eclipse. However, as Eclipse is a flexible platform, its class loader has some special characteristics. When developing Eclipse plug-ins, we often encounter issues that cannot be found by classes, especially when the applications we develop use third-party software packages. This article thoroughly analyzes the Class Loader mechanism of Java and the principles and models of the Class Loader of eclipse, and summarizes common issues related to the class loader in Eclipse plug-in application development, the corresponding solutions are provided.

Principles of Java class loaders

The class loader is a JVM class used to load classes. It is a very important concept for Java programming. Generally, programmers can ignore the existence of class loaders when writing programs. However, for programming on the server side or in some special cases, it is necessary to have a deep understanding of the Class Loader mechanism and its implementation under different circumstances.

First, when a JVM is started, Java starts to use three class loaders by default. They are:

Bootstrap class loader;
Extension class loader;
System class loader;

They implement the following functions:

The bootstrap loader is a Class Loader implemented using local code. It loads the Class Libraries under <java_runtime_home>/lib to the memory.
The extended class loader is implemented by Sun's extclassloader. It loads <java_runtime_home>/lib/EXT or the class library specified by the system variable java. Ext. dir to the memory.
The system class loader is also called the application class loader, which is implemented by Sun's appclassloader. It is responsible for loading the class library specified in the system classpath to the memory.

How does the Class Loader Work when an application needs to load a class into the memory? This design is an important aspect of the Class Loader: the proxy mechanism. In addition to the bootstrap loader, each class loader has a parent class loader. For the three default class loaders defined by the system, the bootstrap loader is the parent class loader of the extended class loaders, the extended class loader is the parent class loader of the system class loader. Of course, applications can also use their own class loaders to load classes using specific methods. Therefore, the class loaders in the entire system form a tree structure.

When a class loader is used to load a class, the Class Loader first uses its parent class loader to load the class. JVM assigns a unique ID to each loaded class. Therefore, different class loaders can load the same class to the JVM. For example, for the structure of classloadera and classloaderb:


Figure 1 Structure of the Class Loader

Assume that class C is in the class path specified by the system class loader, then both classloadera and classloaderb will get the same class C.

However, if Class C is in the class library specified by classloadera and classloaderb, the class C Instance obtained by using classloadera is different from the class C Instance obtained by classloaderb. Although the two class loaders are in the same JVM.

The upward proxy structure of the above class loader looks perfect, but it still seems useless when the system becomes complicated.

For example, after Java introduces JNDI, the core part of JNDI is loaded into JVM at JVM startup through the bootstrap loader. The core part of jdni is to load specific classes defined in the user's class path at runtime through configuration information to fulfill specific needs. This is not supported by the upward proxy mode of the Class Loader defined above.

To solve this problem, Java 2 introduces the thread context class loader. Each thread has a context class loader. The context class loader uses the thread method. setcontextclassloader () is set. If the current thread does not call this method after creation to set the context class loader, the current thread inherits the context Class Loader from its parent thread. If the context class loader is not set for the entire application, the system class loader is set as the context class loader for all threads.

For the above-mentioned JNDI situation, the JNDI core class loaded by the bootstrap loader will use the context class loader to load the required JNDI implementation class, instead of proxy the load task to its parent class loader. In this way, the above problem is solved. It can be considered that the context class loader opens a backdoor in the traditional Java upward proxy mechanism. The context class loader is widely used in J2EE, such as Java Naming Service (JNDI) and Java API for XML parsing (JAXP) (Note: in Java, JAXP is part of the Java core class, and it starts to use the context class loader to load different implementation classes.

In simple terms, the class loaders in Java are the above types. However, there are still many changes in actual use. We will explain some situations respectively.

Principle of eclipse Class Loader

In a typical Java application, when we want to load a class or resource, we can usually use three types of loaders:

The class loader of the current class;
The context loader of the current thread;
System class loader;

In actual application development, the first two class loaders are commonly used, the following describes the structure and Principles of the first two types of loaders In the Eclipse plug-in runtime environment and their differences with typical Java applications.

Class Loader of the current plug-in class

Is the architecture of the Class Loader of the current plug-in class when the Eclipse plug-in is running.


Figure 2 Structure of the Eclipse plug-in loader

The eclipseclassloader Class Loader implements the osgi specification bundleclassloader, which is used to load the osgi parentclassloader class loader in the bundle (that is, the plug-in) and is the parent class loader of the Eclipse plug-in class loader, you can set the system attribute osgi when starting eclipse. parentclassloader to change it. This change class will affect all Eclipse plug-ins. If the system attribute osgi. parentclassloader is not set at startup, eclipse uses a default empty class loader.

Bundleloader is the proxy of the eclipseclassloader Class Loader. It is used to load plug-in-related resources.

The process of loading classes or resources by the Eclipse plug-in loader is as follows:

First, we try to load the class from the parent loader. The process is to load the class from the osgi parentclassloader class loader, the osgi parentclassloader Class Loader uses the delegate mode of the traditional Java loader to load classes from the parent class loader in sequence.

If the class cannot be loaded from the osgi parentclassloader class loader, an attempt is made to load the class through the proxy bundleloader.

Bundleloader first tries to load the required class from the plug-in requirement dependency plug-in ("require" specified plug-in). If it cannot be found, you can use the eclipseclassloader class loader to locally load the required classes from the plug-in.

If you still cannot find the class to be loaded, an exception will be thrown.

Context loader of the current thread

The context class loader is not set in eclipse. By default, the context class loader of the current thread is the system class loader. Its architecture is shown in figure 3.


Figure 3 structure of the context class loader of the current Eclipse plug-in

In eclipse, each plug-in has its own class loader, and each thread has its own class loader. There is no uniform ing between plug-ins and threads, so the eclipse framework does not set the context class loader of the thread to a meaningful class loader.

Eclipse plug-in development common class Loading Problems and Solutions

Eclipse has been increasingly used as a platform, and there are more and more eclipse-based plug-in application development, especially the application that uses Eclipse plug-in as a rich client to access the server. There are two typical applications:

Call EJB in Eclipse plug-in
Call Web Services in Eclipse plug-ins

During the development of these typical Eclipse plug-ins, the following problems are usually encountered:

An exception occurred while querying the Naming Service in JNDI.
When you call a web service using https/SSL, the class cannot be found.

An exception occurred while querying the Naming Service in JNDI.

Problem

Use the "Hello, world" template in eclipse to develop a simple plug-in application. Then add the following method to the implementation of the action and call it in the run method.

Listing 1 how to find the JNDI Service

  1. Public object ejblookup (string ejbjndiname) throws namingexception {
  2. Properties props = new properties ();
  3. Props. Put (context. initial_context_factory,
  4. "Com. IBM. websphere. Naming. wsninitialcontextfactory ");
  5. Props. Put (context. provider_url, "IIOP: //" + was_host + ":" + was_iiop_port );
  6. System. Out. println ("*** creating initial context ...");
  7. Context CTX = new initialcontext (props );
  8. System. Out. println ("*** looking up EJB:" + ejbjndiname );
  9. Object OBJ = CTX. Lookup (ejbjndiname );
  10. System. Out. println ("*** got EJB object [" + obj. tostring () + "]");
  11. Return OBJ;
  12. }

The above method is used to search for the EJB object based on the input JNDI name in JNDI, and print the object after finding the EJB object.

Before running the preceding simple Eclipse plug-in application, make sure that all WebSphere library files required for calling EJB as independent Java applications are under the plug-in root directory, and modify the plug-in. XML adds these library files to the "run-time libraries" list.

At the same time, make sure that the queried EJB has been deployed on WebSphere and started.

Note: In this example, the author uses the EJB object in the WebSphere 6.0 built-in plants by WebSphere sample application. This example application can be installed using the following command:

  1. Was_install_root/samples/bin/install-samples plantsbywebsphere

Run the developed Eclipse plug-in application and click "Hello, eclipse world" to call the above method. The following exception information is displayed on the console:

Listing 2 shows the method running result of the JNDI object.

  1. * ** Creating initial context...
  2. Javax. Naming. noinitialcontextexception: cannot instantiate class:
  3. Com. IBM. websphere. Naming. wsninitialcontextfactory. Root exception is
  4. Java. Lang. classnotfoundexception:
  5. Com. IBM. websphere. Naming. wsninitialcontextfactory
  6. At java.net. urlclassloader. findclass (urlclassloader. Java: 374)
  7. At java. Lang. classloader. loadclass (classloader. Java (compiled code ))
  8. At sun. Misc. launcher $ appclassloader. loadclass (launcher. Java: 441)
  9. At java. Lang. classloader. loadclass (classloader. Java (compiled code ))
  10. At java. Lang. Class. forname0 (native method)
  11. At java. Lang. Class. forname (class. Java: 259)
  12. At com. Sun. Naming. Internal. versionhelper12.loadclass (versionhelper12.java: 59)
  13. At javax. Naming. SPI. namingmanager. getinitialcontext (namingmanager. Java: 661)
  14. At javax. Naming. initialcontext. getdefaultinitctx (initialcontext. Java: 256)
  15. At javax. Naming. initialcontext. INIT (initialcontext. Java: 232)
  16. At javax. Naming. initialcontext. <init> (initialcontext. Java: 208)
  17. At com. Test. Actions. invoker. ejblookup (invoker. Java: 73)

From the exception above, we can see that eclipse does not find the class COM. IBM. webSphere. naming. wsninitialcontextfactory, which is located in the WebSphere Library File naming. jar, in fact this library file has been added to the plug-in plguin as the Runtime Library. the runtime section of the XML file, but the Eclipse plug-in cannot find the class in the library file at runtime. The following describes the causes.

Cause

The above exception occurs when initializing the initial context (initial context) of JNDI. We know that Java class loading uses the delegate mechanism, and it always loads classes in the parent class loader first. The core JNDI class is loaded in the bootstrap class loader, and the specific JNDI class is in the library file provided by the vendor (here is the naming. jar file provided by IBM ). During JNDI initialization, the core JNDI class located in the bootstrap loader uses the context class loader of the current thread to load the specific JNDI implementation class, because the specific implementation classes of these JNDI are located in naming. the jar library file is located in the list of Runtime library files of the plug-in. Figure 3 shows the structure of the current thread context class loader of the Eclipse plug-in class, the tree structure of the Class Loader does not contain the class forwarder that loads the local library file of the Eclipse plug-in. Therefore, the Eclipse plug-in cannot find the Library File naming. jar.

Solution

We can solve the above problem by dynamically setting the context class loader of the thread in the plug-in program. Before calling the JNDI lookup method, we can set the context class loader of the current thread as the class loader of the current class, in this way, the system structure of the Class Loader of the current thread contains the class loader that loads the local library file of the Eclipse plug-in.

The code for modifying the call method ejblookup is as follows:

Listing 3 set the context class loader before calling ejblookup

  1. Classloader currentclassloader = This. getclass (). getclassloader ();
  2. Thread currthread = thread. currentthread ();
  3. Classloader originalcontextcl = currthread. getcontextclassloader ();
  4. Try {
  5. Currthread. setcontextclassloader (currentclassloader );
  6. Invoker. ejblookup ("plantsby/shoppingcarthome ");
  7. } Catch (exception e ){
  8. E. printstacktrace ();
  9. } Finally {
  10. Currthread. setcontextclassloader (originalcontextcl );
  11. }

First, save the context class loader of the current thread, set the context class loader of the current thread as the class loader of the Eclipse plug-in, and then call the ejblookup method, finally, make sure that the class loader of the current thread is restored to the original Class Loader. It is a good method to put the restored statement into the Finally block.

If you run the Eclipse plug-in application again, the exception does not occur and the EJB search is successful. The result is as follows:

Listing 4 The JNDI name is successfully run.

  1. * ** Creating initial context...
  2. * ** Looking up EJB: plantsby/shoppingcarthome
  3. * ** Got EJB object [IOR: 00bdbd00000055524d... 000407e]

Summary

When we call a third-party library file in the Eclipse plug-in, and the library file uses the context class loader of the thread to load the class, then, although we put these library files under the root directory of the plug-in, and in the plug-in. declare it as a Runtime Library file in XML, and the plug-in may still not find classes in these library files during runtime. This usually happens when the factory mechanism is used for library files.

In this case, we can solve this problem by manually setting the context loader of the current thread as the class loader of the Eclipse plug-in program.

It is worth mentioning that this problem is solved in the latest version 3.2 of Eclipse, in the eclipse 3.2 plug-in program, we do not need to manually set the context class loader of the current thread in the program.

When you call a web service using https/SSL, the class cannot be found.

Problem

Develop a plug-in eclipse as the Web service client. Eclipse plug-in works normally when we use HTTP to call Web Services, however, when the web service requires that the client must use the https-based transmission protocol (SSL) to call the web service, we usually encounter security-related class files that cannot be found.

First, we use HTTP to call Web Services.

1. The code for calling the Web service is as follows:

Listing 5 how to call a Web Service

  1. Public void callwebserivce (URL wsdlurl, string endpoint ){
  2. Try {
  3. Servicefactory factory = servicefactory. newinstance ();
  4. QNAME = new
  5. QNAME ("http://addr.webservices.samples.websphere.ibm.com ",
  6. "Addressbookservice ");
  7. Service = factory. createservice (wsdlurl, QNAME );
  8. Addressbook addrbook = (addressbook) service. getport (New
  9. QNAME ("http://addr.webservices.samples.websphere.ibm.com ",
  10. "Addressbook "),
  11. Addressbook. Class );
  12. (Javax. xml. rpc. stub)
  13. Addrbook). _ setproperty ("javax. xml. rpc. Service. endpoint. Address", endpoint );
  14. System. Out. println ("*** getting address from address book ...");
  15. Address ADDR = addrbook. getaddressfromname ("Purdue boilermaker ");
  16. System. Out. println ("*** city of the address is:" + ADDR. getcity ());
  17. } Catch (serviceexception e ){
  18. E. printstacktrace ();
  19. } Catch (RemoteException e ){
  20. E. printstacktrace ();
  21. }
  22. }

2. The code for calling the above method is as follows:

Listing 6 call the callwebserivce Method

  1. Classloader currentclassloader = This. getclass (). getclassloader ();
  2. Thread currthread = thread. currentthread ();
  3. Classloader originalcontextcl = currthread. getcontextclassloader ();
  4. Try {
  5. URL wsdlurl = new
  6. URL ("http: // localhost: 9080/addressbookw2je/services/addressbook? WSDL ");
  7. Invoker. callwebserivce (wsdlurl, "http: // localhost: 9080/addressbookw2je
  8. /Services/addressbook ");
  9. } Catch (exception e ){
  10. E. printstacktrace ();
  11. } Finally {
  12. Currthread. setcontextclassloader (originalcontextcl );
  13. }

Note: The code in this article uses the WebService sample application that comes with WebSphere 6.0.

You can run the following command to install the sample program:

  1. Install_root/samples/bin/install-samples webservicessamples

Note: when calling the callwebserivce method, you must set the context class loader of the current thread as the class loader of the Eclipse plug-in. Otherwise, the class cannot be found, the reason is the same as described above.

3. Run the Eclipse plug-in and trigger the call of the above method. If the call is normal, the following output will be obtained.

Listing 7 results of using HTTP to call Web Services

  1. * ** Getting address from address book...
  2. * ** City of the address is: West Lafayette

Next we modify the above program and use SSL to call the web service.

1. Modify the endpoint address of the web service in the code of callwebserivce.

Listing 8 modifying the endpoint address of a Web Service

  1. ...
  2. Invoker. callwebserivce (wsdlurl,
  3. "Https: // localhost: 9443/addressbookw2je/services/addressbook ");

2. Then run the Eclipse plug-in application again. Before running, make sure to add the following security-related Java Virtual Machine Parameters in the run-time workbench STARTUP configuration.

Listing 9 Java Virtual Machine Parameters for calling Web Services

  1. -Djavax.net. SSL. truststore = <was_home>/profiles/default/etc/dummyclienttrustfile. jks
  2. -Djavax.net. SSL. truststorepassword = webas
  3. -Djavax.net. SSL. keystore = <was_home>/profiles/default/etc/dummyclientkeyfile. jks
  4. -Djavax.net. SSL. keystorepassword = webas

3. The running result is as follows.

Listing 10 results of using HTTPS to call Web Services

  1. * ** Getting address from address book...
  2. 2006-12-29 16:15:50
  3. Com. IBM. ws. WebServices. Engine. descrithandlerwrapper bindexceptiontoresponse
  4. Severe: wsws3400i: Information: Unexpected exception.
  5. Java. Lang. noclassdeffounderror: COM/IBM/crypto/FIPS/provider/ibmjcefips
  6. At com. IBM. ws. SSL. sslconfig. <init> (sslconfig. Java: 279)
  7. At com. IBM. ws. SSL. sslconfig. <clinit> (sslconfig. Java: 206)
  8. At com.ibm.ws.webservices.engine.components.net.
  9. Sslconfiguration. <init> (sslconfiguration. Java: 87)
  10. At com. IBM. ws. WebServices. Engine. Transport. HTTP.
  11. Httpchanneladdress. keyvalueforpool (httpchanneladdress. Java: 325)
  12. At com. IBM. ws. WebServices. Engine. Transport. Channel. outboundconnectioncache.
  13. Findgroupandgetconnection (outboundconnectioncache. Java: 224)
  14. At com. IBM. ws. WebServices. Engine. Transport. http. httpsender. Invoke (httpsender. Java: 391)
  15. At com. IBM. ws. WebServices. Engine. Fig. Invoke (fig. Java: 226)
  16. At com. IBM. ws. WebServices. Engine. Fig. Invoke (fig. Java: 226)
  17. At com. IBM. ws. WebServices. Engine. Fig. Invoke (fig. Java: 226)
  18. At com. IBM. ws. WebServices. Engine. webservicesengine. Invoke (webservicesengine. Java: 279)
  19. At com. IBM. ws. WebServices. Engine. Client. Connection. invokeengine (connection. Java: 798)
  20. At com. IBM. ws. WebServices. Engine. Client. Connection. Invoke (connection. Java: 693)
  21. At com. IBM. ws. WebServices. Engine. Client. Connection. Invoke (connection. Java: 644)
  22. At com. IBM. ws. WebServices. Engine. Client. Connection. Invoke (connection. Java: 472)
  23. At com. IBM. ws. WebServices. Engine. Client. Stub $ invoke. Invoke (stub. Java: 818)
  24. ......

The application cannot find the class COM. IBM. crypto. FIPS. provider. ibmjcefips. This class is located in the library file ibmjcefips under the extension directory (JRE/lib/EXT. jar, this library file is used to provide Java encryption extensions, and belongs to the class provided by Java Virtual Machine implementation.

Cause

Figure 2 the architecture of the Eclipse plug-in Class Loader shows that the Eclipse plug-in cannot find classes from the default extension (library files in the JRE/lib/EXT directory) when loading classes, by default, the Eclipse plug-in searches for classes in the following sequence:

Java kernel boot library file (RT. Jar)
Demand dependency plug-in
Classes in the current plug-in
Runtime files located in the current agent runtime

Java's default extension directory (usually in the JRE/lib/EXT directory) usually stores some java common extensions, such as Java Cryptography extensions (JCE ). Different security extensions are usually placed under the extension directory, so that the application does not need to modify the user's class path to implement the security Extension function.

However, sometimes our plug-in applications use library files under the default extension directory. For example, when we use the SSL transfer protocol to call Web Services in the Eclipse plug-in, you need to use security extension-related library files. Different vendors implement different methods. For example, the ibmjce provider library file in the extended directory is used in the ibm jdk runtime environment, the above problem is caused by the JCE implementation class provided by IBM when we use SSL transmission protocol to call Web Services.

Solution

There are two ways to solve this problem:

1. Set the Java Virtual Machine parameter osgi. parentclassloader to "Ext" when starting eclipse, as shown in figure 4.


Figure 4 Java virtual machine parameter settings during Eclipse plug-in running

Eclipse supports setting the system parameter osgi. parentclassloader as the following class loader at startup:

Boot: Set it to the bootstrap class loader of Java;
APP: Set it to a java system class loader;
Ext: extension class loader set to Java;
Fwk: Set it to the class loader of the osgi framework;

When we set the value to ext, the order in which the Eclipse plug-in looks for classes is changed:

Java kernel boot library file (RT. Jar );
By default, JRE extends the library files in the directory;
Requirement dependency plug-ins;
Class in the current plug-in;
Library files located at the runtime of the current plug-in;

In this way, when we run the above program, the Eclipse plug-in will find the class from the library file of the default extended directory, thus successfully calling the web service.

However, the following problem occurs: Changes to the class loading sequence will affect all plug-ins, and because the Java extension mechanism will load all library files located in the extension directory, this may cause potential Library File conflicts, because the extension directory is preferentially loaded. If an Eclipse plug-in Runtime Library file list contains the same library file in the extension directory, eclipse will use the library files under the extension Directory, which is why eclipse does not put the extension directory in the class loading path by default, eclipse encourages each plug-in to use its own class path to load classes and avoid conflicts between library files.

2. Copy the ibmjce provider library file to the Eclipse plug-in directory and add them to the Runtime Library file list. This method regards these JVM library files as third-party library files, so that other Eclipse plug-ins are not affected during runtime.

Summary

When the classes used in the plug-in exist in the Java extension directory (JRE/lib/EXT directory), these classes are not in the class loading path of the plug-in by default, A common situation is that when you call Web Services Based on the SSL transmission protocol, some of the required security encryption extension library files are located in the Java extension directory.

In this case, we can solve this problem by setting the system parameter osgi. parentclassloader or copying the required library file to the Eclipse plug-in directory and adding it to the Runtime Library file list.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.