当前位置: 首页 > 知识库问答 >
问题:

springboot中带aop的bytebuddy不起作用

崔绍辉
2023-03-14

我尝试使用bytebuddy在springboot中实现aop。代码如下:

package klordy.learning.annotation;
@Target(METHOD)
@Retention(RUNTIME)
@Documented
public @interface CostTime {
}
package klordy.learning.agent;
public class Agent {
private static Agent instance = new Agent();
    private Logger logger = LoggerFactory.getLogger(Agent.class);
    private Agent() {}
    public static Agent getInstance(){ return instance; }
    public void install() {
        ByteBuddyAgent.install();
        AgentBuilder.Listener listener = new AgentBuilder.Listener() {
            // do nothing
            ...
        };

        new AgentBuilder.Default()
                .type(ElementMatchers.nameStartsWith("klordy.learning"))
                .transform((builder, typeDescription, classLoader, module) ->
                        builder.visit(Advice.to(TimeAdvice.class).on(ElementMatchers.isAnnotatedWith(named("klordy.learning.annotation.CostTime")))))
                .with(listener)
                // *** added as supposed, but still seems not work.
                .with(AgentBuilder.RedefinitionStrategy.RETRANSFORMATION)
                .installOnByteBuddyAgent();
         logger.info("byte buddy modification done.");
     }
}
public class TimeAdvice {
    @Advice.OnMethodEnter
    static long enter(@Advice.AllArguments Object args[], @Advice.Origin Method method){
        return System.currentTimeMillis();
    }

    @Advice.OnMethodExit
    static void exit(@Advice.Enter long startTime,
                     @Advice.Return(typing = Assigner.Typing.DYNAMIC) Object result,
                     @Advice.Origin Method method,
                     @Advice.Thrown Throwable throwable){
        if(throwable != null){
            System.out.println("error func " + System.currentTimeMillis());
        }else {
            System.out.println("func takes " + (System.currentTimeMillis() - startTime));
        }
    }
}

springboot的监听器如下:

public class AppEnvListener implements ApplicationListener<ApplicationEnvironmentPreparedEvent> {
    private Logger logger = LoggerFactory.getLogger(AppEnvListener.class);
    @Override
    public void onApplicationEvent(ApplicationEnvironmentPreparedEvent applicationEnvironmentPreparedEvent) {
        Agent.getInstance().install();
        logger.info("finished byte buddy installation.");
    }
}

最后,在springboot启动中注册侦听器:

@SpringBootApplication
@ComponentScan(basePackages = "klordy.learning")
public class SpringBootDemoApplication {

    public static void main(String[] args) {
       SpringApplication application = new SpringApplication(SpringBootDemoApplication.class);
       // register listener
       application.addListeners(new AppEnvListener());
       application.run(args);
    }
}

当我启动应用程序时,调试记录器显示良好。然而,当请求被处理时,aop不起作用。我做错了什么?我很困惑。。。

共有2个答案

姚棋
2023-03-14

您所讨论的类可能已经加载。

设置。在代理配置中使用(RetransformationStrategy.RETRANSFORM),或者在main方法中加载Spring之前安装代理。

夏侯元忠
2023-03-14

好吧,我想我通过用Spring Boot重现你的情况找到了你的问题。不过,没有Spring也会发生。基本上你就碰到这个问题了。

因此,如果您将建议修改为@advice。在methodexit(onThrowable=Throwable.class)上,您应该很好。您还应该添加。disableClassFormatChanges()发送给您的代理,顺便说一句。它有助于避免重新传输以前加载的类时出现问题。JVM要求它们在结构上不被改变。

我怎么知道发生了什么?我启动了控制台登录ByteBuddy。之前我用过你的监听器,让它记录每一个动作,这样我就可以看到BB实际上被触发了。但是BB日志确实显示了由于错误使用@Advice而导致的异常。抛出(在通知注释中没有onThrowable=Throwable.class)。

public void install() {
  ByteBuddyAgent.install();
  new AgentBuilder.Default()
    .disableClassFormatChanges()
    .with(RETRANSFORMATION)
    .with(AgentBuilder.RedefinitionStrategy.Listener.StreamWriting.toSystemError())
    .with(AgentBuilder.Listener.StreamWriting.toSystemError().withTransformationsOnly())
    .with(AgentBuilder.InstallationListener.StreamWriting.toSystemError())
    .type(ElementMatchers.nameStartsWith("klordy.learning"))
    .transform((builder, typeDescription, classLoader, module) ->
      builder.visit(
        Advice
          .to(TimeAdvice.class)
          .on(isAnnotatedWith(named("klordy.learning.annotation.CostTime")))
      )
    )
    .installOnByteBuddyAgent();
  logger.info("byte buddy modification done.");
}
 类似资料:
  • 我使用Spring AOP来实现我的应用程序的日志系统。但我有一些麻烦。 我有简单的课

  • 自定义注释 自定义注释处理程序 超级类 子类 Subclass调用SuperClass方法但在不调用 当我将移动到子类method时,AspectHandler可以获取 如何在超类保护方法中使用自定义注释? 更改 但还是不行 所以我把我的< code >子DAO改成了under code 这不是完美的解决方案,但它的工作原理 情况1:从子类方法调用超类方法不起作用 情况 2:使超级类实例和从实例调

  • 我对Spring Boot和AOP是新手,我花了三天时间试图让它工作,但没有效果。 我有一门课叫应用程序。该类调用一个名为invokeRetrieveMethod的方法--该方法调用autowired businessClass对象中的另一个方法。我只是试图记录运行使用自定义注释的方法所需的时间,但在运行代码时,我得到了一个空指针异常。请救命! 我的自定义注释

  • 问题内容: 我无法在注解中使用方法。也给。我想念什么?虽然效果很好。 我正在从数据库向用户分配权限。 问题答案: 你必须命名前缀你的权威来使用,看到Spring Security的参考 : HttpServletRequest.isUserInRole(String)将确定是否包含具有传递给的角色。通常,用户不应将“ ROLE_”前缀传递给此方法,因为它是自动添加的。例如,如果要确定当前用户是否具

  • 我有一个简单的Spring Boot应用程序,其中有一个jpa存储库对象,我希望它在类中自动生成,如下所示。 下面是类 我有以下例外。

  • 我的springboot版本是2.3.7。我知道spring boot starter验证不是spring boot starter web的可传递依赖项。但即使单独添加了它,我的注释也不起作用。 //下面的依赖我已经添加build.gradle编译'org.springframework.boot: spring-boot-starter-validation' //我希望在请求时出错的示例类