如何巧妙运用Spring扩展BeanFactoryPostProcessor实现高级配置?

2026-05-25 20:361阅读0评论SEO教程
  • 内容介绍
  • 文章标签
  • 相关推荐

本文共计1065个文字,预计阅读时间需要5分钟。

如何巧妙运用Spring扩展BeanFactoryPostProcessor实现高级配置?

目录+1、Spring 扩展点+BeanFactoryPostProcessor+使用技巧+1.1、BeanDefinitionRegistryPostProcessor+1.1.1、ScannedGenericBeanDefinition+1.1.2、AnnotatedGenericBeanDefinition+1.1.3、RootBeanDefinition+1.2、环境变量+Environment

目录
  • 1、Spring 扩展点 BeanFactoryPostProcessor 使用技巧
    • 1.1、BeanDefinitionRegistryPostProcessor
      • 1.1.1、ScannedGenericBeanDefinition
      • 1.1.2、AnnotatedGenericBeanDefinition
      • 1.1.3、RootBeanDefinition
    • 1.2、环境变量 Environment

    1、Spring 扩展点 BeanFactoryPostProcessor 使用技巧

    方法

    void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;

    其中提供一个 ConfigurableListableBeanFactory 回调对象,里面提供了很多框架内部使用的方法,建议的话使用它的实现类去注册 Bean 的信息。

    不建议使用里面的方法直接实例化对象,因为过早的创建对象会导致后续 Spring 一些对 Bean 修饰执行不到,生命周期不完整。

    1.1、BeanDefinitionRegistryPostProcessor

    BeanFactoryPostProcessor 的实现类。

    调用位置

    org.springframework.context.support.PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors(org.springframework.beans.factory.config.ConfigurableListableBeanFactory, java.util.List<org.springframework.beans.factory.config.BeanFactoryPostProcessor>)

    方法

    void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;

    一般来使用当前方法来注册 BeanDefinition。

    void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException;

    第一个参数填的是 Bean 的名称,第二个就是 Bean 的信息。一般可以使用以下方式去获取 BeanDefinition。

    1.1.1、ScannedGenericBeanDefinition

    public class Test { private static final PathMatchingResourcePatternResolver PATTERN_RESOLVER = new PathMatchingResourcePatternResolver(); private static final CachingMetadataReaderFactory READER_FACTORY = new CachingMetadataReaderFactory(); static final String DEFAULT_RESOURCE_PATTERN = "**/*.class"; public static void main(String[] args) throws IOException { System.out.println(doScan("com.rookie.mybatis.study")); } private static List<ScannedGenericBeanDefinition> doScan(String basePackage) throws IOException { basePackage = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + resolveBasePackage(basePackage) + '/' + DEFAULT_RESOURCE_PATTERN; List<ScannedGenericBeanDefinition> result = new ArrayList<>(); // 当前会扫描该类下所有的类文件 Resource[] resources = PATTERN_RESOLVER.getResources(basePackage); for (Resource resource : resources) { MetadataReader metadataReader = READER_FACTORY.getMetadataReader(resource); ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader); sbd.setSource(resource); result.add(sbd); } return result; } private static String resolveBasePackage(String basePackage) { return ClassUtils.convertClassNameToResourcePath(new StandardEnvironment().resolveRequiredPlaceholders(basePackage)); } }

    以上方式会将包下的所有类都扫描到然后添加到 Spring 容器当中,以上代码参考于 Mybatis 注册 Bean 的方式。

    1.1.2、AnnotatedGenericBeanDefinition

    这种方式就很直接了。直接 new 一个对象将需要的 Bean 的 class 放进去。

    AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(Test.class);

    1.1.3、RootBeanDefinition

    这个实现类和上面很类似,只不过多了几个构造方法:

    RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(Test.class);

    public RootBeanDefinition(String beanClassName);

    最主要的还是以下的构造器:

    如何巧妙运用Spring扩展BeanFactoryPostProcessor实现高级配置?

    public RootBeanDefinition(@Nullable Class<?> beanClass, @Nullable ConstructorArgumentValues cargs,@Nullable MutablePropertyValues pvs);

    这个的话多了几个参数,ConstructorArgumentValues,看名字就大概可以猜的出是传构造参数的。当我们需要创建的 Bean 是有参构造器时,我们就可以使用当前方法将构造参数传递进去。

    ConstructorArgumentValues constructorArgumentValues = new ConstructorArgumentValues(); // 添加构造参数 constructorArgumentValues.addGenericArgumentValue(111);

    这个添加的顺序就代表了构造器参数的顺序。

    第二个对象我们可以通过它去修改类属性的值。

    // 修改类属性的值 MutablePropertyValues mutablePropertyValues = new MutablePropertyValues(); mutablePropertyValues.addPropertyValue("age",555);

    当然我们也可以通过其他工具类去创建:

    BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.rootBeanDefinition(TestBean.class); beanDefinitionBuilder.addConstructorArgValue(1);registry.registerBeanDefinition("testBean",beanDefinitionBuilder.getBeanDefinition());

    1.2、环境变量 Environment

    一般我们创建 Bean 的时候都喜欢去读 yml 的配置文件,但是在当前对象中,直接使用注入的方式是获取不到配置文件的:

    @Value("${test.case}") private String name; @Autowired private Environment environment;

    这时候我们可以配合另外一个扩展点去获取环境变量。因为在当前扩展点执行的之后,Environment 是已经创建了放置进了 IOC 容器当中,我们需要通过下面的方式去获取:

    @Component public class Test implements BeanDefinitionRegistryPostProcessor, ApplicationContextAware { @Override public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException { } @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { } @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { Environment environment = applicationContext.getEnvironment(); String xx = environment.getProperty("xx"); } }

    以上就是Spring扩展BeanFactoryPostProcessor使用技巧详解的详细内容,更多关于Spring扩展BeanFactoryPostProcessor的资料请关注自由互联其它相关文章!

    本文共计1065个文字,预计阅读时间需要5分钟。

    如何巧妙运用Spring扩展BeanFactoryPostProcessor实现高级配置?

    目录+1、Spring 扩展点+BeanFactoryPostProcessor+使用技巧+1.1、BeanDefinitionRegistryPostProcessor+1.1.1、ScannedGenericBeanDefinition+1.1.2、AnnotatedGenericBeanDefinition+1.1.3、RootBeanDefinition+1.2、环境变量+Environment

    目录
    • 1、Spring 扩展点 BeanFactoryPostProcessor 使用技巧
      • 1.1、BeanDefinitionRegistryPostProcessor
        • 1.1.1、ScannedGenericBeanDefinition
        • 1.1.2、AnnotatedGenericBeanDefinition
        • 1.1.3、RootBeanDefinition
      • 1.2、环境变量 Environment

      1、Spring 扩展点 BeanFactoryPostProcessor 使用技巧

      方法

      void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;

      其中提供一个 ConfigurableListableBeanFactory 回调对象,里面提供了很多框架内部使用的方法,建议的话使用它的实现类去注册 Bean 的信息。

      不建议使用里面的方法直接实例化对象,因为过早的创建对象会导致后续 Spring 一些对 Bean 修饰执行不到,生命周期不完整。

      1.1、BeanDefinitionRegistryPostProcessor

      BeanFactoryPostProcessor 的实现类。

      调用位置

      org.springframework.context.support.PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors(org.springframework.beans.factory.config.ConfigurableListableBeanFactory, java.util.List<org.springframework.beans.factory.config.BeanFactoryPostProcessor>)

      方法

      void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;

      一般来使用当前方法来注册 BeanDefinition。

      void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException;

      第一个参数填的是 Bean 的名称,第二个就是 Bean 的信息。一般可以使用以下方式去获取 BeanDefinition。

      1.1.1、ScannedGenericBeanDefinition

      public class Test { private static final PathMatchingResourcePatternResolver PATTERN_RESOLVER = new PathMatchingResourcePatternResolver(); private static final CachingMetadataReaderFactory READER_FACTORY = new CachingMetadataReaderFactory(); static final String DEFAULT_RESOURCE_PATTERN = "**/*.class"; public static void main(String[] args) throws IOException { System.out.println(doScan("com.rookie.mybatis.study")); } private static List<ScannedGenericBeanDefinition> doScan(String basePackage) throws IOException { basePackage = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + resolveBasePackage(basePackage) + '/' + DEFAULT_RESOURCE_PATTERN; List<ScannedGenericBeanDefinition> result = new ArrayList<>(); // 当前会扫描该类下所有的类文件 Resource[] resources = PATTERN_RESOLVER.getResources(basePackage); for (Resource resource : resources) { MetadataReader metadataReader = READER_FACTORY.getMetadataReader(resource); ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader); sbd.setSource(resource); result.add(sbd); } return result; } private static String resolveBasePackage(String basePackage) { return ClassUtils.convertClassNameToResourcePath(new StandardEnvironment().resolveRequiredPlaceholders(basePackage)); } }

      以上方式会将包下的所有类都扫描到然后添加到 Spring 容器当中,以上代码参考于 Mybatis 注册 Bean 的方式。

      1.1.2、AnnotatedGenericBeanDefinition

      这种方式就很直接了。直接 new 一个对象将需要的 Bean 的 class 放进去。

      AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(Test.class);

      1.1.3、RootBeanDefinition

      这个实现类和上面很类似,只不过多了几个构造方法:

      RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(Test.class);

      public RootBeanDefinition(String beanClassName);

      最主要的还是以下的构造器:

      如何巧妙运用Spring扩展BeanFactoryPostProcessor实现高级配置?

      public RootBeanDefinition(@Nullable Class<?> beanClass, @Nullable ConstructorArgumentValues cargs,@Nullable MutablePropertyValues pvs);

      这个的话多了几个参数,ConstructorArgumentValues,看名字就大概可以猜的出是传构造参数的。当我们需要创建的 Bean 是有参构造器时,我们就可以使用当前方法将构造参数传递进去。

      ConstructorArgumentValues constructorArgumentValues = new ConstructorArgumentValues(); // 添加构造参数 constructorArgumentValues.addGenericArgumentValue(111);

      这个添加的顺序就代表了构造器参数的顺序。

      第二个对象我们可以通过它去修改类属性的值。

      // 修改类属性的值 MutablePropertyValues mutablePropertyValues = new MutablePropertyValues(); mutablePropertyValues.addPropertyValue("age",555);

      当然我们也可以通过其他工具类去创建:

      BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.rootBeanDefinition(TestBean.class); beanDefinitionBuilder.addConstructorArgValue(1);registry.registerBeanDefinition("testBean",beanDefinitionBuilder.getBeanDefinition());

      1.2、环境变量 Environment

      一般我们创建 Bean 的时候都喜欢去读 yml 的配置文件,但是在当前对象中,直接使用注入的方式是获取不到配置文件的:

      @Value("${test.case}") private String name; @Autowired private Environment environment;

      这时候我们可以配合另外一个扩展点去获取环境变量。因为在当前扩展点执行的之后,Environment 是已经创建了放置进了 IOC 容器当中,我们需要通过下面的方式去获取:

      @Component public class Test implements BeanDefinitionRegistryPostProcessor, ApplicationContextAware { @Override public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException { } @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { } @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { Environment environment = applicationContext.getEnvironment(); String xx = environment.getProperty("xx"); } }

      以上就是Spring扩展BeanFactoryPostProcessor使用技巧详解的详细内容,更多关于Spring扩展BeanFactoryPostProcessor的资料请关注自由互联其它相关文章!