`

Kilim源码分析之二 ---- 织入入口及可织入判断

阅读更多

1、织入入口,配置

    1.1、织入入口 
        kilim.tools.Weaver是织入的主类,通过程序参数设置要织入的代码路径,可以是class文件、jar包、其他(是什么)、目录(目录中可以是jar包、class文件)。
        如果传入的是class文件,会直接织入;调用kilim.tools.Weaver.weaveFile(String, InputStream, Detector)织入
        如果是jar包,会解析jar文件,for循环时候,jdk会把for编译成iterator接口实现,对于jar文件,实际提取文件内容的是kilim.analysis.JarIterator,从java.util.jar.JarFile中直接获取所有entries,for循环中返回的每一项(class文件或者目录)都是FileLister.Entry的子类JEntry,可以获取文件名、文件流和文件大小。然后循环jar文件中每一项,如果是class文件就织入,调用接口同传入class文件一样。
        如果是目录,则会递归目录,但是也只会处理目录下的class文件,不会处理目录下的jar包。处理方式类似jar包,会调用迭代器DirIterator处理,迭代器没有用递归实现,而是自己放入了个Stack。迭代时候每次返回FileLister.Entry的子类DirEntry。jar包验证,处理.            
    1.2、ant配置
 
<java classname="kilim.tools.Weaver" fork ="yes">
	<classpath refid="kilim.classpath"/>
	<assertions>
		<enable/>
	</assertions>
	<arg value="-x" />
	<!-- Skip classes that match ExInvalid. These are negative tests for the weaver. Also skip tests for this pass-->
	<arg value="ExInvalid|test" />
	<arg value="-d" />
	<arg value="./classes" />
	<arg line="./classes" />
</java>
     

2、可织入分析 && 织入文件

    2.1、织入接口kilim.tools.Weaver.weaveFile(String, InputStream, Detector)

        在1中的织入入口会调用到,包括织入代码,把织入后的代码写到磁盘:

static void weaveFile(String name, InputStream is, Detector detector) throws IOException {
        try {
            ClassWeaver cw = new ClassWeaver(is, detector);
            cw.weave();//织入
            writeClasses(cw);//把织入后的代码字节数据从ClassInfo写入到class文件
        } catch (KilimException ke) {
            System.err.println("***** Error weaving " + name + ". " + ke.getMessage());
            // ke.printStackTrace();
            err = 1;
        } catch (RuntimeException re) {
            System.err.println("***** Error weaving " + name + ". " + re.getMessage());
            re.printStackTrace();
            err = 1;
        } catch (IOException ioe) {
            err = 1;
            System.err.println("***** Unable to find/process '" + name + "'\n" + ioe.getMessage());
        }
    }
              创建ClassWeaver的时候,传入的decetor是Detector.DEFAULT,一个默认的实现,这个类主要用来判断类是否需要织入、织入状态灯。
        ClassWeaver封装了ClassFlow,ClassFlow是继承了ClassNode的,ClassNode是asm拿着类文件中所有内容构造的一棵树。在构造ClassWeaver的时候,就会构造一个ClassFlow对象:
    public ClassWeaver(InputStream is, Detector detector) throws IOException {
        classFlow = new ClassFlow(is, detector);
    }
         cw.weave()[kilim.analysis.ClassWeaver.weave()]是织入的地方,包括对字节码的分析、通过ClassWriter织入、把植入后的字节码转换成ClassInfo对象:
public void weave() throws KilimException {
        classFlow.analyze(false);//分析
        if (needsWeaving() && classFlow.isPausable()) {
            ClassWriter cw = new ClassWriter(false);
            accept(cw);//对需要进行织入的方法进行织入
            addClassInfo(new ClassInfo(classFlow.getClassName(), cw.toByteArray()));//把需要植入后的字节码从ClassWriter放入到ClassInfo
        }
    }
     ClassFlow.analyze(false),对一个方法是否需要织入的分析,方法isPausable为true的就是可织入的:
public ArrayList<MethodFlow> analyze(boolean forceAnalysis) throws KilimException {
        Detector save = Detector.setDetector(detector);
        try {
            cr.accept(this, false);//把当前ClassFlow实例传入到ClassReader中,会把当前类信息填充到ClassFlow中
            for (Object o : this.fields) {
                FieldNode fn = (FieldNode) o;
                if (fn.name.equals(Constants.WOVEN_FIELD)) {//织入的时候会写入的一个变量,如果已经有了,则表明已经织入过
                    isWoven = true;
                    break;
                }
            }
            if (isWoven && !forceAnalysis) 
                return new ArrayList<MethodFlow>(); // This is a hack. 如果织入过并且不强制织入,就返回。强制呢? 
            cr = null; // We don't need this any more.
            classDesc = TypeDesc.getInterned("L" + name + ';');//类型描述符
            ArrayList<MethodFlow> flows = new ArrayList<MethodFlow>(methods.size());
            String msg = "";
            for (Object o : methods) {
                try {
                    MethodFlow mf = (MethodFlow) o;
                    if (mf.isBridge()) {//方法access_flag包含bridge的方法,方法由编译器产生
                        MethodFlow mmf = getOrigWithSameSig(mf);//获取bridge方法对应的原始方法
                        if (mmf != null)
                            mf.setPausable(mmf.isPausable());//把birdge方法的pausable属性设置给原始方法
                    }
                    mf.verifyPausables();//验证可织入性,如果已经织入或者不需要织入是直接返回了的
                    if (mf.isPausable())
                        isPausable = true;
                    if ((mf.isPausable() || forceAnalysis) && (!mf.isAbstract())) {
                        mf.analyze();
                    }
                    flows.add(mf);
                } catch (KilimException ke) {
                    msg = msg + ke.getMessage() + "\n-------------------------------------------------\n";
                }
            }
            if (msg.length() > 0) {
                throw new KilimException(msg);
            }
            methodFlows = flows;
            return flows;
        } finally {
            Detector.setDetector(save);
        }
    }
        mf.isBridge()里边是判断方法access flag是否有bridge标记,这种方法是由编译器生成,是JDK1.5引入泛型后,为了是java泛型方法生成的字节码和1.5之前的字节码相兼容,由编译器[为某个方法]自动生成的。更多关于bridge的信息,猛击这里这里
分享到:
评论
6 楼 yueyemaitian 2013-10-16  
runfriends 写道
yueyemaitian 写道
runfriends 写道
用kilim把用到的所有类 包括tomcat jar、jdk的jar和第三方库还有自己的类都织入一遍可行吗?

怎么会有这样的需求呢,jdk、tomcat的类你也要加pausable么?我没这么干,我只是织入了我们依赖的业务jar包,织入了近900+个类

那要是jdk tomcat也织入了不会有不好的影响吧


jdk的,你要看能不能加载成功,jdk自己类加载有安全限制的。如果成功,功能正确也可以接受吧
5 楼 runfriends 2013-10-16  
yueyemaitian 写道
runfriends 写道
用kilim把用到的所有类 包括tomcat jar、jdk的jar和第三方库还有自己的类都织入一遍可行吗?

怎么会有这样的需求呢,jdk、tomcat的类你也要加pausable么?我没这么干,我只是织入了我们依赖的业务jar包,织入了近900+个类

那要是jdk tomcat也织入了不会有不好的影响吧
4 楼 yueyemaitian 2013-10-15  
runfriends 写道
用kilim把用到的所有类 包括tomcat jar、jdk的jar和第三方库还有自己的类都织入一遍可行吗?

怎么会有这样的需求呢,jdk、tomcat的类你也要加pausable么?我没这么干,我只是织入了我们依赖的业务jar包,织入了近900+个类
3 楼 runfriends 2013-10-13  
用kilim把用到的所有类 包括tomcat jar、jdk的jar和第三方库还有自己的类都织入一遍可行吗?
2 楼 yueyemaitian 2013-09-24  
runfriends 写道
kilim自己的类也需要织入吗?
如果是都有哪些类需要织入呢?

需要织入的,有Pausable的异常抛出的方法都需要织入,eg. Mailbox、Task,还会生成一些pojo对象用来存储中间结果。kilim里边的ant文件里边有自己织入自己的target
kilim/S_O.class
kilim/S_O3L2.class
kilim/S_O2.class
kilim/S_O2IL.class
kilim/Cell.class
kilim/Generator.class
kilim/S_O2L.class
kilim/Mailbox.class
kilim/Task.class
kilim/TaskGroup.class
kilim/S_OI.class
kilim/S_O2I2.class
kilim/S_OI2.class
kilim/http/HttpRequest.class
kilim/http/HttpResponse.class
kilim/http/HttpSession.class
kilim/S_O2I.class
kilim/S_O2I3.class
kilim/S_I3.class
kilim/S_O2IL2.class
kilim/S_O2L2.class
kilim/nio/EndPoint.class
kilim/S_I.class
kilim/nio/NioSelectorScheduler$ListenTask.class
kilim/nio/NioSelectorScheduler$RegistrationTask.class
1 楼 runfriends 2013-09-21  
kilim自己的类也需要织入吗?
如果是都有哪些类需要织入呢?

相关推荐

    actor线程库:kilim0.6

    在kilim-0.6这个压缩包中,包含了kilim库的源码、文档和其他相关资源。使用者可以通过阅读源码了解其内部实现机制,或者直接将其导入到项目中使用。kilim的核心特性包括: 1. **异步消息传递**:每个Actor都有自己...

    协程Coroutine和Kilim

    协程Coroutine和Kilim是两个与并发编程相关的概念,主要在Java开发环境中被讨论。在现代软件系统中,多线程和并发处理是提升性能和响应能力的关键技术。协程提供了一种轻量级的并发模型,它比传统的线程更高效,内存...

    基于角色的消息传递框架Kilim.zip

    Kilim 是一种 Java 消息传递框架,提供了超轻量级的线程,推动了线程之间迅速、安全、无需复制的消息传递的实现。 Kilim 使用 Java 编写,融入了角色模型的概念。在 Kilim 中,“角色” 是使用 Kilim 的 Task 类型...

    JAVA版本his系统源码-kilim:用于Java的轻量级线程,具有消息传递、nio、http和调度支持

    JAVA版本他的系统源码Kilim :JVM 的延续、纤维、Actor 和消息传递 Kilim 由 2 个主要组件组成: Kilim weaver 修改已编译的 java 类的字节码,启用一种方法来保存它的状态并放弃对其线程的控制,即协同多任务 Kilim...

    基于Kilim、Promise JDeferred、Zookeeper和Spring Boot的协程分布式调用聚合框架设计源码

    该项目是一款基于Kilim、Promise JDeferred、Zookeeper和Spring Boot技术的协程驱动分布式调用聚合框架。源码包含223个文件,涵盖143个Java源文件、33个XML配置文件、13个GIF图片、7个JAR包、5个批处理脚本、4个属性...

    kilim-motifs:具有Lindenmayer系统的程序性Kilim主题生成

    《kilim-motifs:基于Lindenmayer系统的程序化Kilim图案生成》 ...同时,"kilim-motifs"也提供了一个实例,说明了开源软件如何促进创新,让全球的开发者都能参与到艺术和技术的融合之中,推动生成艺术的发展。

    vivo X9主板原理图及PCB板图

    ### vivo X9 主板原理图及 PCB 板图解析 #### 概述 本文将针对“vivo X9 主板原理图及 PCB 板图”进行深入解析,旨在为相关技术人员提供维修参考与技术支持。vivo X9 作为一款广受欢迎的智能手机型号,其主板设计...

    mapleliang-Jungle Server Core使用与扩展1

    通过以上介绍,我们可以看到Jungle Server Core提供了强大的灵活性和可扩展性,无论是从协议支持还是处理器设计,都能满足复杂的服务场景需求。开发者可以根据自身业务特点,充分利用这些特性来构建高效稳定的服务器...

    协程式驱动框架Nepxion-Coroutine.zip

    Coroutine是基于Kilim/Promise JDeferred的协程式驱动框架,基于Apache Zookeeper的分布式规则存储和动态规则变更通知。 主要特性: 1. 基于微服务框架理念设计 2. 支持同步/异步调用 3. 支持串行/并行调用 4....

    在Java中使用协程.pdf

    在Java中,虽然语言本身并不直接支持协程,但在Sun JDK 7发布之前,开发者可以借助其他工具或语言,如Scala和Kilim,来实现协程的概念。 Scala是一种基于JVM的多范式编程语言,它不仅支持面向对象编程,还支持函数...

Global site tag (gtag.js) - Google Analytics