背景

拦截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'
  • 总结
    • 可以拦截其中的任意方法。在其前后做一些事情
Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐