1、类加载器

·简要介绍什么是类加载器,和类加载器的作用

·Java虚拟机中可以安装多个类加载器,系统默认三个主要类加载器,每个类负责加载特定位置的类:BootStrap,ExtClassLoader,AppClassLoader

·类加载器也是Java类,因为其他是Java的类加载器本身也要被类加载器加载,显然必须有第一个加载器不是Java类,这正是BootStrap

·Java虚拟机中的所有类加载器采用具有树形结构进行组织,在实例化每个类装载器对象时,需要为其指定一个父类级的装载器对像或者采用系统默认类装载器为其父类加载

·类加载器之间的父子关系和管辖范围:

注意点:用Eclipse的打包工具将ClassLoaderTest输出成jre/lib/ext目录下的shanhw.jar包,在用Eclipse中运行这个类,运行结果显示为ExeClassLoader。此时环境状态是classpath目录有ClassLoaderTest.class,ext/shanhw.jar包中也有ClassLoarderTest.class,这时候,我们就需要了解类加载的具体过程和原理了

类加载器的委托机制:

·当Java虚拟机要加载一个类时,到底派出那个类加载器去加载呢?1、首先在当前线程的类加载器去在加载线程中的第一个类 2、如果类中A引用了类B,Java虚拟机将使用装载A的装载器来装载B 3、还有可以直接调用ClassLoader.loadClass();方法来指定某个类加载器去加载某个类

· 每个类加载器加载时,优先委托给其上级类加载器;

2、编写自己的类加载器

自定义类加载器,例子:写了三个类,1、MyClassLoaderTest.java 2、MyClassLoader.java 3、ClassLoaderAttachment.java

MyClassLoaderTest.java

 1 package com.shanhw.javaEnhance.thirteenthDay;
 2
 3 import java.util.Date;
 4
 5
 6 /**
 7  * 自定义类加载器
 8  */
 9 public class MyClassLoaderTest {
10
11     public static void main(String[] args) throws Exception {
12         String path = "E:\\Kingsoft Cloud\\Workspaces\\TestExample\\shanhwlib\\ClassLoaderAttachment.class";
13         Class<?> clzz = new MyClassLoader(path).loadClass("com.shanhw.javaEnhance.thirteenthDay.ClassLoaderAttachment");
14         Date d = (Date)clzz.newInstance();
15         System.out.println(d);
16     }
17
18 }

MyClassLoader.java

 1 package com.shanhw.javaEnhance.thirteenthDay;
 2
 3 import java.io.ByteArrayOutputStream;
 4 import java.io.FileInputStream;
 5 import java.io.InputStream;
 6 import java.io.OutputStream;
 7
 8 public class MyClassLoader extends ClassLoader{
 9
10     private static void cypher(InputStream is,OutputStream os) throws Exception{
11         int i = 0;
12         while((i = is.read()) != -1){
13             os.write(i ^ 0xff);
14         }
15     }
16
17     private String classDir;
18
19     public MyClassLoader(String classDir){
20         this.classDir = classDir;
21     }
22
23     @SuppressWarnings("deprecation")
24     @Override
25     protected Class<?> findClass(String name) throws ClassNotFoundException {
26         try {
27
28             FileInputStream fis = new FileInputStream(classDir);
29             ByteArrayOutputStream baos = new ByteArrayOutputStream();
30             cypher(fis,baos);
31             fis.close();
32             byte[] bytes = baos.toByteArray();
33             return defineClass(bytes, 0,bytes.length);
34         } catch (Exception e) {
35             throw new RuntimeException("运行时异常");
36         }
37     }
38 }

ClassLoaderAttachment.java

 1 package com.shanhw.javaEnhance.thirteenthDay;
 2
 3 import java.util.Date;
 4
 5 public class ClassLoaderAttachment extends Date {
 6     /**
 7      *
 8      */
 9     private static final long serialVersionUID = 1L;
10
11     public String toString(){
12         return "Hello Houwang Shan!";
13     }
14 } 

3、分析代理类的作用与原理及AOP概念

·生活中的代理:武汉人从武汉代理商手中买联想电脑和直接跑到北京联想总部买电脑,你觉得最终业务的主体业务目标有什么区别吗?基本上一样,解决了核心问题,从代理商那里买,是不是更方便一些?

·程序中的代理:1、要为已经存在的多个具有相同接口的目标类的各个方法增加一些功能,例如:异常处理、日志、计算方法的运行时间、事物管理等等,你准备如何做?2、编写一个目标类具有相同接口的代理类,代理类的每个方法调用目标类的相同方法,并在调用方法时加上系统功能代码、如图:

3、如果采用工厂模式和配置文件的方式进行管理,则不需要修改客户端程序,在配置文件中配置是使用目标类、还是代理类,这样以后很容易切换,譬如,想要日志功能时,就配置代理类,否则配置目标类,这样,增加系统功能很容易,以后运行一段时间后,又想去掉系统功能也很容易

·AOP

1、系统中存在交叉业务,一个交叉业务就是要切入到系统的一个方面,(安全、事物、日志等要贯穿到好多的模块中,所以它们就是交叉业务)如下所示:

2、用具体的程序代码描述交叉业务

3、交叉业务的编码问题即为面向方面的编程(Aspect Oriented Program 简称AOP),AOP的目标就是使用交叉业务模块儿化。可以采用将切面代码移动到原始方法的周围,这与直接在方法中编写切面代码运行效果是一样的,如下所示:

4、使用代理技术正好可以解决这种问题,代理是实现AOP功能的核心和关键技术

·动态代理技术

1、要为系统中的各种接口的类增加代理功能,那将需要太多的代理类,全部采用静态代理的方式,将是一件非常麻烦的事情,写成成百上千的代理类,是不是太累了

2、JVM可以在运行期动态生成类的字节码,这种动态生成的类,往往被用作代理类,即动态代理

3、JVM生成动态类必须实现一个或者多个接口,所以JVM生成的动态类只能用作具有相同接口的目标类的代理

4、CGLIB库可以动态生成一个类的子类,一个类的子类也可以用作该类的代理,所以,如果要为一个没有实现接口的类生成动态代理,那么可以使用CGLIB库

5、代理类的各个方法中通常除了要调用目标的相应方法和对外返回目标返回的结果外,还可以在代理方法中的如下四个位置加上系统功能代码:

******1、在调用目标方法之前 2、在调用目标方法之后 3、在调用目标方法前后 4、在处理目标方法异常的catch块中

·分析JVM动态生成的类

·1、创建实现了Collection接口的动态类和查看其名称,分析Proxy.getProxyClass方法的各个参数

·2、编码列出动态类中的所有构造方法和参数签名

·3、编码列出动态类中的所有方法和参数签名

·4、创建动态类的实例对象

  1、用反射获得动态方法

  2、编写一个简单的InvocationHandle类

  3、调用构造方法创建动态类的实例对象,并将编写的InvocationHandler类的实例对象传进去

  4、打印创建的对象和调用的对象的没有返回值和getClass方法,演示调用其他返回值的方法报告了异常

  5、将创建动态类的实例对象的代理改成匿名内部类的形式编写,锻炼习惯匿名内部类

1、例子:ProxyTest.java

 1 package com.shanhw.javaEnhance.thirteenthDay;
 2
 3 import java.lang.reflect.Constructor;
 4 import java.lang.reflect.InvocationHandler;
 5 import java.lang.reflect.Method;
 6 import java.lang.reflect.Proxy;
 7 import java.util.ArrayList;
 8 import java.util.Collection;
 9
10 public class ProxyTest {
11
12     /**
13      *
14      */
15     public static void main(String[] args) throws Exception{
16         Class clazzProxy = Proxy.getProxyClass(Collection.class.getClassLoader(), Collection.class);
17         System.out.println("----------Constructors:----------");
18         Constructor[] constructors = clazzProxy.getConstructors();
19         for(Constructor constructor:constructors){
20             String consName = constructor.getName();
21             StringBuilder str = new StringBuilder(consName);
22             str.append('(');
23             Class[] clazzParas = constructor.getParameterTypes();
24             for(Class clazzPara : clazzParas){
25                 str.append(clazzPara.getName()).append(',');
26             }
27             if(clazzParas.length != 0){
28                 str.deleteCharAt(str.length()-1);
29             }
30             str.append(')');
31             System.out.println(str);
32         }
33         System.out.println("----------Methods:----------");
34         Method[] methods = clazzProxy.getMethods();
35         for(Method method:methods){
36             String consName = method.getName();
37             StringBuilder str = new StringBuilder(consName);
38             str.append('(');
39             Class[] clazzParas = method.getParameterTypes();
40             for(Class clazzPara : clazzParas){
41                 str.append(clazzPara.getName()).append(',');
42             }
43             if(clazzParas.length != 0){
44                 str.deleteCharAt(str.length()-1);
45             }
46             str.append(')');
47             System.out.println(str);
48         }
49         System.out.println("----------创建实例对象:----------");
50         Constructor constructor = clazzProxy.getConstructor(InvocationHandler.class);
51
52         Collection collection = (Collection)constructor.newInstance(new InvocationHandler(){
53
54             @Override
55             public Object invoke(Object proxy, Method method, Object[] args)
56                     throws Throwable {
57                 return null;
58             }});
59         Collection proxy = (Collection) Proxy.newProxyInstance(Collection.class.getClassLoader(),
60                 new Class[]{Collection.class},
61                 new InvocationHandler(){
62                     ArrayList arrayList = new ArrayList();
63                     @Override
64                     public Object invoke(Object proxy, Method method,
65                             Object[] args) throws Throwable {
66                         return method.invoke(arrayList, args);
67                     }
68                 });
69         proxy.add("a");
70         proxy.add("a");
71         proxy.add("a");
72         System.out.println(proxy.size());
73     }
74 }

 内部的原理:猜想分析动态生成的类的内部代码?

·动态生成的类实现了Collection接口(可以实现若干接口),生成的类有Collection接口中的所有方法和一个如下接受InvocationHandler参数的构造方法

·构造方法接受一个InvocationHandler对象,接受对象干什么了呢?该方法内部类的代码会是怎么样的呢?

·实现的Collection接口中的各个方法的代码又是怎么样的呢?InvocationHandler接口中定义的invoke方法接受的三个参数是什么意思呢?

·让动态生成的类,成为目标类的代理

1、分析动态代理的工作原理图:

2、怎样将目标类传进去?

****1、在InvocationHandler实现类中创建目标类的实例对象,可以看运行效果和加入日志代码,但是没有实际意义

****2、为InvocationHandler实现类注入目标类的实例对象,不能采用匿名内部类的形式了

****3、让匿名的InvocationHandler实现访问外面方法中的目标类实例对象的final类型的引用变量

3、将创建代理的过程改为一种更优雅的方式,eclipse重构出一个getProxy方法绑定接受目标同时返回代理对象,让调用者更懒惰,更方便,调用者甚至不用接触任何代理的API

4、把系统功能代码模块化,即将切面代码也改为通过参数形式提供,怎样把要执行的系统功能代码从参数形式提供?

****1、把要执行的代码装到一个对象的某个方法里,然后把这个对象作为参数传递,接收者只要调用这个对象的方法,即等于执行外界提供的代码。

****2、为bind方法增加一个Advice参数。

·实现类似Spring的可配置的AOP框架

(实现思路):1、工厂类BeanFactory负责创建目标类或代理类的实例对象,并通过配置文件实现切换,其getBean方法根据参数字符串返回一个相应的实例对象,如果参数字符串在配置文件中对应的类名不是ProxyFactoryBean,则直接返回该类的实例对象,否则,返回该类实例对象的getProxy方法返回的对象

2、BeanFactory的构造方法接收代表配置文件的输入流对象,配置文件格式如下:xxx = java.util.ArrayList #xxx = cn.shanhw.ProxyFactoryBean xxx.target=java.util.ArrayList xxx = advice.shanhw.MyAdvice

·ProxyFactoryBean充当封装生成动态代理的工厂,需要为工厂类提供哪些配置参数信息:1、目标 2、通知

·编写客户端应用 1、编写实现Advice接口的类和配置文件中进行配置 2、调用BeanFactory获取对象

转载于:https://www.cnblogs.com/shanhouwang/archive/2013/03/24/2979737.html

JAVA基础加强(张孝祥)_类加载器、分析代理类的作用与原理及AOP概念、分析JVM动态生成的类、实现类似Spring的可配置的AOP框架...相关推荐

  1. 高新技术(反射、内省、类加载器、代理)

    一.反射 1.概述: 1)Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类中的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:这种动态获取的信息以及动态调用对象的方 ...

  2. java类加载器_类加载器

    回顾一下类加载过程 类加载过程:加载->连接->初始化.连接过程又可分为三步:验证->准备->解析. 一个非数组类的加载阶段(加载阶段获取类的二进制字节流的动作)是可控性最强的 ...

  3. java基础代码实例_基础篇:详解JAVA对象实例化过程

    1 对象的实例化过程 对象的实例化过程是分成两部分:类的加载初始化,对象的初始化 要创建类的对象实例需要先加载并初始化该类,main方法所在的类需要先加载和初始化 类初始化就是执行方法,对象实例化是执 ...

  4. Java高新技术第一篇:类加载器详解

    首先来了解一下字节码和class文件的区别: 我们知道,新建一个java对象的时候,JVM要将这个对象对应的字节码加载到内存中,这个字节码的原始信息存放在classpath(就是我们新建Java工程的 ...

  5. java加载顺序_类加载过程中几个重点执行顺序整理

    正文前先来一波福利推荐: 福利一: 百万年薪架构师视频,该视频可以学到很多东西,是本人花钱买的VIP课程,学习消化了一年,为了支持一下女朋友公众号也方便大家学习,共享给大家. 福利二: 毕业答辩以及工 ...

  6. java课后习题七解析_《Java基础入门》_课后习题解析.doc

    <Java基础入门>_课后习题解析 <Java基础入门>课后习题 Java开发入门 一.填空题 1.Java的三大体系分别是_JavaSE_____._JavaEE_____. ...

  7. spring源码分析第四天------springmvc核心原理及源码分析

    spring源码分析第四天------springmvc核心原理及源码分析 1.基础知识普及 2. SpringMVC请求流程 3.SpringMVC代码流程 4.springMVC源码分析 4.1 ...

  8. spring源码分析第五天------springAOP核心原理及源码分析

    spring源码分析第五天------springAOP核心原理及源码分析 1. 面向切面编程.可以通过预 编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能的一种技术 切面(A ...

  9. java类加载器 架构 设计_类加载器(DexClassLoader)与插件化(动态加载)

    类加载器与插件化解析 2.1 类装载器 DexClassLoader 首先,我们需要了解关于java代码本地import的一些知识: import中所引用的类有两个特点: 1.必须存在于本地,当程序运 ...

最新文章

  1. 游戏开发:js实现简单的板球游戏
  2. 如何从NumPy直接创建RNN?
  3. linux c 编译警告 warning: this decimal constant is unsigned only in ISO C90
  4. ILockBytes Windows Mobile 6.5
  5. 一句话回复:关于'SqlMembershipProvider' requires a database schema compatible with schema version '1'...
  6. 第四范式恭祝大家新春快乐!
  7. 使用String.intern()减少内存使用
  8. nginx_keepalived配置(转载保存)
  9. C++数据结构与算法 竞赛树, 二叉搜索树
  10. linux 路由访问不了php文件,linux系统nginx服务器不能访问php文件问题
  11. Mongoose多数据库连接及实用样例
  12. QueryRunner类 的應用,以及ResultSetHandler 接口的实现类
  13. 一个空格引发的Bug! ----CSV输出和CSV读入
  14. wangeditor光标乱跑,回车换行又返回来问题
  15. 安卓开发之Intent使用介绍(显式Intent和隐式Intent)
  16. 不容错过的 能源logo设计灵感 标志设计
  17. python自动生成ppt_用Python自动化生成倒计时图片
  18. 计算机专业毕业文案,毕业微信朋友圈说说 2020毕业文案经典个性
  19. AI人工智能—数据标注的主要类型和标注注意事项
  20. 如何修改word2016模板

热门文章

  1. 实现全屏轮播,并且轮播div中的文字盒子一直自动垂直居中
  2. MVC日期和其它字符串格式化
  3. Android学习笔记(七):多个Activity和Intent
  4. (转)flash位图缓存cacheAsBitmap
  5. 上云实践操作(漫步云端)之上云动力
  6. 第三章 笔记本电脑案例
  7. springboot设置静态资源不拦截的方法
  8. 设计模式——工厂模式
  9. Visual Studio 2015价格大幅下调
  10. 基于Hibernate的JPA2.0快速构建