5. 注解、反射、字节码、类加载机制课堂笔记

一. 反射:Reflection

 把 java 类中的 各种结构( ( 方法、属性、构造器、类名) ) 映射 成一个个的 Java 对象。利用反射技术可以对一个类进行解剖 , 反射是框架设计的灵魂。

1、获取Class对象
      三种方式:

          (1)对象.getClass()

          (2)类.class()

          (3)Class.forName("包名.类名")

               Class clz = Class.forName("包名.类名");
 2、可以动态创建对象
               Iphone iphone2 = (Iphone)clz.getConstructor().newInstance();

二.XML解析

1. XML : Extensible Markup Language ,可扩展标记语言,作为数据的一种存储格式或用于
存储软件的参数,程序解析此配置文件,就可以到达不修改代码就能更改程序的目的。

2. //SAX解析

//1、获取解析工厂
SAXParserFactory factory=SAXParserFactory.newInstance();
//2、从解析工厂获取解析器
SAXParser parse =factory.newSAXParser();
//3、编写处理器
//4、加载文档 Document 注册处理器
PersonHandler handler=new PersonHandler();
//5、解析
parse.parse(Thread.currentThread().getContextClassLoader()
.getResourceAsStream("com/sxt/server/basic/p.xml")
,handler);

三.HTTP协议
超文本传输协议( HTTP ,t HyperText Transfer Protocol) 是互联网上应
用最为广泛的一种 网络协议,所有 的 WWW 文件都必须遵守这个标准。

1. 请求协议

(1)GET 的请求协议

           请求行:     方法(GET)、 URI 、协议 / 版本

                              GET /index.html? name=test&pwd=123456 HTTP/1.1
           请求体:     get和post相同

                             Accept: text/html, application/xhtml+xml, 
                            Accept-Language: zh-CN
                            User-
                            Agent: Mozilla/5.0 (compatible; MSIE 9.0; W
                            indows NT 6.1; Trident/5.0)
                            Accept-Encoding: gzip, deflate
                            Host: localhost
                            Connection: Keep-Alive 

             请求正文:

(2)POST 的请求协议

          请求行:     方法(POST)、 URI 、协议 / 版本

                               POST /index.html HTTP/1.1
           请求头:     get和post相同

                              Accept: text/html, application/xhtml+xml, 

                             Accept-Language: zh-CN
                             User-
                             Agent: Mozilla/5.0 (compatible; MSIE 9.0; W
                             indows NT 6.1; Trident/5.0)
                             Accept-Encoding: gzip, deflate
                             Host: localhost
                             Connection: Keep-Alive 

             请求正文:

              //注意这里有一个空行,同时也要注意空格

             name=test&pwd=123456

2. 响应协议

     状态行:       HTTP/1.0 200 OK
     请求头:
                       Date:Mon,31Dec209904:25:57GMT
                       Server:shsxtServer/0.0.1;charset=GBK
                       Content-type:text/html
                       Content-length:39725426
      请求正文 (注意与请求头之间有个空行):
                       xxxxxx

四.状态码

     

五. 注解Annotation

1.  Annotation的作用:

* 不是程序本身,可以对程序作出解释。(这一点,跟注释没什么区别)
* 可以被其他程序(比如:编译器等)读取。(注解信息处理流程,是注解和注释的重大区别。如果没有注解信息处理流程,则注解毫无意义)

2. 内置注解

(1)@Override:表示一个方法声明打算重写超类中的另一个方法声明

(2)@Deprecated 此注释可用于修辞方法、属性、类,表示不鼓励程序员使用这样的元素,通常是因为它很危险或存在更好的选择

(3)@SuppressWarnings用来抑制编译时的警告信息。

   @SuppressWarnings("unchecked")
   @SuppressWarnings(value={"unchecked", "deprecation"})

3. 自定义注解:

(1)使用@interface自定义注解,自动继承了java.lang.annotation.Annotation接口

(2)public @interface 注解名 {定义体}

         可以通过default来声明参数的默认值。如果只有一个参数成员,一般参数名为value

(3)注解元素必须要有值。我们定义注解元素时,经常使用空字符串、0作为默认值。也经常使用负数(比如:-1)表示不存在的含义。

4. 元注解

(1)元注解的作用就是负责注解其他注解。 Java定义了4个标准的meta-annotation类型,它们被用来提供对其它 annotation类型作说明

– @Target   用于描述注解的使用范围(即:被描述的注解可以用在什么地方)

@Target(value = {ElementType.METHOD, ElementType.TYPE})


– @Retention    表示需要在什么级别保存该注释信息,用于描述注解的生命周期

@Retention(RetentionPolicy.RUNTIME)


– @Documented
– @Inherited

5. 反射机制

(1)指的是可以于运行时加载、探知、使用编译期间完全未知的类。
(2)程序在运行状态中,可以动态加载一个只有名称的类,对于任意一个已加载的类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;

          获取Class类的对象:
          Class c = Class. forName ("com.bjsxt.test.User");
(3) 加载完类之后,在堆内存中,就产生了一个 Class 类型的对象(一个类只有一个 Class 对象),这个对象就包含了完整的类的结构信息。我们可以通过这个对象看到类的结构。这个对象就像一面镜子,透过这个镜子看到类的结构,所以,我们形象的称之为:反射

(4)动态加载类、动态获取类的信息(属性、方法、构造器)

            //获取类的名字
			System.out.println(clazz.getName());//获得包名+类名:com.bjsxt.test.bean.User
			System.out.println(clazz.getSimpleName());	//获的类名:User
			
			//获取属性信息
            //Field[] fields = clazz.getFields(); //只能获得public的field
			Field[] fields = clazz.getDeclaredFields();//获得所有的field
			Field f = clazz.getDeclaredField("uname");
			System.out.println(fields.length);
			for(Field temp:fields){
				System.out.println("属性:"+temp);
			}
			//获取方法信息
			Method[] methods = clazz.getDeclaredMethods();
			Method m01 = clazz.getDeclaredMethod("getUname", null);
			//如果方法有参,则必须传递参数类型对应的class对象
			Method m02 = clazz.getDeclaredMethod("setUname", String.class); 
			for(Method m:methods){
				System.out.println("方法:"+m);
			}
			
			//获得构造器信息
			Constructor[] constructors = clazz.getDeclaredConstructors();
			Constructor c =clazz.getDeclaredConstructor(int.class,int.class,String.class);
			System.out.println("获得构造器:"+c);
			for(Constructor temp:constructors){
				System.out.println("构造器:"+temp);
			}
			

(5)反射操作泛型:

• ParameterizedType: 表示一种参数化的类型,比如Collection<String>
• GenericArrayType: 表示一种元素类型是参数化类型或者类型变量的数组类型
• TypeVariable: 是各种类型变量的公共父接口
• WildcardType: 代表一种通配符类型表达式,比如?, ? extends Number, ? super Integer【wildcard是一个单词:就是“通配符”】


//获得指定方法参数泛型信息
Method m = Demo04.class.getMethod("test01", Map.class,List.class);
Type[] t = m.getGenericParameterTypes();
for (Type paramType : t) {
		System.out.println("#"+paramType);
		if(paramType instanceof ParameterizedType){
			Type[] genericTypes = ((ParameterizedType) paramType).getActualTypeArguments();
			for (Type genericType : genericTypes) {
				System.out.println("泛型类型:"+genericType);
				}
			}
		}
			
//获得指定方法返回值泛型信息
	Method m2 = Demo04.class.getMethod("test02", null);
	Type returnType = m2.getGenericReturnType();
	if(returnType instanceof ParameterizedType){
			Type[] genericTypes = ((ParameterizedType) returnType).getActualTypeArguments();

	for (Type genericType : genericTypes) {
		System.out.println("返回值,泛型类型:"+genericType);
		}
					
	}
			
			

(6)反射操作注解:


	Class clazz = Class.forName("com.classloading.testReflection.annotation.testStudent");
			
    //获得类的所有有效注解
    Annotation[] annotations=clazz.getAnnotations();
	for (Annotation a : annotations) {
		System.out.println(a);
	}
	//获得类的指定的注解
	testTable st = (testTable) clazz.getAnnotation(testTable.class);
	System.out.println(st.value());
	
	//获得类的属性的注解
	Field f = clazz.getDeclaredField("studentName");
	testField sxtField = f.getAnnotation(testField.class);
	System.out.println(sxtField.columnName()+"--"+sxtField.type()+"--"+sxtField.length());

(7)启用和禁用访问安全检查的开关,禁止安全检查,可以提高反射的运行速度。

    m.setAccessible(true);  //不需要执行访问安全检查

6. 动态编译

 (1)动态编译的应用场景:
        – 可以做一个浏览器端编写java代码,上传服务器编译和运行的在线评测系统。
        – 服务器动态加载某些类文件进行编译

(2)动态编译的两种做法:
        – 通过Runtime调用javac,启动新的进程去操作

//通过Runtime调用执行类
//    Runtime run = Runtime.getRuntime();  
//        Process process = run.exec("java -cp  c:/myjava    HelloWorld"); 

       – 通过JavaCompiler动态编译

//通过IO流操作,将字符串存储成一个临时文件(Hi.java),然后调用动态编译方法!
String str = "public class Hi {public static void main(String[] args){System.out.println(\"HaHa,ddd!\");}}";

JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
int result = compiler.run(null, null, null, "c:/myjava/HelloWorld.java");
  /*第一个参数: 为java编译器提供参数
• 第二个参数: 得到 Java 编译器的输出信息
• 第三个参数: 接收编译器的 错误信息
• 第四个参数: 可变参数(是一个String数组)能传入一个或多个 Java 源文件
• 返回值: 0表示编译成功,非0表示编译失败
*/
System.out.println(result==0?"编译成功":"编译失败");

7. 脚本引擎执行Javascript代码

//获得脚本引擎对象
ScriptEngineManager sem = new ScriptEngineManager();
ScriptEngine engine = sem.getEngineByName("javascript");

//定义变量,存储到引擎上下文中
engine.put("msg", "dd is a good man!");
String str = "var user = {name:'dd',age:18,schools:['清华大学','北京dd']};";
str += "println(user.name);";

//执行脚本
engine.eval(str);
engine.eval("msg = 'ddd is a good school';");
System.out.println(engine.get("msg"));
System.out.println("###########################");

//定义函数
engine.eval("function add(a,b){var sum = a + b; return sum;}");
//取得调用接口
Invocable jsInvoke = (Invocable) engine;
//执行脚本中定义的方法
Object result1 = jsInvoke.invokeFunction("add", new Object[]{13,20});
System.out.println(result1);

//导入其他java包,使用其他包中的java类.若需要深入了解细节,可以详细学习Rhino的语法
String jsCode = "importPackage(java.util); var list=Arrays.asList([\"北京ddd\",\"清华大学\",\"北京大学\"]);";
engine.eval(jsCode);

List<String> list2 = (List<String>)engine.get("list");
for (String temp : list2) {
   System.out.println(temp);
}

//执行一个js文件(我们将a.js至于项目的src下即可)
URL url = Demo01.class.getClassLoader().getResource("a.js");
FileReader fr = new FileReader(url.getPath());
engine.eval(fr);
fr.close(); 

8. Java字节码操作

(1)Java动态性的两种实现方式:

         a. 字节码操作

         b. 反射

(2)常见的字节码操作类库

        BCEL(Byte Code Engineering Library):基于JVM汇编语言

        ASM:基于JVM汇编语言

        CGLIB(Code Generation Library):Code生成类库

        Javassist: 分析, 编辑和创建Java字节码类库,

                         主要由CtClass(compile TIme Class),CtMethod,CtField组成

                         对应JDK反射中:Class ,Method, Field

(3)Javassist:

在 Javassist 中,类 Javaassit.CtClass 表示 class 文件。一个 GtClass (编译时类)对象可以处理一个 class 文件,ClassPool是 CtClass 对象的容器。它按需读取类文件来构造 CtClass 对象,并且保存 CtClass 对象以便以后使用。

需要注意的是 ClassPool 会在内存中维护所有被它创建过的 CtClass,当 CtClass 数量过多时,会占用大量的内存,API中给出的解决方案是 有意识的调用CtClassdetach()方法以释放内存

ClassPool需要关注的方法:

1. getDefault : 返回默认的ClassPool 是单例模式的,一般通过该方法创建我们的ClassPool;
2.appendClassPath, insertClassPath : 将一个ClassPath加到类搜索路径的末尾位置 或 插入到起  始位置。通常通过该方法写入额外的类搜索路径,以解决多个类加载器环境中找不到类的尴尬;
3.toClass : 将修改后的CtClass加载至当前线程的上下文类加载器中,CtClass的toClass方法是通过调用本方法实现。需要注意的是一旦调用该方法,则无法继续修改已经被加载的class;
4.get , getCtClass : 根据类路径名获取该类的CtClass对象,用于后续的编辑。

CtClass需要关注的方法:

1. freeze : 冻结一个类,使其不可修改;
2. isFrozen : 判断一个类是否已被冻结;
3. prune : 删除类不必要的属性,以减少内存占用。调用该方法后,许多方法无法将无法正常使用,慎用;
4. defrost : 解冻一个类,使其可以被修改。如果事先知道一个类会被defrost, 则禁止调用 prune 方法;
5. detach : 将该class从ClassPool中删除;
6. writeFile : 根据CtClass生成 .class 文件;
7. toClass : 通过类加载器加载该CtClass。

CtMethod中的一些重要方法:

1. insertBefore : 在方法的起始位置插入代码;
2. insterAfter : 在方法的所有 return 语句前插入代码以确保语句能够被执行,除非遇到exception;
3. insertAt : 在指定的位置插入代码;
4. setBody : 将方法的内容设置为要写入的代码,当方法被 abstract修饰时,该修饰符被移除;
5. make : 创建一个新的方法。


/**
 * 测试使用javassist生成一个新的类
 */
public class Demo01 {
	public static void main(String[] args) throws Exception {
		ClassPool pool = ClassPool.getDefault();
		CtClass cc = pool.makeClass("com.classloading.testJavassist.Emp");
		
		//创建属性
		CtField f1 = CtField.make("private int empno;", cc);
		CtField f2 = CtField.make("private String ename;", cc);
		cc.addField(f1);
		cc.addField(f2);
		
		//创建方法
		CtMethod m1 = CtMethod.make("public int getEmpno(){return empno;}", cc);
		CtMethod m2 = CtMethod.make("public void setEmpno(int empno){this.empno=empno;}", cc);
		cc.addMethod(m1);
		cc.addMethod(m2);
		
		//添加构造器
		CtConstructor constructor = new CtConstructor(new CtClass[]{CtClass.intType,pool.get("java.lang.String")}, cc);
		constructor.setBody("{this.empno=empno; this.ename=ename;}");
		cc.addConstructor(constructor);
		
		cc.writeFile("c:/myjava"); //将上面构造好的类写入到c:/myjava中
		System.out.println("生成类,成功!");
	}
/**
 * 测试javassist的API
 */
public class Demo02 {
	/**
	 * 处理类的基本用法
	 * @throws Exception 
	 */
	public static void test01() throws Exception{
		ClassPool pool = ClassPool.getDefault();
		CtClass cc = pool.get("com.classloading.testJavassist.Emp");
		
		byte[] bytes = cc.toBytecode();
		System.out.println(Arrays.toString(bytes));
		
		System.out.println(cc.getName()); //获取类名
		System.out.println(cc.getSimpleName()); //获取简要类名
		System.out.println(cc.getSuperclass()); //获得父类
		System.out.println(cc.getInterfaces()); //获得接口
		
	}
	
	/**
	 * 测试产生新的方法
	 * @throws Exception 
	 */
	public static void test02() throws Exception{
		ClassPool pool = ClassPool.getDefault();
		CtClass cc = pool.get("com.classloading.testJavassist.Emp");
		
//		CtMethod m = CtNewMethod.make("public int add(int a,int b){return a+b;}", cc);
		
		CtMethod m = new CtMethod(CtClass.intType,"add",
				new CtClass[]{CtClass.intType,CtClass.intType},cc);
		m.setModifiers(Modifier.PUBLIC);
		// $0=this / $1,$2,$3... 代表方法参数
		m.setBody("{System.out.println(\"www.baidu.cn\");return $1+$2;}");
		
		cc.addMethod(m);
		
		//通过反射调用新生成的方法
		Class clazz = cc.toClass();
		Object obj = clazz.newInstance();  //通过调用Emp无参构造器,创建新的Emp对象
		Method method = clazz.getDeclaredMethod("add", int.class,int.class);
		Object result = method.invoke(obj, 200,300);
		System.out.println(result);
	}
	
	/**
	 * 修改已有的方法的信息,修改方法体的内容
	 * @throws Exception
	 */
	public static void test03() throws Exception{
		ClassPool pool = ClassPool.getDefault();
		CtClass cc = pool.get("com.classloading.testJavassist.Emp");
		
		CtMethod cm = cc.getDeclaredMethod("sayHello",new CtClass[]{CtClass.intType});
		cm.insertBefore("System.out.println($1);System.out.println(\"start!!!\");");
		cm.insertAt(9, "int b=3;System.out.println(\"b=\"+b);");
		cm.insertAfter("System.out.println(\"end!!!\");");
		
		//通过反射调用新生成的方法
		Class clazz = cc.toClass();
		Object obj = clazz.newInstance();  //通过调用Emp无参构造器,创建新的Emp对象
		Method method = clazz.getDeclaredMethod("sayHello", int.class);
		method.invoke(obj, 300);
	}

	/**
	 * 属性的操作
	 * @throws Exception
	 */
	public static void test04() throws Exception{
		ClassPool pool = ClassPool.getDefault();
		CtClass cc = pool.get("com.classloading.testJavassist.Emp");
		
//		CtField f1 = CtField.make("private int empno;", cc);
		CtField f1 = new CtField(CtClass.intType,"salary",cc);
		f1.setModifiers(Modifier.PRIVATE);
		cc.addField(f1);
		
//		cc.getDeclaredField("ename");   //获取指定的属性
		
		//增加相应的set和get方法
		cc.addMethod(CtNewMethod.getter("getSalary", f1));
		cc.addMethod(CtNewMethod.getter("setSalary", f1));

	}
	
	/**
	 * 构造方法的操作
	 * @throws Exception
	 */
	public static void test05() throws Exception {
		ClassPool pool = ClassPool.getDefault();
		CtClass cc = pool.get("com.classloading.testJavassist.Emp");
		
		CtConstructor[] cs = cc.getConstructors();
		for (CtConstructor c : cs) {
			System.out.println(c.getLongName());
		}
	}
	
	
	public static void test06() throws Exception{
		 CtClass cc = ClassPool.getDefault().get("com.classloading.testJavassist.Emp");
		 Object[] all = cc.getAnnotations();
		 Author a = (Author)all[0]; 
		 String name = a.name();
		 int year = a.year();
		 System.out.println("name: " + name + ", year: " + year);

	}
	
	
	public static void main(String[] args) throws Exception {
		test06();
	}
}

9. 类加载全过程:

(1) JVM把class文件加载到内存,并对数据进行校验、解析和初始化,最终形成JVM可以直接使用的Java类型的过程。

*  加载:

将class文件字节码内容加载到内存中,并将这些静态数据转换成方法区中的运行时数据结构,在堆中生成一个代表这个类的java.lang.Class对象,作为方法区类数据的访问入口。 这个过程需要类加载器参与。

* 链接

将Java类的二进制代码合并到JVM的运行状态之中的过程
   • 验证:– 确保加载的类信息符合JVM规范,没有安全方面的问题。
   • 准备:– 正式为类变量(static变量)分配内存并设置类变量初始值的阶段,这些内存都将在方法   区中进行分配
   • 解析:– 虚拟机常量池内的符号引用替换为直接引用的过程

* 初始化

   • 初始化阶段是执行类构造器<clinit>()方法的过程。类构造器<clinit>()方法是由编译器自动收集类中的所有类变量的赋值动作和静态语句块(static块)中的语句合并产生的。
   • 当初始化一个类的时候,如果发现其父类还没有进行过初始化、则需要先出发其父类的初始化
   • 虚拟机会保证一个类的<clinit>()方法在多线程环境中被正确加锁和同步。

(2)类的主动引用(一定会发生类的初始化)
        – new一个类的对象
        – 调用类的静态成员(除了final常量)和静态方法
        – 使用java.lang.reflect包的方法对类进行反射调用
        – 当虚拟机启动,java Hello,则一定会初始化Hello类。说白了就是先启动main方法所在的类
        – 当初始化一个类,如果其父类没有被初始化,则先会初始化他的父类
(3) 类的被动引用(不会发生类的初始化)
        – 当访问一个静态域时,只有真正声明这个域的类才会被初始化
                  • 通过子类引用父类的静态变量,不会导致子类初始化
       – 通过数组定义类引用,不会触发此类的初始化
       – 引用常量不会触发此类的初始化(常量在编译阶段就存入调用类的常量池中了)

(4)类加载器

1)作用:

将class文件字节码内容加载到内存中,并将这些静态数据转换成方法区中的运行时数据结构,在堆中生成一个代表这个类的java.lang.Class对象,作为方法区类数据的访问入口。

2)类缓存:

标准的Java SE类加载器可以按要求查找类,但一旦某个类被加载到类加载器中,它将维持加载(缓存)一段时间。不过,JVM垃圾收集器可以回收这些Class对象。

3)java.lang.ClassLoader类

基本职责就是根据一个指定的类的名称,找到或者生成其对应的字节代码,然后从这些字节代码中定义出一个Java 类,即 java.lang.Class类的一个实例。

4)相关方法

getParent() ----返回该类加载器的父类加载器。
loadClass(String name) ----加载名称为 name的类,返回的结果是 java.lang.Class类的实例。
findClass(String name) ----查找名称为 name的类,返回的结果是 java.lang.Class类的实例。
findLoadedClass(String name) ---查找名称为 name的已经被加载过的类,返回的结果是java.lang.Class类的实例。
defineClass(String name, byte[] b, int off, int len) ---把字节数组 b中的内容转换成 Java 类,返回的结果是java.lang.Class类的实例。这个方法被声明为 final的。
resolveClass(Class<?> c) ----链接指定的 Java 类。
– 对于以上给出的方法,表示类名称的 name参数的值是类的二进制名称。需要注意的是内部类的表示,如com.example.Sample$1和com.example.Sample$Inner等表示方式。

5)类加载器的层次结构(树状结构)

• 引导类加载器(bootstrap class loader)
– 它用来加载 Java 的核心库(JAVA_HOME/jre/lib/rt.jar,或sun.boot.class.path路径下的
内容),是用原生代码来实现的,并不继承自 java.lang.ClassLoader。

• 扩展类加载器(extensions class loader)
– 用来加载 Java 的扩展库(JAVA_HOME/jre/ext/*.jar,或java.ext.dirs路径下的内容) 。
Java 虚拟机的实现会提供一个扩展库目录。该类加载器在此目录里面查找并加载 Java
类。
– 由sun.misc.Launcher$ExtClassLoader实现


• 应用程序类加载器(application class loader)
– 它根据 Java 应用的类路径(classpath,java.class.path 路径下的内容)来加载 Java 类。
一般来说,Java 应用的类都是由它来完成加载的。
– 由sun.misc.Launcher$AppClassLoader实现


• 自定义类加载器
– 开发人员可以通过继承 java.lang.ClassLoader类的方式
实现自己的类加载器,以满足一些特殊的需求。

6)类加载器的代理模式

• 代理模式
– 交给其他加载器来加载指定的类
• 双亲委托机制
– 就是某个特定的类加载器在接到加载类的请求时,首先将加载任务委托给父类加载器,依次追溯,直到最高的爷爷辈的,如果父类加载可以完成类加载任务,就成功返回;只有父类加载器无法完成此加载任务时,才自己去加载。
– 双亲委托机制是为了保证 Java 核心库的类型安全。这种机制就保证不会出现用户自己能定义java.lang.Object类的情况。
– 类加载器除了用于加载类,也是安全的最基本的屏障。
• 双亲委托机制是代理模式的一种
– 并不是所有的类加载器都采用双亲委托机制。
– tomcat服务器类加载器也使用代理模式,所不同的是它是首先尝试去加载某个类,如果找不到再代理给父类加载器。这与一般类加载器的顺序是相反的

7)自定义类加载器的流程

– 1、首先检查请求的类型是否已经被这个类装载器装载到命名空间中了,如果已经装载,直接返回;否则转入步骤2
– 2、委派类加载请求给父类加载器(更准确的说应该是双亲类加载器,真个虚拟机中各种类加载器最终会呈现树状结构),如果父类加
载器能够完成,则返回父类加载器加载的Class实例;否则转入步骤3
– 3、调用本类加载器的findClass(…)方法,试图获取对应的字节码,如果获取的到,则调用defineClass(…)导入类型到方法区;如
果获取不到对应的字节码或者其他原因失败,返回异常给loadClass(…), loadClass(…)转抛异常,终止加载过程(注意:这里的
异常种类不止一种)。
– 注意:被两个类加载器加载的同一个类, JVM不认为是相同的类。

8)线程上下文类加载器

当你需要动态加载资源的时候 , 你至少有三个 ClassLoader 可以选择 :
– 1.系统类加载器或叫作应用类加载器 (system classloader or application classloader)
– 2.当前类加载器
– 3.当前线程类加载器
• 当前线程类加载器是为了抛弃双亲委派加载链模式。
– 每个线程都有一个关联的上下文类加载器。如果你使用new Thread()方式生成新的线程,新线程将继承其父线程的上下文类加载器。如果程序对线程上下文类加载器没有任何改动的话,程序中所有的线程将都使用系统类加载器作为上下文类加载器。

Class<Demo01> c = (Class<Demo01>) Thread.currentThread().getContextClassLoader().loadClass("com.classloading.testClassLoad.Demo01");

9)TOMCAT 服务器的类加载机制

每个 Web 应用都有一个对应的类加载器实例。该类加载器也使用代理模式(不同于前面说的双亲委托机制),所不同的是它是首先尝试去加载某个类,如果找不到再代理给父类加载器。这与一般类加载器的顺序是相反的。但也是为了保证安全,这样核心库就不在查询范围之内。

10)OSGI原理介绍

• OSGi™是 Java 上的动态模块系统。它为开发人员提供了面向服务和基于组件的运
行环境,并提供标准的方式用来管理软件的生命周期。

• 原理:
– OSGi 中的每个模块(bundle)都包含 Java 包和类。

– 模块可以声明它所依赖的需要导入(import)的其它模块的 Java 包和类(通过 Import-Package),也可以声明导出(export)自己的包和类,供其它模块使用(通过 Export-Package)。也就是说需要能够隐藏和共享一个模块中的某些 Java 包和类。

– 这是通过 OSGi 特有的类加载器机制来实现的。OSGi 中的每个模块都有对应的一个类加载器。它负责加载模块自己包含的Java 包和类。

– 当它需要加载 Java 核心库的类时(以 java开头的包和类),它会代理给父类加载器(通常是启动类加载器)来完成。当它需要加载所导入的 Java 类时,它会代理给导出此 Java 类的模块来完成加载。模块也可以显式的声明某些 Java 包和类,必须由父类加载器来加载。只需要设置系统属性 org.osgi.framework.bootdelegation的值即可。

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值