Spring源码(七)reflush的prepareBeanFactory方法与postProcessBeanFactory方法

Spring源码(七)reflush的prepareBeanFactory方法与postProcessBeanFactory方法

前言

上文介绍了obtainBeanFactory方法,主要创建了BeanFactory,并解析了xml文件设置到bd中,而且将bd放入到bdMap与bdNames,但是并没有对BeanFactory属性赋值,所以prepareBeanFactory就是为beanFactory方法的属性进行赋值操作。

prepareBeanFactory方法

先看下代码

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
		// Tell the internal bean factory to use the context's class loader etc.
		beanFactory.setBeanClassLoader(getClassLoader());
		beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
		beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

		// Configure the bean factory with context callbacks.
		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 interface not registered as resolvable type in a plain factory.
		// MessageSource registered (and found for autowiring) as a bean.
		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));


		if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
			beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
			// Set a temporary ClassLoader for type matching.
			beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
		}

		if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
			beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
		}
		if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
			beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
		}
		if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
			beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
		}
	}

首先设置一下类加载器,然后用到了setBeanExpressionResolver,看下这个方法的参数。
在这里插入图片描述
这个就是我们用SPEL表达式了,内部细节我们就不看了,但是我们必须要知道,一开始需要一个bean表达式的处理类,在处理类内部有SPEL的解析类,在解析类有个当前解析类的配置类。
接下来看,添加了属性编辑注册器,addPropertyEditorRegistrar方法。这个也是扩展点,如果在一个对象中有省市区,我们需要自己定义编辑器,将省市区区分开来。
看下创建的ResourceEditorRegistrar,以及实现的类。

public class ResourceEditorRegistrar implements PropertyEditorRegistrar {

	private final PropertyResolver propertyResolver;

	private final ResourceLoader resourceLoader;

	public ResourceEditorRegistrar(ResourceLoader resourceLoader, PropertyResolver propertyResolver) {
		this.resourceLoader = resourceLoader;
		this.propertyResolver = propertyResolver;
	}
		@Override
	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));
		}
	}

构造方法只是加了个资源加载器以及属性解析器,我们看下实现的这个类PropertyEditorRegistar。

public interface PropertyEditorRegistrar {
	void registerCustomEditors(PropertyEditorRegistry registry);

}

这里有个方法,注册自定义编辑器registerCustomEditors,那么我们就能知道了,我们要实现自己的功能,那么就在这里做扩展了。
继续回到 ResourceEditorRegistrar这个类里,我们看到这里实现了方法。
这里我们只是添加了这个属性编辑注册器addPropertyEditorRegistrar,后面在填充属性实例化的时候,肯定会调用这个方法,完成属性的填充。史记载initBeanWrapper方法中会调用这个方法。

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

我们做一下扩展工作,看下怎么扩展的。

doRegisterEditor(registry, Resource.class, baseEditor);
		doRegisterEditor(registry, ContextResource.class, baseEditor);
		doRegisterEditor(registry, InputStream.class, new InputStreamEditor(baseEditor));
		doRegisterEditor(registry, InputSource.class, new InputSourceEditor(baseEditor));

这里我们看到传入了一个registry,一个转换的类,还有一个处理转换的类。
我们看下editor怎么实现的。

public class FileEditor extends PropertyEditorSupport {

这里继承了propertyEditorsSupport,再看下propertyEditorsSupport方法

public class PropertyEditorSupport implements PropertyEditor {
    private Object value;
    private Object source;
    private Vector<PropertyChangeListener> listeners;

    public PropertyEditorSupport() {
        this.setSource(this);
    }

    public PropertyEditorSupport(Object source) {
        if (source == null) {
            throw new NullPointerException();
        } else {
            this.setSource(source);
        }
    }

    public Object getSource() {
        return this.source;
    }

    public void setSource(Object source) {
        this.source = source;
    }

    public void setValue(Object value) {
        this.value = value;
        this.firePropertyChange();
    }

    public Object getValue() {
        return this.value;
    }

    public boolean isPaintable() {
        return false;
    }

    public void paintValue(Graphics gfx, Rectangle box) {
    }

    public String getJavaInitializationString() {
        return "???";
    }

    public String getAsText() {
        return this.value != null ? this.value.toString() : null;
    }

    public void setAsText(String text) throws IllegalArgumentException {
        if (this.value instanceof String) {
            this.setValue(text);
        } else {
            throw new IllegalArgumentException(text);
        }
    }

上面有个很关键的东西,setAsText,就是我们将东西进行转换的方法。
所以,总结一下:
1.自定义一个实现了propertyEditorSupport接口的编辑器。
2.让spring识别此编辑器。自定义实现一个属性编辑器的注册器,实现了propertyEditorRegistrar接口
3.让Spring感知注册器。实际上是再customEditorConfiger这个类把propertyEditorRegistrar放入Spring容器。这里我们怎么会调用这个customEditorConfiger方法呢,如果在这个方法上,可以看到实际实现了BeanFacoryPostProcessor,然后回有个方法遍历,如果propertyEditorRegistrar不为空,那么addPropertyEditorRegistrar到beanFactory里面去了。

下面我们测试一下,首先写一个adress类,然后用customer类将其包装起来,这个就省略了。然后我们写一个编辑器。

public class AddressPropertyEditor  extends PropertyEditorSupport {

    @Override
    public void setAsText(String text) throws IllegalArgumentException {
        String[] s = text.split("_");
        Address address = new Address();
        address.setProvince(s[0]);
        address.setCity(s[1]);
        address.setTown(s[2]);
        this.setValue(address);
    }
}

写一个注册器

public class AddressPropertyEditorRegistrar implements PropertyEditorRegistrar {

    @Override
    public void registerCustomEditors(PropertyEditorRegistry registry) {
        registry.registerCustomEditor(Address.class,new AddressPropertyEditor());
    }
}

这里写的方式都是仿照前面Spring源码写的。
然后我们需要把custom这个类,让Spring容器捕获到,所以定义一个xml的bean信息。

    <bean id="customer" class="com.mashibing.selfEditor.Customer">
        <property name="name" value="zhangsan"></property>
        <property name="address" value="江苏省_南京_鼓楼区"></property>
    </bean>

继续我们要想的问题是,怎么注册器让Spring感知呢,我们也需要加个bean信息。

<!--    <bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">-->
<!--        <property name="propertyEditorRegistrars">-->
<!--            <list>-->
<!--                <bean class="com.mashibing.selfEditor.AddressPropertyEditorRegistrar"></bean>-->
<!--            </list>-->
<!--        </property>-->
<!--    </bean>-->
    <bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
        <property name="customEditors">
            <map>
                <entry key="com.mashibing.selfEditor.Address">
                    <value>com.mashibing.selfEditor.AddressPropertyEditor</value>
                </entry>
            </map>
        </property>
    </bean>

这里有两种方式,都可以使用,一个是属性为propertyEditorRegistrars的数组。看下效果。
在这里插入图片描述
接下来继续往下,beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));添加beanpostprocessor后置处理器。这个new ApplicationContextAwareProcessor实际上是处理aware接口的方法,我们一般认为aware都是在invokeawareMethods里面实现的,但是实际上,这个方法只是实现了3个aware接口,其他的却不在这里,我们看下ApplicationContextAwareProcessor的实现类

	public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		if (!(bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
				bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
				bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)){
			return bean;
		}

在postProcessBeforeInitialization里面就有对其他aware接口的处理!
下面是忽略了aware接口,到后面统一调用,实际上在前面obtainfreshbeanfactory里,也有这些。
接下来到了

		beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
		beanFactory.registerResolvableDependency(ResourceLoader.class, this);
		beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
		beanFactory.registerResolvableDependency(ApplicationContext.class, this);

如果用@autowired匹配的类型有多个,那么这里可以处理,一般我们加@primary。

接下来:

		beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));

这个就是加入到一个多播器里面,以后再聊。
接下来:

if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
			beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
			// Set a temporary ClassLoader for type matching.
			beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
		}
		................................

此处是,aspectj提供了两种织入方式,第一种是通过特殊编译器,在编译器,将aspectj语言编写的切面类织入到java类中,第二种是类加载期织入,就是下面的load time weaving,此处在aop再聊。

接下来:

if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
			beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
		}
		if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
			beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
		}
		if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
			beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
		}

注册了三个属性值,把enviroment,SYSTEM_PROPERTIES,SYSTEM_ENVIRONMENT都放进我们工厂里面去就行了。这三个值在setconfigLocations的resovlepath中已经设置了。

总结

prepareBeanFactory是做一些准备工作,给beanFactory填充属性。这里主要设置了SPEL表达式、属性编辑器、增加了aware接口的beanPostProcessor、autowire的织入方式以及primary。

postProcessBeanFactory这个方法里面为空的,这里就是我们扩展实现的方法,比如我们自定义打印一行。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值