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