<menu id="guoca"></menu>
<nav id="guoca"></nav><xmp id="guoca">
  • <xmp id="guoca">
  • <nav id="guoca"><code id="guoca"></code></nav>
  • <nav id="guoca"><code id="guoca"></code></nav>

    SpringBoot 實現異步記錄復雜日志

    VSole2023-01-07 10:08:53

    1、背景

    最近接手一個任務,需要給當前項目加一個較為復雜的日志。有多復雜呢? 要有日志類型、不同日志類型要有不同的操作和備注等。作為小白的我最開始的做法是在業務層寫代碼記錄日志,好處就是方便,壞處就是這種做法直接侵襲Service層,Service層無法做到職責單一了。

    經導師點撥,改用自定義注解+AOP切面異步日志

    2、技術方案-自定義注解

    注解(Annotation),也叫元數據。

    2.1 注解介紹

    注解其實就是代碼里的特殊標記,這些標記可以在編譯、類加載、運行時被讀取,并執行相應的處理。通過使用注解,程序員可以在不改變原有邏輯的情況下,在源文件中嵌入一些補充信息。

    2.2 元注解

    元注解用于修飾其他注解的注解,在JDK5.0中提供了四種元注解:Retention、Target、Documented、Inherited

    (1) Retention
    用于修飾注解,用于指定修飾的哪個注解的聲明周期。@Rentention包含一個RetentionPolicy枚舉類型的成員變量,使用@Rentention時必須為該value成員變量指定值

    RetentionPolicy.SOURCE:在源文件中有效(即源文件保留),編譯器直接丟棄這種策略的注釋,在.class文件中不會保留注解信息

    RetentionPolicy.CLASS:在class文件中有效(即class保留),保留在.class文件中,但是當運行java程序時,他就不會繼續加載了,不會保留在內存中,JVM不會保留注解。如果注解沒有加Retention元注解,那么相當于默認的注解就是這種狀態。

    RetentionPolicy.RUNTIME:在運行有效(即運行時保留),當運行Java程序時,JVM會保留注釋,加載在內存中,那么程序可以通過反射獲取該注釋。

    @Documented
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.ANNOTATION_TYPE)
    public @interface Retention {
     
        RetentionPolicy value();
    }
     
    public enum RetentionPolicy {
     
        SOURCE,
     
        CLASS,
     
        RUNTIME
    }
    
    (2)Target

    用于修飾注解的注解,定義當前注解能夠修飾程序中的哪些元素(類、屬性、方法,構造器等等)

    @Documented
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.ANNOTATION_TYPE)
    public @interface Target {
     
        ElementType[] value();
    }
    
    (3)Documented

    用于指定被該元注解修飾的注解類將被javadoc工具提取成文檔。默認情況下,javadoc是不包括注解的,但是加上這個注解生成的文檔中就會帶著注解了

    @Documented
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.ANNOTATION_TYPE)
    public @interface Documented {
    }
    
    (4)Inherited

    被它修飾的Annotation將具有繼承性。如果某個類使用了被@Inherited修飾的Annotation,則其子類將自動具有該注解。

    @Documented
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.ANNOTATION_TYPE)
    public @interface Inherited {
    }
    

    注解的基礎知識基本介紹完畢,我們開始寫起來吧!!!

    2.3 實現自定義注解

    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Inherited
    public @interface Log {
        // 日志類型
        LogType logType() ;
        // 操作類型
        OperateType operate();
        // 備注
        String note() default "";
    }
    

    3、技術方案-AOP切面

    AOP切面編程一般可以幫助我們在不修改現有代碼的情況下,對程序的功能進行拓展, 往往用于實現 日志處理,權限控制,性能檢測,事務控制等。AOP實現的原理就是動態代理。在有接口的情況下,使用JDK動態代理,在沒有接口的情況下使用cglib動態代理。

    3.1 AOP術語解析

    • Joint point:類里面那些可以被增強的方法,這些方法被稱之為連接點
    • PointCut:實際被增強的方法,這些方法被稱之為連接點
    • Advice:實際增加的邏輯部分稱為通知
    • Target:被增強功能的對象(被代理的對象)
    • Aspect:Aspect 聲明類似與Java中的類聲明,在Aspect中會包含著一些PointCut以及相應的Advice.
    • Weaving:創建代理對象并實現功能增強的聲明并運行過程將Aspect和其他對象連接起來,并創建Adviced object的過程

    3.2 切入點表達式

    切入點表達式:通過一個表達式來確定AOP要增強的是哪個或者哪些方法.

    3.2 ADVICE通知類型

    • 前置通知:@Before 執行前置通知,并通過JointPoint獲取方法中的參數
    @Aspect
    @Component
    public class DaoAspect {
     
     /*
     前置通知:在執行addUser方法之前,執行前置通知,并通過JointPoint獲取addUser()方法中的參數
     */
        @Before("execution(* com.xzit.dao.Impl.UserDaoImpl.addUser(..))")
        public void methodBefore(JoinPoint joinPoint){
            System.out.println("methodBefore invoked ... ...");
            Object[] args = joinPoint.getArgs();
            System.out.println(Arrays.toString(args));
     
        }
    }
    
    • 后置通知@After 切點方法是否出現異常,后置通知都會執行
    • 返回通知@AfterReturning 切點出現異常,返回通知不會執行
    • 異常通知@AfterThrowing 切點方法出現異常就執行,不出現異常就不執行
    • 環繞通知@Around 在切點方法之前和之后執行。是@Before@AfterReturing 相結合

    3.3 技術實現

    根據任務背景,我選擇了返回通知@AfterReturning。使用返回通知一定要注意的是:由于我需要用到返回值,所以會用@AfterReturning注解中的returning屬性來獲取方法的返回值

    returning指定的名稱必須和切面方法參數中的名稱相同。例如在下面代碼中指定的"cId"都是相同的

    @AfterReturning(pointcut = "@annotation(com.xxx.xxx.xxx.Log)",
            returning = "cId")
    public void handleRdLogs(JoinPoint joinPoint, int cId) 
    

    切面方法參數中的參數類型必須和方法返回類型一致

    @AfterReturning(pointcut = "@annotation(com.xxx.xxx.xxx.Log)",
            returning = "cId")
    public void handleRdLogs(JoinPoint joinPoint, int cId) {
        // 獲取方法簽名
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        // 獲取@Log注解內容
        if (!methodSignature.getMethod().isAnnotationPresent(Log.class)) {
            log.error("獲取注解@Log失敗");
            throw new Exception("獲取注解@Log失敗");
        }
        Log log = methodSignature.getMethod().getAnnotation(Log.class);
        // 輸出日志的備注
        System.out.println(log.note())
    }
    

    3.4 相關操作

    (1) 獲取方法簽名

    MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();`
    

    (2)根據方法簽名獲取自定義注解

    Log log = methodSignature.getMethod().getAnnotation(Log.class);
    

    (3)根據自定義注解獲取,注解內部的參數

    System.out.println(log.note())
    

    4、高級操作

    場景:不僅需要獲取返回值,還得知道方法參數的值,而且方法參數的值不能作為返回值,這個該怎么辦呢?

    秀操作開始:

    第一步:在注解上寫 "#" + "方法參數的名"

    @Log(note = "#note")
    public int rdAuditReturn(String note) {
         System.out.println(note)
         xxxx.....
         xxxx.....
         業務代碼.....
         xxxx.....
         xxxx....
        return cId;
    }
    

    第二步:實現切面,只要調用這個方法,就可以得到note的值了

    private final ExpressionParser parser = new SpelExpressionParser();
    private final EvaluationContext evaluationContext = new StandardEvaluationContext();
     
     
    private void getNote(JoinPoint joinPoint, StringBuilder noteBuilder, String note) throws NoSuchMethodException {
        if (!StringUtils.isBlank(note)) {
            Class targetCls = joinPoint.getTarget().getClass();
            MethodSignature ms = (MethodSignature) joinPoint.getSignature();
            Method targetMethod = targetCls.getDeclaredMethod(ms.getName(), ms.getParameterTypes());
            ParameterNameDiscoverer pnd = new DefaultParameterNameDiscoverer();
            String[] parameterNames = pnd.getParameterNames(targetMethod);
            Object[] args = joinPoint.getArgs();
            for (int i = 0; i < args.length; ++i) {
                int index = i;
                Optional.ofNullable(args[i]).ifPresent(param -> {
                    String paramName = parameterNames[index];
                    this.evaluationContext.setVariable(paramName, param);
                });
            }
            Optional.ofNullable(this.parser.parseExpression(note).getValue(this.evaluationContext)).ifPresent(k ->
                    noteBuilder.append((String) k)
            );
        }
    }
    
    logtarget
    本作品采用《CC 協議》,轉載必須注明作者和本文鏈接
    Android 應用gl,使用了加固i,老版本的應用gl是js源碼,新版本更新后,剛開始以為是加密了源碼,分析后才知道是使用了Hermes優化引擎。Hermes優化的優化效果如下:優化前:優化后:二、前期準備2.1 繞過root檢測應用gl使用了加固i,在被root 的手機上運行,閃退。繞過方法也很簡單,在magisk的設置中,開啟遵守排除列表,然后在配置排除列表中選擇應用gl。
    靶機Agile補充圖片
    2023-03-22 10:04:15
    Nmap done: 1 IP address scanned in 171.68 seconds. 添加host└─# echo "10.10.11.203 superpass.htb" >> /etc/hosts. 注冊個賬號就讀取了。我們可以在 python 中創建一個腳本,自動實現這個過程,只需要輸入的文件路徑└─# cat lfi.py. data = {"username": "123", "password": "123", "submit": ""}
    mysql提權總結
    2021-09-17 15:04:08
    使用過MySQL的人都知道,MySQL有很多內置函數提供給使用者,包括字符串函數、數值函數、日期和時間函數等,給開發人員和使用者帶來了很多方便。
    如果您遇到使用 WordPress 的網站,您會怎么做,滲透思路和安全檢測思路?如何挖掘Wordpress網站的漏洞如果您訪問https://target.com并查看源代碼,您將看到來自 WordPress 的主題和插件的鏈接。獲取網站上的用戶名http://target.com/?
    Ceye DNS:DNS oob平臺 http://ceye.io/. TLS證書信息查詢Censys:https://censys.io. 網絡空間搜索Fofa:https://fofa.info/
    Ceye DNS:DNS oob平臺 http://ceye.io/. TLS證書信息查詢Censys:https://censys.io. 網絡空間搜索Fofa:https://fofa.info/
    技術已經改變了一切,從我們經營業務的方式到我們的生活方式。但伴隨著便利而來的是新的威脅。Target、Facebook 和 Equifax 等公司的高調安全漏洞提醒人們,沒有人能幸免。作為技術領導者,我們有責任創造一種文化,在這種文化中,保護數字應用程序和生態系統是每個人的責任。
    需要llvm 11+,這是當前afl支持的效率最高的選擇,也意味著編譯要花更長時間。實現了編譯級插樁,效果比匯編級插樁更好。從編譯的實現流程上理解插樁模式差異:afl-gcc插樁分析考慮到afl的插樁方式隨編譯器的選擇而變化,從最簡單的afl-gcc開始入手。
    通過log頁面,可以搜索指定的版本進行下載。總的來說docker和VM的編譯流程沒有太大區別,因為我習慣在VM環境下進行操作,因此下文的編譯流程都是在VMware17 Pro中進行操作的。編譯流程我是在VMware中編譯內核,步驟如下:1.創建一個虛擬機并安裝操作系統。
    隨著攻防演練的頻繁和?們安全意識的提升,企業內部Windows主機的?令也設置的較為復雜,經 常拿到windows 服務器的時候,獲取到了hash,但是?法解密出密碼的情況,這時候就需要?法,攻擊者不需要花費時間來懟hash進?02測試環境Windows server 2012 ?先需要獲取ntml hash,由于直接從內存讀取到的可能是密碼修改之前的hash,這?些遠程命令的執??持wmi,默認開啟,且windows 默認不會將wmi 的操作記錄到?具的原理是wmi 創建進程執?impacket 中的smbexec 程序,命令如下python3 smbexec.py -hashes
    VSole
    網絡安全專家
      亚洲 欧美 自拍 唯美 另类