在spring中使用bytebuddy 对bean做Aop拦截

文章介绍了如何在Spring框架中使用ByteBuddy库实现对特定Bean的`UserService`方法进行AOP拦截,以在方法执行前后添加自定义操作。作者展示了如何创建一个BeanDefinitionRegistryPostProcessor来替换或增强原有方法,并使用LoggerAdvisor进行日志记录。
摘要由CSDN通过智能技术生成

背景

拦截spring 中的某个bean拦截其方法的调用。在其前后做一些类似于aop的操作

拦截bean

  • MyBeanDefinitionRegistryPostProcessor
import lombok.extern.slf4j.Slf4j;
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.asm.Advice;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;

import static net.bytebuddy.matcher.ElementMatchers.named;
import static net.bytebuddy.matcher.ElementMatchers.returns;

/**
 * @author wxl
 */
@Slf4j
public class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        boolean userService = registry.containsBeanDefinition("userService");
        if (userService) {
            registry.removeBeanDefinition("userService");
            Class<? extends UserService> method02 = new ByteBuddy()
                    .subclass(UserService.class)
                    .method(named("method02").and(returns(String.class)))
                    .intercept(Advice.to(LoggerAdvisor.class))
                    .make()
                    .load(getClass().getClassLoader())
                    .getLoaded();
            BeanDefinition beanDefinitions = BeanDefinitionBuilder.rootBeanDefinition(method02).getBeanDefinition();
            beanDefinitions.setAutowireCandidate(true);
            registry.registerBeanDefinition("userService", beanDefinitions);
        }
    }

}
  • LoggerAdvisor
import lombok.extern.slf4j.Slf4j;
import net.bytebuddy.asm.Advice;

import java.lang.reflect.Method;
import java.util.Arrays;

/**
 * @author wxl
 */
@Slf4j
public class LoggerAdvisor {

    @Advice.OnMethodEnter
    public static void onMethodEnter(@Advice.Origin Method method, @Advice.AllArguments Object[] arguments) {
        System.out.println("Enter " + method.getName() + " with arguments: " + Arrays.toString(arguments));
    }

    @Advice.OnMethodExit
    public static void onMethodExit(@Advice.Origin Method method, @Advice.AllArguments Object[] arguments, @Advice.Return Object ret) {
        System.out.println("Exit " + method.getName() + " with arguments: " + Arrays.toString(arguments) + " return: " + ret);
    }
}
  • BeanB

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * @author wxl
 */
@Component
public class BeanB {
    @Autowired
    private UserService userService;

    public void test() {
        System.out.println("beanB");
        userService.method02("ss");
    }
}
  • 测试
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;

/**
 * @author wxl
 */
@Slf4j
@SpringBootApplication
public class SpringBytecodeDemoApplication {

    public static void main(String[] args) throws Exception {
//        ClassPool pool = ClassPool.getDefault();
//        CtClass cc = pool.get("cc.sofast.demo.springbytecodedemo.UserService");
//        cc.defrost();
//        CtMethod m = cc.getDeclaredMethod("say");
//        m.insertBefore("{ System.out.println(\"Hello.say():\"); }");
//        m.insertAfter("{ System.out.println(\"result: \"+$_); }");
//        cc.writeFile(".");
//        cc.toClass();
//        ByteBuddyAgent.install();
//
//        new ByteBuddy()
//                .redefine(UserService.class)
//                .method(named("method02").and(returns(String.class)))
//                .intercept(to(new OvUserService()))
//                .make()
//                .load(UserService.class.getClassLoader(), ClassReloadingStrategy.fromInstalledAgent());
        ConfigurableApplicationContext context = SpringApplication.run(SpringBytecodeDemoApplication.class, args);
        BeanB bean = context.getBean(BeanB.class);
        bean.test();
    }

    @Bean
    public MyBeanDefinitionRegistryPostProcessor myBeanDefinitionRegistryPostProcessor() {
        return new MyBeanDefinitionRegistryPostProcessor();
    }

}
  • build.gradle
    implementation 'org.javassist:javassist:3.30.2-GA'
    implementation 'net.bytebuddy:byte-buddy:1.14.14'
    implementation 'net.bytebuddy:byte-buddy-agent:1.14.14'
  • 总结
    • 可以拦截其中的任意方法。在其前后做一些事情
  • 8
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值