进行方法级注释,该注释告诉方法将所有日志保存到数据库

发布于 2025-01-23 12:55:19 字数 158 浏览 3 评论 0 原文

我的问题是,我的项目中的许多方法现在需要存储它们的日志,AOP并不是很可行需要。

注释方法将调用一种自定义方法,以存储每当登录其中的东西时存储日志消息。

我从来没有做过注释,也不真正熟悉反思,所以我想知道这样的事情是否可以可行,还是您建议某种方法。

非常感谢。

My problem is that a lot of methods in my project now require to have their logs stored, AOP isn't very viable since there isn't an appropriate point to cut, so I'm thinking about making a custom annotation and putting it wherever it's needed.

Annotated methods would call a custom method to store the log message whenever something is logged inside it.

I have never made annotations and I'm not really familiar with reflection, so I would like to know if such a thing would be doable, or is there some kind of approach you would suggest.

Thank you very much.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

妖妓 2025-01-30 12:55:20

最后,我使用记录过滤器过滤所有日志记录事件,然后使用iLoggingeent的stacktrace来找出记录事件的堆栈中是否存在注释。

注释:

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface StoreLog {

    //business logic hidden

}

这是过滤器的实现:

public class SaveLogFilter extends Filter<ILoggingEvent> {

    @Override
    public FilterReply decide(ILoggingEvent event) {
        if (event.getLevel() == Level.DEBUG) {
            return FilterReply.DENY;
        }
        StackTraceElement[] callerData = event.getCallerData();
        if (callerData != null && callerData.length > 0) {
            for (StackTraceElement stackTraceElement : callerData) {
                StoreLog annotation;
                try {
                    Class clazz = Class.forName(stackTraceElement.getClassName());
                    annotation = (StoreLog) clazz.getAnnotation(StoreLog.class);
                    if (annotation == null) {                      
                        Method method = ReflectionUtils.getMethod(stackTraceElement);
                        if (method.isAnnotationPresent(StoreLog.class)) {
                            annotation = method.getAnnotation(StoreLog.class);
                        }
                    }
                    
                  
                    //business logic to save the log

                    return FilterReply.ACCEPT;
                }catch (Exception ignored){
                    //no action needed
                }
            }
        }
        return FilterReply.ACCEPT;
    }

要找到一个注释方法:


import aj.org.objectweb.asm.Opcodes;
import org.objectweb.asm.*;


import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.concurrent.atomic.AtomicReference;

public class ReflectionUtils {

    private ReflectionUtils() {
    }

    public static Method getMethod(final StackTraceElement stackTraceElement) throws ClassNotFoundException, IOException, NoSuchMethodException, NoSuchLineException {
        final String stackTraceClassName = stackTraceElement.getClassName();
        final String stackTraceMethodName = stackTraceElement.getMethodName();
        final int stackTraceLineNumber = stackTraceElement.getLineNumber();
        Class<?> stackTraceClass = Class.forName(stackTraceClassName);
        final AtomicReference<String> methodDescriptorReference = new AtomicReference<>();
        InputStream classFileStream = stackTraceClass.getResourceAsStream(stackTraceClassName.split("\\.")[stackTraceClassName.split("\\.").length - 1] + ".class");
        if (classFileStream == null) {
            throw new ClassNotFoundException("Could not acquire the class file containing for the calling class");
        }
        try {
            ClassReader classReader = new ClassReader(classFileStream);
            classReader.accept(
                    new ClassVisitor(Opcodes.ASM5) {
                        @Override
                        public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
                            if (!name.equals(stackTraceMethodName)) {
                                return null;                              
                            }
                            return new MethodVisitor(Opcodes.ASM5) {
                                @Override
                                public void visitLineNumber(int line, Label start) {
                                    if (line == stackTraceLineNumber) {
                                        methodDescriptorReference.set(desc);
                                    }
                                }
                            };
                        }
                    },
                    0
            );
        } finally {
            classFileStream.close();
        }
        String methodDescriptor = methodDescriptorReference.get();
        if (methodDescriptor == null) {
            throw new NoSuchLineException("Could not find line " + stackTraceLineNumber);
        }
        for (Method method : stackTraceClass.getMethods()) {
            if (stackTraceMethodName.equals(method.getName()) && methodDescriptor.equals(Type.getMethodDescriptor(method))) {
                return method;
            }
        }
        throw new NoSuchMethodException("Could not find the calling method");
    }

}

logback.xml:


<configuration>
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <filter class="#{filter.path}"/>
        <encoder>
            <pattern>
                %-4relative [%thread] %-5level %logger - %msg%n
            </pattern>
        </encoder>
    </appender>
    <root>
        <appender-ref ref="STDOUT"/>
    </root>
</configuration>

In the end I used the logback filter to filter all logging events, then used the stacktrace from the ILoggingEent to find out whether an annotation is present in the stacktrace of the logging event.

Annotation:

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface StoreLog {

    //business logic hidden

}

Here's the implementation of the filter:

public class SaveLogFilter extends Filter<ILoggingEvent> {

    @Override
    public FilterReply decide(ILoggingEvent event) {
        if (event.getLevel() == Level.DEBUG) {
            return FilterReply.DENY;
        }
        StackTraceElement[] callerData = event.getCallerData();
        if (callerData != null && callerData.length > 0) {
            for (StackTraceElement stackTraceElement : callerData) {
                StoreLog annotation;
                try {
                    Class clazz = Class.forName(stackTraceElement.getClassName());
                    annotation = (StoreLog) clazz.getAnnotation(StoreLog.class);
                    if (annotation == null) {                      
                        Method method = ReflectionUtils.getMethod(stackTraceElement);
                        if (method.isAnnotationPresent(StoreLog.class)) {
                            annotation = method.getAnnotation(StoreLog.class);
                        }
                    }
                    
                  
                    //business logic to save the log

                    return FilterReply.ACCEPT;
                }catch (Exception ignored){
                    //no action needed
                }
            }
        }
        return FilterReply.ACCEPT;
    }

To find an annotated method:


import aj.org.objectweb.asm.Opcodes;
import org.objectweb.asm.*;


import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.concurrent.atomic.AtomicReference;

public class ReflectionUtils {

    private ReflectionUtils() {
    }

    public static Method getMethod(final StackTraceElement stackTraceElement) throws ClassNotFoundException, IOException, NoSuchMethodException, NoSuchLineException {
        final String stackTraceClassName = stackTraceElement.getClassName();
        final String stackTraceMethodName = stackTraceElement.getMethodName();
        final int stackTraceLineNumber = stackTraceElement.getLineNumber();
        Class<?> stackTraceClass = Class.forName(stackTraceClassName);
        final AtomicReference<String> methodDescriptorReference = new AtomicReference<>();
        InputStream classFileStream = stackTraceClass.getResourceAsStream(stackTraceClassName.split("\\.")[stackTraceClassName.split("\\.").length - 1] + ".class");
        if (classFileStream == null) {
            throw new ClassNotFoundException("Could not acquire the class file containing for the calling class");
        }
        try {
            ClassReader classReader = new ClassReader(classFileStream);
            classReader.accept(
                    new ClassVisitor(Opcodes.ASM5) {
                        @Override
                        public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
                            if (!name.equals(stackTraceMethodName)) {
                                return null;                              
                            }
                            return new MethodVisitor(Opcodes.ASM5) {
                                @Override
                                public void visitLineNumber(int line, Label start) {
                                    if (line == stackTraceLineNumber) {
                                        methodDescriptorReference.set(desc);
                                    }
                                }
                            };
                        }
                    },
                    0
            );
        } finally {
            classFileStream.close();
        }
        String methodDescriptor = methodDescriptorReference.get();
        if (methodDescriptor == null) {
            throw new NoSuchLineException("Could not find line " + stackTraceLineNumber);
        }
        for (Method method : stackTraceClass.getMethods()) {
            if (stackTraceMethodName.equals(method.getName()) && methodDescriptor.equals(Type.getMethodDescriptor(method))) {
                return method;
            }
        }
        throw new NoSuchMethodException("Could not find the calling method");
    }

}

Logback.xml:


<configuration>
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <filter class="#{filter.path}"/>
        <encoder>
            <pattern>
                %-4relative [%thread] %-5level %logger - %msg%n
            </pattern>
        </encoder>
    </appender>
    <root>
        <appender-ref ref="STDOUT"/>
    </root>
</configuration>

青衫负雪 2025-01-30 12:55:19

您可以从 lombok )。它可以帮助您定义一个默认的日志实例,您可以在非常注释的类中使用。

编辑:您也可以使用 interceptor

但是,如果您仍然想要使用反射使用您的自定义注释,总是可能的。

@Slf4j
public class MyClass {

    public void myMethod() {
        log.error("Something else is wrong here");
    }
}

You can use Slf4j annotation from lombok. It helps you define a default log instance that you can use in very annotated classes.

Edit: You can also use an interceptor

But if you still want to use reflection with your custom annotation, it is always possible.

@Slf4j
public class MyClass {

    public void myMethod() {
        log.error("Something else is wrong here");
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文