Spring源码分析(二十二)功能扩展
摘要: 本文结合《Spring源码深度解析》来分析Spring 5.0.6版本的源代码。若有描述错误之处,欢迎指正。
目录
一、增加SPEL语言的支持
二、增加属性注册编辑器
1. 使用自定义属性编辑器
2. 注册Spring自带的属性编辑器CustomDateEditor
3. 添加 ApplicationContextAwareProcessor 处理器
4. 设置忽略依赖
5. 注册依赖
在进入prepareBeanFactory前,Spring已经完成了对配置的解析,而ApplicationContext在功能上的扩展也由此展开。
- /**
- * Configure the factory's standard context characteristics,
- * such as the context's ClassLoader and post-processors.
- * @param beanFactory the BeanFactory to configure
- */
- protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
- // Tell the internal bean factory to use the context's class loader etc.
- // 设置beanFactory的classLoader为当前context的classLoader
- beanFactory.setBeanClassLoader(getClassLoader());
- // 设置beanFactory的表达式语言处理器,Spring3增加了表达式语言的支持,
- // 默认可以使用#{bean.xxx}的形式来调用相关属性值
- beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
- // 为beanFactory增加了一个默认的propertyEditor,这个主要是对bean的属性等设置管理的一个工具
- beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
- // Configure the bean factory with context callbacks.
- // 添加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 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);
- // Register early post-processor for detecting inner beans as ApplicationListeners.
- beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
- // Detect a LoadTimeWeaver and prepare for weaving, if found.
- // 增加对AspectJ的支持
- 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()));
- }
- // Register default environment beans.
- // 添加默认的系统环境bean
- 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());
- }
- }
上面函数中主要进行了几个方面的扩展。
- 增加对SPEL语言的支持。
- 增加对属性编辑器的支持。
- 增加对一些内置类,比如EnvironmentAvare、MessageSourceAware的信息注入。
- 设置了依赖功能可忽略的接口。
- 注册一些固定依赖的属性。
- 增加对AspectJ的支持。
- 将相关环境变量及属性注册以单例模式注册。
可能读者不是很理解每个步骤的具体含义,接下来我们会对各个步骤进行详细地分析。
一、 增加SPEL语言的支持
Spring 表达式语言全称为 “Spring Expression Language”,缩写为 “SpEL”,类似于Struts 2x 中使用的OGNL表达式语言,能在运行时构建复杂表达式、存取对象图属性、对象方法调用等, 并且能与Spring功能完美整合,比如能用 来配置bean定义。SpEL是单独模块,只依赖于core 模块,不依赖于其他模块,可以单独使用。
SpEL使用#{...}为定界符,所有在花括号中的字符都将被认为是SpEL,使用格式如下:
- <bean id = "saxophone" value = "com.xxx.xxx.Xxx"/>
- <bean >
- <property name="instrument" value="#{saxophone}"/>
- <bean/>
相当于:
- <bean id = "saxophone" value = "com.xxx.xxx.Xxx"/>
- <bean >
- <property name="instrument" ref="saxophone"/>
- <bean/>
当然,上面只是列举了其中最简单的使用方式,SPEL功能非常强大,使用好可以大大提高开发效率,这里只为唤起读者的记忆来帮助我们理解源码,有兴趣的读者可以进一步深入研究。
在源码中通过代码beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver())注册语言解析器,就可以对SPEL进行解析了,那么在注册解析器后 Spring 又是在什么时候调用这个解析器进行解析呢?
之前我们讲解过 Spring 在 bean 进行初始化的时候会有属性填充的一步,而在这一步中 Spring 会调用AbstractAutowireCapableBeanFactory类的 applyPropertyValues 函数来完成功能。就在这个函数中,会通过构造 BeanDefinitionValueResolver 类型实例 valueResolver 来进行属性值的解析。同时,也是在这个步骤中一般通过 AbstractBeanFactory中的 evaluateBeanDefinitionString 方法去完成 SPEL 的解析。
- /**
- * Evaluate the given String as contained in a bean definition,
- * potentially resolving it as an expression.
- * @param value the value to check
- * @param beanDefinition the bean definition that the value comes from
- * @return the resolved value
- * @see #setBeanExpressionResolver
- */
- @Nullable
- 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);
- }
- }
- return this.beanExpressionResolver.evaluate(value, new BeanExpressionContext(this, scope));
- }
当调用这个方法时会判断是否存在语言解析器,如果存在则调用语言解析器的方法进行解析,解析的过程是在Spring的expression的包内,这里不做过多解释。我们通过查看对evaluateBeanDefinitionString方法的调用层次可以看出,应用语言解析器的调用主要是在解析依赖注入bean的时候,以及在完成bean的初始化和属性获取后进行属性填充的时候。
二、增加属性注册编辑器
在Spring DI注入的时候可以把普通属性注入进来,但是像Date类型就无法被识别。例如:
- public class UserManager {
- private Date dateValue;
- public Date getDateValue() {
- return dateValue;
- }
- public void setDateValue(Date dateValue) {
- this.dateValue = dateValue;
- }
- @Override
- public String toString() {
- return "dataValue: " + dateValue;
- }
- }
上面代码中,需要对日期型属性进行注入:
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans.xsd">
- <bean id="userManager" class="org.cellphone.uc.UserManager">
- <property name="dateValue">
- <value>2018-07-29</value>
- </property>
- </bean>
- </beans>
测试代码:
- public static void main(String[] args) {
- ApplicationContext context = new ClassPathXmlApplicationContext("spring/beans-test.xml");
- UserManager manager = (UserManager) context.getBean("userManager");
- System.out.println(manager);
- }
如果直接这样使用,程序则会报异常,类型转换不成功。因为在UserManager中的dataValue属性是Date类型的,而在XML中配置的确实String类型的,所以当然会报异常。
Spring针对此问题提供了两种解决方法。
1. 使用自定义属性编辑器
使用自定义属性编辑器,通过继承PropertyEditorSupport,重写setAsText方法,具体步骤如下。
(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 {
- System.out.println("text: " + text);
- SimpleDateFormat sdf = new SimpleDateFormat(format);
- try {
- Date d = sdf.parse(text);
- this.setValue(d);
- } catch (ParseException e) {
- e.printStackTrace();
- }
- }
- }
(2)将自定义属性编辑器注册到Spring中。
- <bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
- <property name="customEditors">
- <map>
- <entry key="java.util.Date" value="org.cellphone.uc.DatePropertyEditor"/>
- </map>
- </property>
- </bean>
在配置文件中引入类型为org.springframework.beans.factory.config.CustomEditorConfigurer的bean,并在属性customEditors中加入自定义的属性编辑器,其中key为属性编辑器所对应的类型。通过这样的配置,当Spring在注入bean的属性时一旦遇到了java.util.Date类型的属性会自动调用自定义的DatePropertyEditor解析器进行解析,并用解析结果代替配置属性进行注入。
2. 注册Spring自带的属性编辑器CustomDateEditor
通过注册Spring自带的属性编辑器CustomDateEditor,具体步骤如下:
(1)定义属性编辑器。
- public class DatePropertyEditorRegistrar implements PropertyEditorRegistrar {
- @Override
- public void registerCustomEditors(PropertyEditorRegistry registry) {
- registry.registerCustomEditor(Date.class, new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd"), true));
- }
- }
(2)注册到Spring中。
- <bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
- <property name="propertyEditorRegistrars">
- <list>
- <bean class="org.cellphone.uc.DatePropertyEditorRegistrar"></bean>
- </list>
- </property>
- </bean>
通过在配置文件中将自定义的DatePropertyEditorRegistrar注册进入org.springframework.beans.factory.config.CustomEditorConfigurer 的 propertyEditorRegistrars 属性中,可以具有与方法 1 同样的效果。
我们了解了自定义属性编辑器的使用,但是,似乎这与本节中围绕的核心代码beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()))并无联系,因为在注册自定义属性编辑器的时候使用的是 ResourceEditorRegistrar的registerCustomEditors方法,而这里使用的是ConfigurableListableBeanFactory的addPropertyEditorRegistrar方法。我们不妨深入探索一下 ResourceEditorRegistrar 的内部实现,在 ResourceEditorRegistrar 中,我们最关心的方法是 registerCustomEditors 。
- /**
- * Populate the given {@code registry} with the following resource editors:
- * ResourceEditor, InputStreamEditor, InputSourceEditor, FileEditor, URLEditor,
- * URIEditor, ClassEditor, ClassArrayEditor.
- * <p>If this registrar has been configured with a {@link ResourcePatternResolver},
- * a ResourceArrayPropertyEditor will be registered as well.
- * @see org.springframework.core.io.ResourceEditor
- * @see org.springframework.beans.propertyeditors.InputStreamEditor
- * @see org.springframework.beans.propertyeditors.InputSourceEditor
- * @see org.springframework.beans.propertyeditors.FileEditor
- * @see org.springframework.beans.propertyeditors.URLEditor
- * @see org.springframework.beans.propertyeditors.URIEditor
- * @see org.springframework.beans.propertyeditors.ClassEditor
- * @see org.springframework.beans.propertyeditors.ClassArrayEditor
- * @see org.springframework.core.io.support.ResourceArrayPropertyEditor
- */
- @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));
- }
- }
- /**
- * Override default editor, if possible (since that's what we really mean to do here);
- * otherwise register as a custom editor.
- */
- private void doRegisterEditor(PropertyEditorRegistry registry, Class<?> requiredType, PropertyEditor editor) {
- if (registry instanceof PropertyEditorRegistrySupport) {
- ((PropertyEditorRegistrySupport) registry).overrideDefaultEditor(requiredType, editor);
- }
- else {
- registry.registerCustomEditor(requiredType, editor);
- }
- }
在doRegisterEditor函数中,可以看到在之前提到的自定义属性中使用的关键代码: registry.registerCustomEditor(requiredType, editor),回过头来看 ResourceEditorRegistrar 类的 registerCustomEditors方法的核心功能,其实无非是注册了一系列的常用类型的属性编辑器,例 如,代码 doRegisterEditor(registry,Class.class, new ClassEditor(classLoader))实现的功能就是注册 Class类对应的属件编辑器。那么,注册后,一旦某个实体bean中存在一些Class类型的属性, 那么Spring会调用ClassEditor将配置中定义的String类型转换为Class类型并进行陚值。
分析到这里,我们不禁有个疑问,虽说ResourceEditorRegistrar类的registerCustomEditors方法实现了批量注册的功能,但是beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment())仅仅是注册了 ResourceEditorRegistrar 实例,却并没有调用ResourceEditorRegistrar 的registerCustomEditors方法进行注册,那么到底是在什么时候进行注册的呢?进一步查看 ResourceEditorRegistrar 的 registerCustomEditors 方法的调用层次结构,如下图所示。
发现在AbstractBeanFactory中的registerCustomEditors方法中被调用过,继续查看AbstractBeanFactory中的registerCustomEditors方法的层次结构,如下图所示。
其中我们看到一个方法是我们熟悉的,就是AbstractBeanFactory类中的initBeanWrapper 方法,这是在bean初始化时使用的一个方法,之前巳经使用过大量的篇幅进行讲解,主要是在将BeanDefinition转换为BeanWrapper后用于对属件的填充。到此,逻辑已经明了,在bean的初始化后会调用ResourceEditorRegistrar的registerCustomEditors方法进行批量的通用属性编辑器注册。注册后,在属性填充的环节便可以直接让Spring使用这些编辑器进行属性的解析了。
既然提到了 BeanWrapper,这里也有必要强调下,Spring中用于封装bean的是BeanWrapper 类型,而它又间接继承了 PropertyEditorRegistry类型,也就是我们之前反复看到的方法参数 PropertyEditorRegistry registry,其实大部分情况下都是 BeanWrapper,对于 BeanWrapper 在 Spring 中的默认实现是 BeanWrapperlmpl,而 BeanWrapperlmpl 除了实现 BeanWrapper 接门外还继承了 PropertyEdhorRegistrySupport,在 PropertyEditorRegistrySupport 中有这样一个方法:
- /**
- * Actually register the default editors for this registry instance.
- */
- private void createDefaultEditors() {
- this.defaultEditors = new HashMap<>(64);
- // Simple editors, without parameterization capabilities.
- // The JDK does not contain a default editor for any of these target types.
- this.defaultEditors.put(Charset.class, new CharsetEditor());
- this.defaultEditors.put(Class.class, new ClassEditor());
- this.defaultEditors.put(Class[].class, new ClassArrayEditor());
- this.defaultEditors.put(Currency.class, new CurrencyEditor());
- this.defaultEditors.put(File.class, new FileEditor());
- this.defaultEditors.put(InputStream.class, new InputStreamEditor());
- this.defaultEditors.put(InputSource.class, new InputSourceEditor());
- this.defaultEditors.put(Locale.class, new LocaleEditor());
- this.defaultEditors.put(Path.class, new PathEditor());
- this.defaultEditors.put(Pattern.class, new PatternEditor());
- this.defaultEditors.put(Properties.class, new PropertiesEditor());
- this.defaultEditors.put(Reader.class, new ReaderEditor());
- this.defaultEditors.put(Resource[].class, new ResourceArrayPropertyEditor());
- this.defaultEditors.put(TimeZone.class, new TimeZoneEditor());
- this.defaultEditors.put(URI.class, new URIEditor());
- this.defaultEditors.put(URL.class, new URLEditor());
- this.defaultEditors.put(UUID.class, new UUIDEditor());
- this.defaultEditors.put(ZoneId.class, new ZoneIdEditor());
- // Default instances of collection editors.
- // Can be overridden by registering custom instances of those as custom editors.
- this.defaultEditors.put(Collection.class, new CustomCollectionEditor(Collection.class));
- this.defaultEditors.put(Set.class, new CustomCollectionEditor(Set.class));
- this.defaultEditors.put(SortedSet.class, new CustomCollectionEditor(SortedSet.class));
- this.defaultEditors.put(List.class, new CustomCollectionEditor(List.class));
- this.defaultEditors.put(SortedMap.class, new CustomMapEditor(SortedMap.class));
- // Default editors for primitive arrays.
- this.defaultEditors.put(byte[].class, new ByteArrayPropertyEditor());
- this.defaultEditors.put(char[].class, new CharArrayPropertyEditor());
- // The JDK does not contain a default editor for char!
- this.defaultEditors.put(char.class, new CharacterEditor(false));
- this.defaultEditors.put(Character.class, new CharacterEditor(true));
- // Spring's CustomBooleanEditor accepts more flag values than the JDK's default editor.
- this.defaultEditors.put(boolean.class, new CustomBooleanEditor(false));
- this.defaultEditors.put(Boolean.class, new CustomBooleanEditor(true));
- // The JDK does not contain default editors for number wrapper types!
- // Override JDK primitive number editors with our own CustomNumberEditor.
- this.defaultEditors.put(byte.class, new CustomNumberEditor(Byte.class, false));
- this.defaultEditors.put(Byte.class, new CustomNumberEditor(Byte.class, true));
- this.defaultEditors.put(short.class, new CustomNumberEditor(Short.class, false));
- this.defaultEditors.put(Short.class, new CustomNumberEditor(Short.class, true));
- this.defaultEditors.put(int.class, new CustomNumberEditor(Integer.class, false));
- this.defaultEditors.put(Integer.class, new CustomNumberEditor(Integer.class, true));
- this.defaultEditors.put(long.class, new CustomNumberEditor(Long.class, false));
- this.defaultEditors.put(Long.class, new CustomNumberEditor(Long.class, true));
- this.defaultEditors.put(float.class, new CustomNumberEditor(Float.class, false));
- this.defaultEditors.put(Float.class, new CustomNumberEditor(Float.class, true));
- this.defaultEditors.put(double.class, new CustomNumberEditor(Double.class, false));
- this.defaultEditors.put(Double.class, new CustomNumberEditor(Double.class, true));
- this.defaultEditors.put(BigDecimal.class, new CustomNumberEditor(BigDecimal.class, true));
- this.defaultEditors.put(BigInteger.class, new CustomNumberEditor(BigInteger.class, true));
- // Only register config value editors if explicitly requested.
- if (this.configValueEditorsActive) {
- StringArrayPropertyEditor sae = new StringArrayPropertyEditor();
- this.defaultEditors.put(String[].class, sae);
- this.defaultEditors.put(short[].class, sae);
- this.defaultEditors.put(int[].class, sae);
- this.defaultEditors.put(long[].class, sae);
- }
- }
具体的调用方法我们就不去深究了,但是至少通过这个方法我们已经知道了在Spring中定义了上面一系列常用的属性编辑器使我们可以方便地进行配置。如果我们定义的bean中的某个属性的类型不在上面的常用配置中的话,才需要我们进行个性化属性编辑器的注册。
3. 添加 ApplicationContextAwareProcessor 处理器
了解了属性编辑器的使用后,接下来我们继续通过AbstractApplicationContext的 prepareBeanFactory 方法的主线来进行函数跟踪。对于 beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this))其实主要目的就是注册个 BneaPostProcessor,而真正的逻辑还是在 ApplicationContextAwareProcessor 中。
ApplicationContextAwareProcessor 实现 BeanPostProcessor 接口,我们回顾下之前讲过的内容,在bean实例化的时候,也就是Spring激活bean的init-method的前后,会调用BeanPostProcessor 的 postProcessBeforelnitialization 方法和 postProcessAfterlnitialization 方法。问样,对于ApplicationContextAwareProcessor我们也关心这两个方法。
对于postProcessAfterlnitialization 方法,在ApplicationContextAwareProcessor 中并没有做过多逻辑处理。
- @Override
- public Object postProcessAfterInitialization(Object bean, String beanName) {
- return bean;
- }
那么,我们重点看一下postProcessBeforelnitialization 方法。
- @Override
- @Nullable
- public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException {
- AccessControlContext acc = null;
- if (System.getSecurityManager() != null &&
- (bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
- bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
- bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)) {
- acc = this.applicationContext.getBeanFactory().getAccessControlContext();
- }
- if (acc != null) {
- AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
- invokeAwareInterfaces(bean);
- return null;
- }, acc);
- }
- else {
- invokeAwareInterfaces(bean);
- }
- return bean;
- }
- private void invokeAwareInterfaces(Object bean) {
- if (bean instanceof Aware) {
- if (bean instanceof EnvironmentAware) {
- ((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
- }
- if (bean instanceof EmbeddedValueResolverAware) {
- ((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
- }
- if (bean instanceof ResourceLoaderAware) {
- ((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
- }
- if (bean instanceof ApplicationEventPublisherAware) {
- ((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
- }
- if (bean instanceof MessageSourceAware) {
- ((MessageSourceAware) bean).setMessageSource(this.applicationContext);
- }
- if (bean instanceof ApplicationContextAware) {
- ((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
- }
- }
- }
postProcessBeforelnitialization 方法中调用了invokeAwareInterfaces。从invokeAwareInterfaces方法中,我们或许已经或多或少了解了Spring的用意,实现这些Aware接口的bean在被初始化之后,可以取得一些对应的资源。
4. 设置忽略依赖
当Spring 将 ApplicationContextAwareProcessor 注册后,那么在 invokeAwarelnterfaces 方法中间接调用的 Aware 类已经不是普通的 bean 了,如 ResourceLoaderAware、ApplicationEventPublisher Aware等,那么当然需要在Spring做bean的依赖注入的时候忽略它们。而ignoreDependencylnterfece的作用正是在此。
- // 设置了几个忽略自动装配的接口
- beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
- beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
- beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
- beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
- beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
- beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
5. 注册依赖
Spring中有了忽略依赖的功能,当然也必不可少地会有注册依赖的功能。
- // 设置了几个自动装配的特殊规则
- beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
- beanFactory.registerResolvableDependency(ResourceLoader.class, this);
- beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
- beanFactory.registerResolvableDependency(ApplicationContext.class, this);
当注册了依赖解析后,例如当注册了对BeanFactory.class的解析依赖后,当bean的属性注入的时候,一旦检测到属性为BeanFactory类型便会将beanFactory的实例注人进去。
Spring源码分析(二十二)功能扩展的更多相关文章
- Spring源码分析(十二)FactoryBean的使用
摘要:本文结合<Spring源码深度解析>来分析Spring 5.0.6版本的源代码.若有描述错误之处,欢迎指正. 一般情况下,Spring通过反射机制利用bean的class属性指定实现 ...
- Spring源码分析(十八)创建bean
本文结合<Spring源码深度解析>来分析Spring 5.0.6版本的源代码.若有描述错误之处,欢迎指正. 目录 一.创建bean的实例 1. autowireConstructor 2 ...
- spark 源码分析之十二 -- Spark内置RPC机制剖析之八Spark RPC总结
在spark 源码分析之五 -- Spark内置RPC机制剖析之一创建NettyRpcEnv中,剖析了NettyRpcEnv的创建过程. Dispatcher.NettyStreamManager.T ...
- Spring源码分析(十九)容器的功能扩展概览
摘要: 本文结合<Spring源码深度解析>来分析Spring 5.0.6版本的源代码.若有描述错误之处,欢迎指正. 经过前面几章的分析,相信大家已经对 Spring 中的容器功能有了简单 ...
- Netty源码分析 (十二)----- 心跳服务之 IdleStateHandler 源码分析
什么是心跳机制? 心跳说的是在客户端和服务端在互相建立ESTABLISH状态的时候,如何通过发送一个最简单的包来保持连接的存活,还有监控另一边服务的可用性等. 心跳包的作用 保活Q:为什么说心跳机制能 ...
- Android源码分析(十二)-----Android源码中如何自定义TextView实现滚动效果
一:如何自定义TextView实现滚动效果 继承TextView基类 重写构造方法 修改isFocused()方法,获取焦点. /* * Copyright (C) 2015 The Android ...
- ABP源码分析三十二:ABP.SignalR
Realtime Realtime是ABP底层模块提供的功能,用于管理在线用户.它是使用SignalR实现给在线用户发送通知的功能的前提 IOnlineClient/OnlineClient: 封装在 ...
- ABP源码分析四十二:ZERO的身份认证
ABP Zero模块通过自定义实现Asp.Net Identity完成身份认证功能, 对Asp.Net Identity做了较大幅度的扩展.同时重写了ABP核心模块中的permission功能,以实现 ...
- Vue.js 源码分析(三十二) 总结
第一次写博客,坚持了一个多月时间,Vue源码分析基本分析完了,回过头也看也漏了一些地方,比如双向绑定里的观察者模式,也可以说是订阅者模式,也就是Vue里的Dep.Watcher等这些函数的作用,网上搜 ...
- Spring源码分析(十六)准备创建bean
本文结合<Spring源码深度解析>来分析Spring 5.0.6版本的源代码.若有描述错误之处,欢迎指正. 我们不可能指望在一个函数中完成一个复杂的逻辑,而且我们跟踪了这么多Spring ...
随机推荐
- 关系型数据库基本概念及MySQL简述
数据库基本概念">关系型数据库基本概念 数据库: 对大量信息进行管理的高效解决方案. 按照数据结构来组织.存储和管理数据的库. 数据库系统(DBS,DATABASE SYSTEM): ...
- java获取当月天数,指定年月的天数,指定日期获取对应星期 .
package huolongluo.family.util; import java.text.SimpleDateFormat; import java.util.Calendar; import ...
- 分布式部署下的报表调用 API调用 权限问题以及性能方案
背景描述: 客户的实际情况是需要在具体系统构架前,通过与厂商讨论确定最终的系统架构方案. 需求是客户自己有管理系统,希望建立一个独立的报表服务器,该报表服务器可以对多个管理系统提供报表服务,不知 ...
- centos7 安装mariadb最新版并配置
打开http://mirrors.aliyun.com/,查找mariadb,然后拼装地址http://mirrors.aliyun.com/mariadb/yum打开,点开你想要的版本,选择你的操作 ...
- 安装nvm之后node不可用,“node”不是内部或外部命令,也不是可运行的程序或批处理文件(ng)
安装nvm: 1.下载nvm压缩包地址:https://github.com/coreybutler/nvm-windows/releases 2.下载后解压在目标文件夹中,我这里是H:\applic ...
- zabbix系列之六——安装后配置二Items
https://www.zabbix.com/documentation/3.4/manual/config/items/itemtypes/snmp 1Items 1.1creating items ...
- springMVC入门-02
本节会在上节基础上讨论springMVC如何传值的问题. 在添加dispatcherServlet之后,拦截器会将url中的参数拦截下来,使之可以在controller中使用.以下代码就是在前台输入u ...
- swift版的GCD封装
swift版的GCD封装 说明 本人针对swift封装了GCD,包括GCDQueue,GCDGroup,GCDTimer以及GCDSemaphore,使用较为便利. 源码 https://github ...
- 安装oracle 11g时,报启动服务出现错误,找不到OracleMTSRecoveryService的解决方法
很多人在安装orcl数据库时,出现很多报错,我也不例外,因上次数据库出现问题,无法修复,只能从新安装,无奈的是,安装时报启动服务出现错误,找不到OracleMTSRecoveryService错MMP ...
- Windows下Git使用报错:warning:LF will be replaced by CRLF in ××××.××
Windows下Git使用报错: warning:LF will be replaced by CRLF in ××××.××(文件名) The file will have its original ...