java的类加载处理的原则是 用的时候再加载 如果在main方法的启动的时候 有import或者 在后续的延伸的类中 有用到这个类 就会把这个类加载进去 具体可以通过参数 -XX:+TraceClassLoading 进行查看。
我们有如下类
a.A.java b.B.java 我们在B.java 里面写一个main方法 不引入A.java的时候 在控制台是不会打印加载A的信息的 这个时候 方法区是不存在A的信息的。
这里可以spring的处理就方便了 事实上 我们写的代码 和spring框架的代码 是不存在关联的(也不准确 应该说成是两个层好一点)spring框架在启动的时候 是不会去调用的我们的代码的 因为不存在import 而且这个框架本身也不知道不我们写的业务逻辑代码 是无感的。
这个时候那一堆注解就派上用场了,事实上spring不会去通过类加载器去加载我们的代码到jvm中,他会通过类加载器去获取我们的代码的文件目录 然后挨个扫描编译后的class文件(这里 在idea里面和打成jar后类加载器 有所不同 因为文件的组织方式变了)通过注解信息生成一系列的bean信息 这个bean会记录这个类里面所有标识的注解 包括一些需要默认指定的。然后根据注解信息使用代理工具(目前应该是cglib) 进行包装 我们的@requestContoller 以及aop transaction 最后实际运行的其实都是经过处理的class 不是原来的那些了,到目前为止 只是把对应的类文件处理了 替换了 还没有进行加载 因为jvm的机制是 如果加载一个类 会把这个类import的类也一起加载进来。后面应该还有一步替换class文件的操作(这个是我猜的 或许不是替换,总之是替换掉原生的class已经读到内存里面的字节码 不然前面的活就白干了),然后在进行实例化,通过注解装配。
我们的请求是通过springmvc 的控制器转发的 控制器通过我们写的注解 找到对应的实例(已经处理过的class),去调用对应的方法,这个方法会调用service,dao等等 还有事务 或者aop在里面 这些组件实际上都是被spring处理过然后在装配在一起的。
这个如果画个图会更容易理解一些。那个class文件替换 研究明白后 在补上。
到现在感觉 支撑起spring框架的核心技术 其实是cglib 没这个东西 aop 事务什么的根本没法搞。cglib底层用的又是asm。
asm又是静态处理字节码的技术 目前java8(或者更早版本)是有技术可以动态修改字节码的 阿里有个框架arths就可以实现 不过目前没有好好研究过,这个底层用的javaagent 探针技术,这个是动态的。
来源:CSDN
作者:zhaoyu_nb
链接:https://blog.csdn.net/zhaoyu_nb/article/details/103457123