• <noscript id="e0iig"><kbd id="e0iig"></kbd></noscript>
  • <td id="e0iig"></td>
  • <option id="e0iig"></option>
  • <noscript id="e0iig"><source id="e0iig"></source></noscript>
  • Groovy簡介——編譯時方法注入

    一般只用于編寫一些插件或者模板方法的時候使用,編譯后的代碼還是會合成為靜態代碼,會比運行時的處理方式效率更高。需要根據AST來添加對應的語法樹。Groovy編譯器允許我們進入其變異截斷,一窺其所處理的AST(Abstract Syntax Tree 抽象語法樹)。

     

    AST:

    這就是生成的語法樹:

     

    Groovy支持開發者在任何階段介入:初始化、解析、轉換、語義分析、規范化、指令選擇、class生成、輸出和結束

    AST在語義分析階段之后生成,如果想使用信息更多的AST,可以再之后的階段介入。

     

    CodeCheck
    
    package CodeAnalysis
    
    import org.codehaus.groovy.ast.ASTNode
    
    import org.codehaus.groovy.ast.ClassNode
    
    import org.codehaus.groovy.ast.ConstructorNode
    
    import org.codehaus.groovy.ast.FieldNode
    
    import org.codehaus.groovy.ast.GroovyClassVisitor
    
    import org.codehaus.groovy.ast.MethodNode
    
    import org.codehaus.groovy.ast.PropertyNode
    
    import org.codehaus.groovy.control.CompilePhase
    
    import org.codehaus.groovy.control.SourceUnit
    
    import org.codehaus.groovy.syntax.SyntaxException
    
    import org.codehaus.groovy.transform.ASTTransformation
    
    import org.codehaus.groovy.transform.GroovyASTTransformation
    
    
    
    @GroovyASTTransformation(phase = CompilePhase.SEMANTIC_ANALYSIS)
    
    class CodeCheck implements ASTTransformation {
    
        @Override
    
        void visit(ASTNode[] astNodes, SourceUnit sourceUnit) {
    
            sourceUnit.ast.classes.each { classNode ->
    
                classNode.visitContents(new OurClassVisitor(sourceUnit))
    
            }
    
        }
    
    }
    
    class OurClassVisitor implements GroovyClassVisitor{
    
        SourceUnit sourceUnit
    
        OurClassVisitor(theSourceUnit){
    
            sourceUnit = theSourceUnit
    
        }
    
        @Override
    
        void visitClass(ClassNode classNode) {
    
        }
    
    
    
    
    
        @Override
    
        void visitConstructor(ConstructorNode constructorNode) {
    
        }
    
        private void reportError(message, lineNumber, columnNumber){
    
            sourceUnit.addError(new SyntaxException(message, lineNumber, columnNumber))
    
        }
    
        @Override
    
        void visitMethod(MethodNode methodNode) {
    
            if (methodNode.name.size() == 1){
    
                reportError "Make method name descriptive, avoid single letter names",
    
                        methodNode.lineNumber, methodNode.columnNumber
    
            }
    
            methodNode.parameters.each {parameter ->
    
                if (parameter.name.size() == 1){
    
                    reportError "Single letter parameters are morally wrong!",
    
                        parameter.lineNumber, parameter.columnNumber
    
                }
    
            }
    
        }
    
    
    
    
    
        @Override
    
        void visitField(FieldNode fieldNode) {
    
        }
    
        @Override
    
        void visitProperty(PropertyNode propertyNode) {
    
        }
    
    }

     

    OurClassVisitor

     

    package CodeAnalysis
    
    import org.codehaus.groovy.ast.ASTNode
    
    import org.codehaus.groovy.ast.ClassNode
    
    import org.codehaus.groovy.ast.ConstructorNode
    
    import org.codehaus.groovy.ast.FieldNode
    
    import org.codehaus.groovy.ast.GroovyClassVisitor
    
    import org.codehaus.groovy.ast.MethodNode
    
    import org.codehaus.groovy.ast.PropertyNode
    
    import org.codehaus.groovy.control.CompilePhase
    
    import org.codehaus.groovy.control.SourceUnit
    
    import org.codehaus.groovy.syntax.SyntaxException
    
    import org.codehaus.groovy.transform.ASTTransformation
    
    import org.codehaus.groovy.transform.GroovyASTTransformation
    
    
    
    @GroovyASTTransformation(phase = CompilePhase.SEMANTIC_ANALYSIS)
    
    class CodeCheck implements ASTTransformation {
    
        @Override
    
        void visit(ASTNode[] astNodes, SourceUnit sourceUnit) {
    
            sourceUnit.ast.classes.each { classNode ->
    
                classNode.visitContents(new OurClassVisitor(sourceUnit))
    
            }
    
        }
    
    }
    
    class OurClassVisitor implements GroovyClassVisitor{
    
        SourceUnit sourceUnit
    
        OurClassVisitor(theSourceUnit){
    
            sourceUnit = theSourceUnit
    
        }
    
        @Override
    
        void visitClass(ClassNode classNode) {
    
        }
    
        @Override
    
        void visitConstructor(ConstructorNode constructorNode) {
    
        }
    
    
    
    
    
        private void reportError(message, lineNumber, columnNumber){
    
            sourceUnit.addError(new SyntaxException(message, lineNumber, columnNumber))
    
        }
    
    
    
        @Override
    
        void visitMethod(MethodNode methodNode) {
    
            if (methodNode.name.size() == 1){
    
                reportError "Make method name descriptive, avoid single letter names",
    
                        methodNode.lineNumber, methodNode.columnNumber
    
            }
    
            methodNode.parameters.each {parameter ->
    
                if (parameter.name.size() == 1){
    
                    reportError "Single letter parameters are morally wrong!",
    
                        parameter.lineNumber, parameter.columnNumber
    
                }
    
            }
    
        }
    
        @Override
    
        void visitField(FieldNode fieldNode) {
    
        }
    
        @Override
    
        void visitProperty(PropertyNode propertyNode) {
    
        }
    
    }
    
    

    配置文件

     

    manifest/META-INF/services/org.codehaus.groovy.transform.ASTTransformation

    groovyc -classpath checkcode.jar smelly.groovy    

     

    groovyc -d classes CodeAnalysis/CodeCheck.groovy  

    jar -cf checkcode.jar -C classes CodeAnalysis -C manifest .

    groovyc -classpath checkcode.jar smelly.groovy    

     

     

    新建InjectAudit.groovy


     

    package AST.InterceptingCalls.com.aglledeveloper
    
    import org.codehaus.groovy.ast.ASTNode
    
    import org.codehaus.groovy.ast.expr.ArgumentListExpression
    
    import org.codehaus.groovy.ast.expr.MethodCallExpression
    
    import org.codehaus.groovy.ast.expr.VariableExpression
    
    import org.codehaus.groovy.ast.stmt.ExpressionStatement
    
    import org.codehaus.groovy.control.CompilePhase
    
    import org.codehaus.groovy.control.SourceUnit
    
    import org.codehaus.groovy.transform.ASTTransformation
    
    import org.codehaus.groovy.transform.GroovyASTTransformation
    
    
    
    
    
    @GroovyASTTransformation(phase = CompilePhase.SEMANTIC_ANALYSIS)
    
    class InjectAudit implements ASTTransformation {
    
        @Override
    
        void visit(ASTNode[] astNodes, SourceUnit sourceUnit) {
    
            def checkingAccountClassNode =
    
                    astNodes[0].classes.find {
    
                        it.name == 'AST.InterceptingCalls.CheckingAccount'
    
                    }
    
            injectAuditMethod(checkingAccountClassNode)
    
        }
    
    
    
        static void injectAuditMethod(checkingAccountClassNode){
    
            def nonAuditMethods =
    
                    checkingAccountClassNode?.methods.findAll{ it.name != 'audit'}
    
            nonAuditMethods?.each { injectMethodWithAudit(it) }
    
        }
    
    
    
        static void injectMethodWithAudit(methodNode){
    
            def callToAudit = new ExpressionStatement(
    
                    new MethodCallExpression(
    
                            new VariableExpression('this'),
    
                            'audit',
    
                            new ArgumentListExpression(methodNode.parameters)
    
                    )
    
            )
    
            methodNode.code.statements.add(0, callToAudit)
    
        }
    
    }
    
    

     

    groovyc -d classes AST/InterceptingCalls/com/aglledeveloper/InjectAudit.groovy    

    jar -cf injectAudit.jar -C classes AST -C manifest .

    生成對應的jar包

     

    UsingCheckingAccount.groovy
    
    package AST.InterceptingCalls
    
    class CheckingAccount {
    
        def audit(amount) {
    
            if (amount > 10000){
    
                print "auditing ..."
    
            }
    
        }
    
    
    
    
    
        def deposit(amount){
    
            println "depositing ${amount} ..."
    
        }
    
        def withdraw(amount){
    
            println "withdrawing ${amount} ..."
    
        }
    
    }
    
    def account = new CheckingAccount()
    
    account.deposit(1000)
    
    account.deposit(12000)
    
    account.withdraw(11000)
    
    
    
    
    
    groovy src/groovy/AST/InterceptingCalls/UsingCheckingAccount.groovy
    
    
    
    depositing 1000 ...
    
    depositing 12000 ...
    
    withdrawing 11000 ...
    
    
    
    depositing 1000 ...
    
    auditing ...depositing 12000 ...
    
    auditing ...withdrawing 11000 ...
    
    

     

    執行:

    groovyc -d classes src/groovy/AST/InterceptingCalls/com/aglledeveloper/InjectAudit.groovy

    jar -cf injectAudit.jar -C classes AST -C manifest .    

    groovy -classpath injectAudit.jar src/groovy/AST/InterceptingCalls/UsingCheckingAccount.groovy

     

     

    結果:

    depositing 1000 ...

    auditing ...depositing 12000 ...

    auditing ...withdrawing 11000 ...

     

    *audit方法被應用在最前方,當對于10000的時候會自動審計

     

     

    版權聲明:本文為thunder_sz原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接和本聲明。
    本文鏈接:https://blog.csdn.net/thunder_sz/article/details/103259206

    智能推薦

    styled-components —— React 中的 CSS 最佳實踐

    https://zhuanlan.zhihu.com/p/29344146 Styled-components 是目前 React 樣式方案中最受關注的一種,它既具備了 css-in-js 的模塊化與參數化優點,又完全使用CSS的書寫習慣,不會引起額外的學習成本。本文是 styled-components 作者之一 Max Stoiber 所寫,首先總結了前端組件化樣式中的最佳實踐原則,然后在此基...

    基于TCP/IP的網絡聊天室用Java來實現

    基于TCP/IP的網絡聊天室實現 開發工具:eclipse 開發環境:jdk1.8 發送端 接收端 工具類 運行截圖...

    19.vue中封裝echarts組件

    19.vue中封裝echarts組件 1.效果圖 2.echarts組件 3.使用組件 按照組件格式整理好數據格式 傳入組件 home.vue 4.接口返回數據格式...

    劍指Offer39-調整數組順序使奇數位于偶數前面

    一開始想著用冒泡排序的方法來做,但是bug還是很多,后來看了評論區答案,發現直接空間換時間是最簡單的,而且和快排的寫法是類似的。...

    【一只蒟蒻的刷題歷程】【藍橋杯】歷屆試題 九宮重排 (八數碼問題:BFS+集合set)

    資源限制 時間限制:1.0s 內存限制:256.0MB 問題描述 如下面第一個圖的九宮格中,放著 1~8 的數字卡片,還有一個格子空著。與空格子相鄰的格子中的卡片可以移動到空格中。經過若干次移動,可以形成第二個圖所示的局面。 我們把第一個圖的局面記為:12345678. 把第二個圖的局面記為:123.46758 顯然是按從上到下,從左到右的順序記錄數字,空格記為句點。 本題目的任務是已知九宮的初態...

    猜你喜歡

    dataV組件容器寬高發生變化后,組件不會自適應解決方法

    項目中需要大屏幕數據展示,于是使用了dataV組件,但是使用是發現拖動瀏覽器邊框,dataV組件顯示異常,如圖: 于是查了官網,官網的解釋如下:   于是按照官網的意思編寫代碼: 于是可以自適應了...

    CSS3干貨10:如何做一個板塊標題水平線左邊帶顏色效果

    很多網站在設計欄目標題的時候,喜歡用下劃線分開欄目標題和內容部分。 而且線條左邊的部分往往還有顏色,且這個顏色跟標題的文字長短保持一致。效果如圖所示: 這種效果其實很簡單。 我這里給大家推薦兩種方式: 假定我們的標題部分 HTML 結構如下: 方式一:利用下邊框。灰色部分是 h1 的下邊框,藍色部分是 span 標簽的下邊框。 h1 的高度為 40px,span 也設置它的高度為 40px。這樣,...

    拜師————python基礎入門——程序的構成,對象,引用,棧內存和堆內存,標識符命名規則——day4

    第九節課:任務9:009.程序的構成 Python程序的構成,一個程序是由什么構成的 1.python程序由模塊組成 , 一個模塊對應一個python源文件,(文件后綴名.py) 2.模塊由語句構成 運行程序時,安裝模塊中語句的順序依次執行。 代碼的組織和縮進 “龜叔”在設計python時,直接通過縮進來組織代碼 縮進時,幾個空格都是允許的,但是空格數必須統一,我們通常用四...

    spark 總結 算子篇

    1、創建工程 在這里添加 spark core包,添加bulid 插件。 算子總結 map 算子 主要是做數據結構的轉換,數據條數不變。 mapPartitions(func) 對分區數據進行轉換。將某一個分區的所有數據拿過來形成一個可迭代的集合要求 返回可迭代的集合。提高效率會使用它。 應用場景: 只對分區內數據進行數據。缺點是不釋放,可能導致oom。 當內存空間較大的時候建議使用 mapPar...

    淺析Redis復制過程

    文章目錄 摘要 復制 當 Master 關閉持久化時,復制的安全性 復制的工作原理 配置 只讀 Slave 寫入Master Slave如何處理key的過期 參考 摘要 Redis默認使用異步復制,其特點是低延遲和高性能。異步復制就意味著在故障轉移期間,有丟失數據的風險。你可以參考Redis 集群文檔,了解關于高可用性和故障轉移的信息,本文主要討論Redis 復制功能的基本特性。 復制 在 Red...

    精品国产乱码久久久久久蜜桃不卡