作者:安小辰 | 来源:互联网 | 2023-09-11 18:22
1、Spring扩展点BeanFactoryPostProcessor使用技巧方法voidpostProcessBeanFactory(ConfigurableListable
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)
方法
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 &#61; new PathMatchingResourcePatternResolver(); private static final CachingMetadataReaderFactory READER_FACTORY &#61; new CachingMetadataReaderFactory(); static final String DEFAULT_RESOURCE_PATTERN &#61; "**/*.class"; public static void main(String[] args) throws IOException { System.out.println(doScan("com.rookie.mybatis.study")); } private static List doScan(String basePackage) throws IOException { basePackage &#61; ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX &#43; resolveBasePackage(basePackage) &#43; &#39;/&#39; &#43; DEFAULT_RESOURCE_PATTERN; List result &#61; new ArrayList<>();// 当前会扫描该类下所有的类文件 Resource[] resources &#61; PATTERN_RESOLVER.getResources(basePackage); for (Resource resource : resources) { MetadataReader metadataReader &#61; READER_FACTORY.getMetadataReader(resource); ScannedGenericBeanDefinition sbd &#61; 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 容器当中&#xff0c;以上代码参考于 Mybatis 注册 Bean 的方式。
1.1.2、AnnotatedGenericBeanDefinition
这种方式就很直接了。直接 new 一个对象将需要的 Bean 的 class 放进去。
AnnotatedGenericBeanDefinition abd &#61; new AnnotatedGenericBeanDefinition(Test.class);
1.1.3、RootBeanDefinition
这个实现类和上面很类似&#xff0c;只不过多了几个构造方法&#xff1a;
RootBeanDefinition rootBeanDefinition &#61; new RootBeanDefinition(Test.class);
public RootBeanDefinition(String beanClassName);
最主要的还是以下的构造器&#xff1a;
public RootBeanDefinition(&#64;Nullable Class> beanClass, &#64;Nullable ConstructorArgumentValues cargs,&#64;Nullable MutablePropertyValues pvs);
这个的话多了几个参数&#xff0c;ConstructorArgumentValues&#xff0c;看名字就大概可以猜的出是传构造参数的。当我们需要创建的 Bean 是有参构造器时&#xff0c;我们就可以使用当前方法将构造参数传递进去。
ConstructorArgumentValues constructorArgumentValues &#61; new ConstructorArgumentValues();// 添加构造参数 constructorArgumentValues.addGenericArgumentValue(111);
这个添加的顺序就代表了构造器参数的顺序。
第二个对象我们可以通过它去修改类属性的值。
// 修改类属性的值MutablePropertyValues mutablePropertyValues &#61; new MutablePropertyValues();mutablePropertyValues.addPropertyValue("age",555);
当然我们也可以通过其他工具类去创建&#xff1a;
BeanDefinitionBuilder beanDefinitionBuilder &#61; BeanDefinitionBuilder.rootBeanDefinition(TestBean.class);beanDefinitionBuilder.addConstructorArgValue(1);registry.registerBeanDefinition("testBean",beanDefinitionBuilder.getBeanDefinition());
一般我们创建 Bean 的时候都喜欢去读 yml 的配置文件&#xff0c;但是在当前对象中&#xff0c;直接使用注入的方式是获取不到配置文件的&#xff1a;
&#64;Value("${test.case}")private String name; &#64;Autowiredprivate Environment environment;
这时候我们可以配合另外一个扩展点去获取环境变量。因为在当前扩展点执行的之后&#xff0c;Environment 是已经创建了放置进了 IOC 容器当中&#xff0c;我们需要通过下面的方式去获取&#xff1a;
&#64;Componentpublic class Test implements BeanDefinitionRegistryPostProcessor, ApplicationContextAware { &#64;Override public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException { } &#64;Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { } &#64;Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { Environment environment &#61; applicationContext.getEnvironment(); String xx &#61; environment.getProperty("xx"); }}