ApplicationContext系列四BeanFactory的功能扩展

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
        //设置beanFactory的ClassLoader为当前context的classloader
        beanFactory.setBeanClassLoader(this.getClassLoader());
        //设置beanFactory的表达式语言处理器,spring3开始支持
        //默认支持#{bean.xxx}来调用相关属性
        beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
        //对beanFactory增加一个默认的PropertyEditor,这个主要是对bean的属性等设置管理
        //的一个工具
        beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, this.getEnvironment()));
        //增加BeanPostProcessor
        beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
        //设置忽略自动装配的接口
        beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
        beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
        beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
        beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
        beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
        beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
        //设置自动装配的特殊规则
        beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
        beanFactory.registerResolvableDependency(ResourceLoader.class, this);
        beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
        beanFactory.registerResolvableDependency(ApplicationContext.class, this);
        beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
        
        //对AspectJ的支持
        if (beanFactory.containsBean("loadTimeWeaver")) {
            beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
            beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
        }
        //添加默认的系统环境
        if (!beanFactory.containsLocalBean("environment")) {
            beanFactory.registerSingleton("environment", this.getEnvironment());
        }

        if (!beanFactory.containsLocalBean("systemProperties")) {
            beanFactory.registerSingleton("systemProperties", this.getEnvironment().getSystemProperties());
        }

        if (!beanFactory.containsLocalBean("systemEnvironment")) {
            beanFactory.registerSingleton("systemEnvironment", this.getEnvironment().getSystemEnvironment());
        }

    }

一、扩展的功能

1、对SPEL的扩展

2、对属性编辑器的支持

3、设置可以忽略的自动装配的接口

4、注册一些固定依赖的属性

5、增加对AspectJ的支持

二、SPEL的扩展

举一个简单的例子

<bean id="user" name="user2" class="com.springboot2.test.User"/>
<alias name="user2" alias="user3"/>

<bean id="stu" class="com.springboot2.test.Stu">
    <property name="user" value="#{user}"></property>
</bean>

spring通过如下方法可以注册对SPEL的解析

beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));

spring在bean的进行初始化的时候会有属性填充的一步,而在这一步中会调用AbstractAutowireCapableBeanFactory类中的applyPropertyValues方法完成解析的。

在applyPropertyValues通过构造BeanDefinitionValueResolver对象,调用resolveValueIfNecessary方法,在这个方法里调用evaluate

protected Object evaluate(TypedStringValue value) {
   Object result = doEvaluate(value.getValue());
   if (!ObjectUtils.nullSafeEquals(result, value.getValue())) {
      value.setDynamic();
   }
   return result;
}
private Object doEvaluate(@Nullable String value) {
   return this.beanFactory.evaluateBeanDefinitionString(value, this.beanDefinition);
}
protected Object evaluateBeanDefinitionString(@Nullable String value, @Nullable BeanDefinition beanDefinition) {
   if (this.beanExpressionResolver == null) {
      return value;
   }

   Scope scope = null;
   if (beanDefinition != null) {
      String scopeName = beanDefinition.getScope();
      if (scopeName != null) {
         scope = getRegisteredScope(scopeName);
      }
   }
   //解析SPEL
   return this.beanExpressionResolver.evaluate(value, new BeanExpressionContext(this, scope));
}

应用语言解析器的调用主要是在解析依赖注入bean的时候,以及在完成bean的初始化和属性获取后进行属性填充的时候。

三、属性编辑器的支持

public class Stu {
    private Date date;

    public Date getDate() {
        return date;
    }

    public void setDate(Date date) {
        this.date = date;
    }
}
<bean id="stu" class="com.springboot2.test.Stu">
    <property name="date" value="2021-10-26"></property>
</bean>

当获取Stu的bean时,会报错,因为spring对子自定义类型转换失败而报错

spring会采用两种解决方式

1、使用自定义属性编辑器

public class DatePropertyEditor extends PropertyEditorSupport {

    private String format = "yyyy-MM-dd";
    public void setFormat(String format) {
        this.format = format;
    }
    @Override
    public void setAsText(String text) throws IllegalArgumentException {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(format);
        try {
            Date parse = simpleDateFormat.parse(text);
            this.setValue(parse);
        } catch (ParseException e) {
            e.printStackTrace();
        }
    }
}
<bean id="stu" class="com.springboot2.test.Stu">
    <property name="date" value="2021-10-26"></property>
</bean>

<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
    <property name="customEditors">
        <map>
            <entry key="java.util.Date" value="com.springboot2.test.DatePropertyEditor"/>
        </map>
    </property>
</bean>

2、注册spring自带的属性编辑器CustomDateEditor

public class DatePropertyEditorRegistrar implements PropertyEditorRegistrar {
    @Override
    public void registerCustomEditors(PropertyEditorRegistry registry) {
        registry.registerCustomEditor(Date.class,
                new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"),true));
    }
}
<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
    <property name="propertyEditorRegistrars">
        <list>
            <bean class="com.springboot2.test.DatePropertyEditorRegistrar"></bean>
        </list>
    </property>
</bean>

属性编辑器的源码解析

beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, this.getEnvironment()));

进入ResourceEditorRegistrar类中最核心方法为registerCustomEditors

public void registerCustomEditors(PropertyEditorRegistry registry) {
   ResourceEditor baseEditor = new ResourceEditor(this.resourceLoader, this.propertyResolver);
   doRegisterEditor(registry, Resource.class, baseEditor);
   doRegisterEditor(registry, ContextResource.class, baseEditor);
   doRegisterEditor(registry, InputStream.class, new InputStreamEditor(baseEditor));
   doRegisterEditor(registry, InputSource.class, new InputSourceEditor(baseEditor));
   doRegisterEditor(registry, File.class, new FileEditor(baseEditor));
   doRegisterEditor(registry, Path.class, new PathEditor(baseEditor));
   doRegisterEditor(registry, Reader.class, new ReaderEditor(baseEditor));
   doRegisterEditor(registry, URL.class, new URLEditor(baseEditor));

   ClassLoader classLoader = this.resourceLoader.getClassLoader();
   doRegisterEditor(registry, URI.class, new URIEditor(classLoader));
   doRegisterEditor(registry, Class.class, new ClassEditor(classLoader));
   doRegisterEditor(registry, Class[].class, new ClassArrayEditor(classLoader));

   if (this.resourceLoader instanceof ResourcePatternResolver) {
      doRegisterEditor(registry, Resource[].class,
            new ResourceArrayPropertyEditor((ResourcePatternResolver) this.resourceLoader, this.propertyResolver));
   }
}
private void doRegisterEditor(PropertyEditorRegistry registry, Class<?> requiredType, PropertyEditor editor) {
   if (registry instanceof PropertyEditorRegistrySupport) {
      ((PropertyEditorRegistrySupport) registry).overrideDefaultEditor(requiredType, editor);
   }
   else {
      //自定义属性编辑器
      registry.registerCustomEditor(requiredType, editor);
   }
}

可以看到registerCustomEditors方法核心逻辑是注册一些列常用的类型的属性编辑器

例如,

doRegisterEditor(registry, Class.class, new ClassEditor(classLoader));

注册后,一旦某个实体bean中存在一些Class类型的属性,那么spring会调用ClassEditor将配置中心定义的String类型转换为Class类型并进行赋值

注意,beanFactory.addPropertyEditorRegistrar只是注册ResourceEditorRegistrar,但是ResourceEditorRegistrar里的方法registerCustomEditors什么时候被调用?

beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, this.getEnvironment()));

经过排查,在AbstractBeanFactory的initBeanWrapper调用了registerCustomEditors

protected void initBeanWrapper(BeanWrapper bw) {
   bw.setConversionService(getConversionService());
   registerCustomEditors(bw);
}

initBeanWrapper是之前讨论过,在bean初始化时使用的方法,用于将BeanDefinition转换为BeanWrapper后对属性填充。

总结

在bean的初始化后调用ResourceEditorRegistrar的registerCustomEditors方法进行批量的通用属性编辑器注册,注册后,在属性填充的环节直接让spring使用这些编辑器对属性解析。

四、添加ApplicationContextAwareProcessor处理器

ApplicationContextAwareProcessor中最重要的方法postProcessBeforeInitialization

postProcessBeforeInitialization方法调用了invokeAwareInterfaces方法,对实现Aware接口的bean在被初始化后,可以取得一些对应的资源。

五、忽略依赖

beanFactory.ignoreDependencyInterface(EnvironmentAware.class);

使用ignoreDependencyInterface方法忽略的bean,在做bean的依赖注入的时候忽略。

六、注册依赖

beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);

注册了依赖后,当bean的属性注入时,一旦检测到属性为BeanFactory类型,便会将BeanFactory的实例注入进去。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值