BeanDefinitionRegistryPostProcessor spring官方解释是:允许在正常的BeanFactoryPostProcessor检测开始之前注册更多的自定义bean。特别是,BeanDefinitionRegistryPostProcessor可以注册更多的bean定义,然后定义BeanFactoryPostProcessor实例。也就是说可以借此方法实现自定义的bean。
BeanDefinitionRegistryPostProcessor继承了BeanBeanFactoryPostProcessor, 也就是说想实现自定义的bean 可以实现BeanDefinitionRegistryPostProcessor或者BeanBeanFactoryPostProcessor中的方法。通过springboot启动后发现这2个方法执行顺序有先后。
1、下面先看下通过BeanDefinitionRegistryPostProcessor实现简单的自定义bean:
@Configuration public class BeanConfiger implements BeanDefinitionRegistryPostProcessor,ApplicationContextAware{ private ApplicationContext applicationContext; private final static Logger LOGGER = LoggerFactory.getLogger(BeanConfiger.class); @Override public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException { LOGGER.info("postProcessBeanDefinitionRegistry执行!"); /*RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(UserDomain.class); rootBeanDefinition.setAutowireMode(RootBeanDefinition.AUTOWIRE_BY_TYPE); rootBeanDefinition.getPropertyValues().add("name","pepsi"); registry.registerBeanDefinition("userDomain",rootBeanDefinition);*/ //使用不同beanDefinition Class> cls = UserDomain.class; BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(cls); GenericBeanDefinition definition = (GenericBeanDefinition) builder.getRawBeanDefinition(); definition.setAutowireMode(GenericBeanDefinition.AUTOWIRE_BY_TYPE); definition.getPropertyValues().add("name","pepsi02"); // 注册bean名,一般为类名首字母小写 registry.registerBeanDefinition("userDomain", definition); } @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException { LOGGER.info("postProcessBeanFactory() 执行!"); } @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; } }
通过新建beanDefinition直接注册上去。通过autowire直接就可以获取。spring是不是非常强大!!!!我也是最近才渐渐明白为什么spring可以作为一个基础框架和其他框架无缝连接。其中mybatis等第三方集成到spring都是通过FactoryBean、BeanDefinitionRegistryPostProcessor、ClassPathBeanDefinitionScanner实现。我自己跟着mybatis的加载过程,自己理了一把如下:
2、使用自定义注解和factorybean实现接口注入:
a、先是通过BeanDefinitionRegistryPostProcessor 进行拦截
@Component public class AnnotationScannerConfigurer implements ApplicationContextAware, BeanDefinitionRegistryPostProcessor{ private ApplicationContext applicationContext; private Logger LOGGER = LoggerFactory.getLogger(AnnotationScannerConfigurer.class); @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; } @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { LOGGER.info("postProcessBeanFactory() beanDefinition的个数=====>"+beanFactory.getBeanDefinitionCount()); } @Override public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException { LOGGER.info("postProcessBeanDefinitionRegistry() beanDefinitionName=====>"+registry.getBeanDefinitionNames().toString()); // 需要被代理的接口 AnnotationScanner annotationScanner = new AnnotationScanner(registry); annotationScanner.setResourceLoader(applicationContext); // "com.pepsi.annotationproxy.service"是我 接口所在的包 annotationScanner.scan("com.pepsi.annotationproxy.service"); } }
b、扫描指定的路径,接口定义
public class AnnotationScanner extends ClassPathBeanDefinitionScanner{ public AnnotationScanner(BeanDefinitionRegistry registry) { super(registry); } @Override protected void registerDefaultFilters() { //扫描规则 // this.addIncludeFilter(new AnnotationTypeFilter(Refrence.class)); this.addIncludeFilter((metadataReader, metadataReaderFactory) -> true); } @Override protected SetdoScan(String... basePackages) { Set beanDefinitions = super.doScan(basePackages); for (BeanDefinitionHolder holder : beanDefinitions) { GenericBeanDefinition definition = (GenericBeanDefinition) holder.getBeanDefinition(); //BeanFactory.getBean的方法跟进去后有一个判断是不是FactroyBean类型的。如果是从FactroyBean.getObejct获取 //RefrenceAnnotationFactoryBean 实现了FactoryBean definition.setBeanClass(RefrenceAnnotationFactoryBean.class); this.getRegistry().registerBeanDefinition(holder.getBeanName(), definition); } return beanDefinitions; } @Override protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) { return beanDefinition.getMetadata().isInterface() && beanDefinition.getMetadata().isIndependent(); } }
c、通过FactoryBean实现接口代理
public class RefrenceAnnotationFactoryBean<T> implements FactoryBean<T> { public RefrenceAnnotationFactoryBean(){} @Override public T getObject() throws Exception { return (T) InterfaceProxy.newInstance(BizService.class); } @Override public Class> getObjectType() { return BizService.class; } @Override public boolean isSingleton() { return true; } }
public class InterfaceProxy implements InvocationHandler { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("ObjectProxy execute:" + method.getName()); String methodName = method.getName(); String param = Arrays.toString(args); return "pepsi is param="+param; } public static <T> T newInstance(Class<T> innerInterface) { ClassLoader classLoader = innerInterface.getClassLoader(); Class[] interfaces = new Class[] { innerInterface }; InterfaceProxy proxy = new InterfaceProxy(); return (T) Proxy.newProxyInstance(classLoader, interfaces, proxy); } }
以上3步,就实现了自定义注解的接口代理和注入。
测试如下:
@Refrence public interface BizService { String getName(String name); }
@Documented @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE}) public @interface Refrence { }
@RunWith(SpringRunner.class) @SpringBootTest public class AnnotationProxyApplicationTests { @Autowired private BizService bizService; @Test public void contextLoads() { bizService.getName("pepsi"); } }
整个自定义注解的接口代理和注入已完成。