Spring 容器相关知识

一、Spring InitializingBean

Spring 为Bean提供了两种初始化方式:

1.通过实现InitializingBean 接口后实现afterPropertiesSet方法,在其中指定初始化业务逻辑。
2.通过在配置中指定init-method实现bean的初始化方法 。

afterPropertiesSet方法与init-method调用的先后顺序

1.如果afterPropertiesSet方法和init-method同时存在,先调用afterPropertiesSet方法,后调用init-method。如果调用afterPropertiesSet方法出错,则不会调用init-method。

通过AbstractAutowireCapableBeanFactory中的invokeInitMethods方法可以看出两者的调用顺序:

protected void invokeInitMethods(String beanName, final Object bean, RootBeanDefinition mbd)
        throws Throwable {

    boolean isInitializingBean = (bean instanceof InitializingBean);
    if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
        if (logger.isDebugEnabled()) {
            logger.debug("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
        }
        if (System.getSecurityManager() != null) {
            try {
                AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
                    @Override
                   //调用afterPropertiesSet方法
                    public Object run() throws Exception {
                        ((InitializingBean) bean).afterPropertiesSet();
                        return null;
                    }
                }, getAccessControlContext());
            }
            catch (PrivilegedActionException pae) {
                throw pae.getException();
            }
        }
        else {
            ((InitializingBean) bean).afterPropertiesSet();
        }
    }
    //调用init-method方法
    if (mbd != null) {
        String initMethodName = mbd.getInitMethodName();
        if (initMethodName != null && !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
                !mbd.isExternallyManagedInitMethod(initMethodName)) {
            invokeCustomInitMethod(beanName, bean, mbd);
        }
    }
}

2.afterPropertiesSet方法是直接调用,比通过反射调用的init-method效率要高,但是init-method消除了对Spring的依赖。

二、Spring BeanFactoryPostProcessor | BeanPostProcessor

1.BeanPostProcessor : Bean的后置处理器的postProcessorBeforeInitailization方法是在bean实例化,依赖注入之后及自定义初始化方法(例如:配置文件中bean标签添加init-method属性指定Java类中初始化方法、@PostConstruct注解指定初始化方法,Java类实现InitailztingBean接口)之前调用。

2.后置处理器的postProcessorAfterInitailization方法是在bean实例化、依赖注入及自定义初始化方法之后调用。实现对Bean的再加工,属性修改和生成代理。

3.BeanPostProcessor 与 InitializingBean和DisposableBean的区别:
BeanPostProcessor将对所有的Bean起作用,即所有的bean初始化前后都会回调BeanPostProcessor实现类,InitializingBean 和 DisposableBean 针对单个bean,即只有在对应的bean实现了InitializingBean或DisposableBean接口才会对其进行回调。

三、BeanDefinitionRegistryPostProcessor

1.通过postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) 可以让我们实现自定义的注册bean定义的逻辑。

 public class CustomBeanDefinitionRegistry implements BeanDefinitionRegistryPostProcessor {

    @Override
     public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {

    }

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
          RootBeanDefinition helloBean = new RootBeanDefinition(Hello.class);
    //新增Bean定义
          registry.registerBeanDefinition("hello", helloBean);
    }
}

2.与ClassPathScanningCandidateComponentProvider配合使用,根据一定的规则扫描类路径下满足特定条件的Class来作为候选的bean定义。

列:扫描指定包及其子包下面的所有非接口和非抽象类

@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
     boolean useDefaultFilters = false;//是否使用默认的filter,使用默认的filter意味着只扫描那些类上拥有Component、Service、Repository或Controller注解的类。
     String basePackage = "com.elim.learn.spring.bean";
     ClassPathScanningCandidateComponentProvider beanScanner = new ClassPathScanningCandidateComponentProvider(useDefaultFilters);
     TypeFilter includeFilter = new TypeFilter() {
            @Override
            public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
            throws IOException {
                  return metadataReader.getClassMetadata().isConcrete();
            }   
    };
 
    beanScanner.addIncludeFilter(includeFilter);
    Set<BeanDefinition> beanDefinitions = beanScanner.findCandidateComponents(basePackage);
    for (BeanDefinition beanDefinition : beanDefinitions) {
    //beanName通常由对应的BeanNameGenerator来生成,比如Spring自带的AnnotationBeanNameGenerator、DefaultBeanNameGenerator等,也可以自己实现。
         String beanName = beanDefinition.getBeanClassName();
         registry.registerBeanDefinition(beanName, beanDefinition);
    }
 }

补充:

  • InitializingBean 和 DisposableBean 只针对单个的Bean
  • BeanPostProcessor: Bean的后置处理器,处理对象是Bean
  • BeanFactoryPostProcessor : BeanFactory的后置处理器,处理对象是BeanFactory
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • 文章作者:Tyan博客:noahsnail.com | CSDN | 简书 3.6 Customizing the...
    SnailTyan阅读 4,371评论 0 3
  • Spring容器高层视图 Spring 启动时读取应用程序提供的Bean配置信息,并在Spring容器中生成一份相...
    Theriseof阅读 7,855评论 1 24
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 136,264评论 19 139
  • 注意LifecycleProcessor接口继承了Lifcycle接口。同时,增加了2个方法,用于处理容器的ref...
    google666s阅读 4,799评论 0 51
  • 丹尼尔惠灵顿的新品米兰钢带款,相比于经典的尼龙表带,细腻的钢带不仅更耐腐蚀,而且更具优雅时髦感。 编织细腻的金属表...
    常浅阅读 1,675评论 0 0

友情链接更多精彩内容