一.背景

  在说BeanFactoryPostProcessor之前,先来说下BeanPostProcessor,在前文Spring笔记(2) - 生命周期/属性赋值/自动装配及部分源码解析中讲解了BeanPostProcessor是一个bean后置处理器(bean创建对象初始化前后进行拦截工作)。

  BeanPostProcessor的运行流程如下:

    1)Spring IOC容器实例化Bean;

    2)调用BeanPostProcessor的postProcessBeforeInitialization方法;

    3)调用bean实例的初始化方法;

    4)调用BeanPostProcessor的postProcessAfterInitialization方法;

  实现BeanPostProcessor接口可以在Bean(实例化之后)初始化的前后做一些自定义的操作,但是拿到的参数只有BeanDefinition实例和BeanDefinition的名称,也就是无法修改BeanDefinition元数据,这里说的Bean的初始化是:

    1)bean实现了InitializingBean接口,对应的方法为afterPropertiesSet

    2)在bean定义的时候,通过init-method设置的方法

  Spring中Bean的实例化过程图示:  

  那么BeanFactoryPostProcessor顾名思义就是bean工厂的后置处理器,说通俗一些就是可以管理我们的bean工厂内所有的BeanDefinition(未实例化)数据,可以随心所欲的修改属性。            

  Spring容器初始化时,从资源中读取到bean的相关定义后,保存在beanFactory的成员变量中(参考DefaultListableBeanFactory类的成员变量beanDefinitionMap),在实例化bean的操作就是依据这些bean的定义来做的,而在实例化之前,Spring允许我们通过自定义扩展来改变bean的定义,定义一旦变了,后面的实例也就变了,而beanFactory后置处理器,即BeanFactoryPostProcessor就是用来改变bean定义的;如果业务需要,可以配置多个BeanFactoryPostProcessor的实现类,通过”order”控制执行次序(要实现Ordered接口)。

  注册一个BeanFactoryPostProcessor实例需要定义一个Java类来实现BeanFactoryPostProcessor接口,并重写该接口的postProcessorBeanFactory方法。通过beanFactory可以获取bean的定义信息,并可以修改bean的定义信息。(这点是和BeanPostProcessor最大区别)

  所以通过上面的介绍可以总结出有两种方式可以对bean做控制(例如修改某个成员变量):

    1. 只改变实例化的对象(BeanPostProcessor接口);

    2. 改变bean的定义(BeanFactoryPostProcessor接口) ,可以想象成修改了class文件,这样实例化出来的每个对象都变了;  

  PS:BeanFactoryPostProcessor回调会先于BeanPostProcessor  

  下面是BeanFactoryPostProcessor的源码:

public interface BeanFactoryPostProcessor {

    /**
* Modify the application context's internal bean factory after its standard
* initialization. All bean definitions will have been loaded, but no beans
* will have been instantiated yet. This allows for overriding or adding
* properties even to eager-initializing beans.
* @param beanFactory the bean factory used by the application context
* @throws org.springframework.beans.BeansException in case of errors
*/
//在ioc容器的bean Factory标准初始化之后可以对它们进行修改。所有的bean定义被加载了,但还没有被实例化。
//允许进行重载或添加属性即使在eager-initializing beans
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException; }

  BeanFactoryPostProcessor此接口只提供了一个方法,方法参数为ConfigurableListableBeanFactory,下面是该类的源码:

public interface ConfigurableListableBeanFactory
extends ListableBeanFactory, AutowireCapableBeanFactory, ConfigurableBeanFactory { void ignoreDependencyType(Class<?> type); void ignoreDependencyInterface(Class<?> ifc); void registerResolvableDependency(Class<?> dependencyType, @Nullable Object autowiredValue); boolean isAutowireCandidate(String beanName, DependencyDescriptor descriptor)
throws NoSuchBeanDefinitionException; BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException; Iterator<String> getBeanNamesIterator(); void clearMetadataCache(); void freezeConfiguration(); boolean isConfigurationFrozen(); void preInstantiateSingletons() throws BeansException; }

  其中有个方法名为getBeanDefinition的方法,我们可以根据此方法,找到我们定义bean的BeanDefinition对象。然后我们可以对定义的属性进行修改,以下是BeanDefinition中的方法:

public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {

    /**
* Scope identifier for the standard singleton scope: "singleton".
* <p>Note that extended bean factories might support further scopes.
* @see #setScope
*/
String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON; /**
* Scope identifier for the standard prototype scope: "prototype".
* <p>Note that extended bean factories might support further scopes.
* @see #setScope
*/
String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE; /**
* Role hint indicating that a {@code BeanDefinition} is a major part
* of the application. Typically corresponds to a user-defined bean.
*/
int ROLE_APPLICATION = 0; /**
* Role hint indicating that a {@code BeanDefinition} is a supporting
* part of some larger configuration, typically an outer
* {@link org.springframework.beans.factory.parsing.ComponentDefinition}.
* {@code SUPPORT} beans are considered important enough to be aware
* of when looking more closely at a particular
* {@link org.springframework.beans.factory.parsing.ComponentDefinition},
* but not when looking at the overall configuration of an application.
*/
int ROLE_SUPPORT = 1; /**
* Role hint indicating that a {@code BeanDefinition} is providing an
* entirely background role and has no relevance to the end-user. This hint is
* used when registering beans that are completely part of the internal workings
* of a {@link org.springframework.beans.factory.parsing.ComponentDefinition}.
*/
int ROLE_INFRASTRUCTURE = 2; // Modifiable attributes /**
* Set the name of the parent definition of this bean definition, if any.
*/
void setParentName(@Nullable String parentName); /**
* Return the name of the parent definition of this bean definition, if any.
*/
@Nullable
String getParentName(); /**
* Specify the bean class name of this bean definition.
* <p>The class name can be modified during bean factory post-processing,
* typically replacing the original class name with a parsed variant of it.
* @see #setParentName
* @see #setFactoryBeanName
* @see #setFactoryMethodName
*/
void setBeanClassName(@Nullable String beanClassName); /**
* Return the current bean class name of this bean definition.
* <p>Note that this does not have to be the actual class name used at runtime, in
* case of a child definition overriding/inheriting the class name from its parent.
* Also, this may just be the class that a factory method is called on, or it may
* even be empty in case of a factory bean reference that a method is called on.
* Hence, do <i>not</i> consider this to be the definitive bean type at runtime but
* rather only use it for parsing purposes at the individual bean definition level.
* @see #getParentName()
* @see #getFactoryBeanName()
* @see #getFactoryMethodName()
*/
@Nullable
String getBeanClassName(); /**
* Override the target scope of this bean, specifying a new scope name.
* @see #SCOPE_SINGLETON
* @see #SCOPE_PROTOTYPE
*/
void setScope(@Nullable String scope); /**
* Return the name of the current target scope for this bean,
* or {@code null} if not known yet.
*/
@Nullable
String getScope(); /**
* Set whether this bean should be lazily initialized.
* <p>If {@code false}, the bean will get instantiated on startup by bean
* factories that perform eager initialization of singletons.
*/
void setLazyInit(boolean lazyInit); /**
* Return whether this bean should be lazily initialized, i.e. not
* eagerly instantiated on startup. Only applicable to a singleton bean.
*/
boolean isLazyInit(); /**
* Set the names of the beans that this bean depends on being initialized.
* The bean factory will guarantee that these beans get initialized first.
*/
void setDependsOn(@Nullable String... dependsOn); /**
* Return the bean names that this bean depends on.
*/
@Nullable
String[] getDependsOn(); /**
* Set whether this bean is a candidate for getting autowired into some other bean.
* <p>Note that this flag is designed to only affect type-based autowiring.
* It does not affect explicit references by name, which will get resolved even
* if the specified bean is not marked as an autowire candidate. As a consequence,
* autowiring by name will nevertheless inject a bean if the name matches.
*/
void setAutowireCandidate(boolean autowireCandidate); /**
* Return whether this bean is a candidate for getting autowired into some other bean.
*/
boolean isAutowireCandidate(); /**
* Set whether this bean is a primary autowire candidate.
* <p>If this value is {@code true} for exactly one bean among multiple
* matching candidates, it will serve as a tie-breaker.
*/
void setPrimary(boolean primary); /**
* Return whether this bean is a primary autowire candidate.
*/
boolean isPrimary(); /**
* Specify the factory bean to use, if any.
* This the name of the bean to call the specified factory method on.
* @see #setFactoryMethodName
*/
void setFactoryBeanName(@Nullable String factoryBeanName); /**
* Return the factory bean name, if any.
*/
@Nullable
String getFactoryBeanName(); /**
* Specify a factory method, if any. This method will be invoked with
* constructor arguments, or with no arguments if none are specified.
* The method will be invoked on the specified factory bean, if any,
* or otherwise as a static method on the local bean class.
* @see #setFactoryBeanName
* @see #setBeanClassName
*/
void setFactoryMethodName(@Nullable String factoryMethodName); /**
* Return a factory method, if any.
*/
@Nullable
String getFactoryMethodName(); /**
* Return the constructor argument values for this bean.
* <p>The returned instance can be modified during bean factory post-processing.
* @return the ConstructorArgumentValues object (never {@code null})
*/
ConstructorArgumentValues getConstructorArgumentValues(); /**
* Return if there are constructor argument values defined for this bean.
* @since 5.0.2
*/
default boolean hasConstructorArgumentValues() {
return !getConstructorArgumentValues().isEmpty();
} /**
* Return the property values to be applied to a new instance of the bean.
* <p>The returned instance can be modified during bean factory post-processing.
* @return the MutablePropertyValues object (never {@code null})
*/
MutablePropertyValues getPropertyValues(); /**
* Return if there are property values values defined for this bean.
* @since 5.0.2
*/
default boolean hasPropertyValues() {
return !getPropertyValues().isEmpty();
} /**
* Set the name of the initializer method.
* @since 5.1
*/
void setInitMethodName(@Nullable String initMethodName); /**
* Return the name of the initializer method.
* @since 5.1
*/
@Nullable
String getInitMethodName(); /**
* Set the name of the destroy method.
* @since 5.1
*/
void setDestroyMethodName(@Nullable String destroyMethodName); /**
* Return the name of the destroy method.
* @since 5.1
*/
@Nullable
String getDestroyMethodName(); /**
* Set the role hint for this {@code BeanDefinition}. The role hint
* provides the frameworks as well as tools with an indication of
* the role and importance of a particular {@code BeanDefinition}.
* @since 5.1
* @see #ROLE_APPLICATION
* @see #ROLE_SUPPORT
* @see #ROLE_INFRASTRUCTURE
*/
void setRole(int role); /**
* Get the role hint for this {@code BeanDefinition}. The role hint
* provides the frameworks as well as tools with an indication of
* the role and importance of a particular {@code BeanDefinition}.
* @see #ROLE_APPLICATION
* @see #ROLE_SUPPORT
* @see #ROLE_INFRASTRUCTURE
*/
int getRole(); /**
* Set a human-readable description of this bean definition.
* @since 5.1
*/
void setDescription(@Nullable String description); /**
* Return a human-readable description of this bean definition.
*/
@Nullable
String getDescription(); // Read-only attributes /**
* Return a resolvable type for this bean definition,
* based on the bean class or other specific metadata.
* <p>This is typically fully resolved on a runtime-merged bean definition
* but not necessarily on a configuration-time definition instance.
* @return the resolvable type (potentially {@link ResolvableType#NONE})
* @since 5.2
* @see ConfigurableBeanFactory#getMergedBeanDefinition
*/
ResolvableType getResolvableType(); /**
* Return whether this a <b>Singleton</b>, with a single, shared instance
* returned on all calls.
* @see #SCOPE_SINGLETON
*/
boolean isSingleton(); /**
* Return whether this a <b>Prototype</b>, with an independent instance
* returned for each call.
* @since 3.0
* @see #SCOPE_PROTOTYPE
*/
boolean isPrototype(); /**
* Return whether this bean is "abstract", that is, not meant to be instantiated.
*/
boolean isAbstract(); /**
* Return a description of the resource that this bean definition
* came from (for the purpose of showing context in case of errors).
*/
@Nullable
String getResourceDescription(); /**
* Return the originating BeanDefinition, or {@code null} if none.
* Allows for retrieving the decorated bean definition, if any.
* <p>Note that this method returns the immediate originator. Iterate through the
* originator chain to find the original BeanDefinition as defined by the user.
*/
@Nullable
BeanDefinition getOriginatingBeanDefinition(); }

  我们可以在上面代码中发现里面的方法名字类似bean标签的属性,setBeanClassName对应bean标签中的class属性,所以当我们拿到BeanDefinition对象时,我们可以手动修改bean标签中所定义的属性值。

  具体这个BeanDefinition是个什么对象,当我们在xml中定义了bean标签时,Spring会把这些bean标签解析成一个javabean,这个BeanDefinition就是bean标签对应的javabean。

  所以当我们调用BeanFactoryPostProcess方法时,这时候bean还没有实例化,此时bean刚被解析成BeanDefinition对象。

  Spring容器初始化bean大致过程 :

    1)定义bean标签

    2)将bean标签解析成BeanDefinition

    3)调用构造方法实例化(IOC)

    4)属性值得依赖注入(DI)

  所以可以看出BeanFactoryPostProcess方法的执行是发生在第二步之后,第三步之前。

  综上所述BeanPostProcessor和BeanFactoryPostProcess都是为Spring提供的后处理bean的接口,只是两者执行的时机不一样。BeanPostProcessor为实例化之后,BeanFactoryPostProcess是实例化之前。功能上,BeanFactoryPostProcess对bean的处理功能更加强大。

二.案例

  1.配置类:进行包扫描将类加载到容器中

@ComponentScan("com.hrh.ext")
@Configuration
public class ExtConfig {
@Bean
public Person person() {
return new Person("张三", "男");
}
}

  2.实体类:

public class Person implements InitializingBean, DisposableBean, BeanNameAware, BeanFactoryAware {
private String name;
private String sex; public Person() {
System.out.println("Person无参构造器"); } public Person(String name, String sex) {
System.out.println("Person有参构造器:[name=" + name + ",sex=" + sex + "]");
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public String getSex() {
return sex;
} public void setSex(String sex) {
this.sex = sex;
} @Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
System.out.println("[Person]调用了BeanFactoryAware的setBeanFactory方法了:" + beanFactory);
} @Override
public void setBeanName(String name) {
System.out.println("[Person]调用了BeanNameAware的setBeanName方法了:" + name);
} @Override
public void destroy() throws Exception {
System.out.println("[Person]调用了DisposableBean的destroy方法了");
} @Override
public void afterPropertiesSet() throws Exception {
System.out.println("[Person]调用了Initailization的afterPropertiesSet方法了");
} @Override
public String toString() {
return "Person [name=" + name + ", sex=" + sex
+ "]";
}
}

  3.自定义BeanFactoryPostProcessor类:

@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
System.out.println("[MyBeanFactoryPostProcessor]调用了postProcessBeanFactory");
int count = beanFactory.getBeanDefinitionCount();
System.out.println("[MyBeanFactoryPostProcessor]当前beanFactory共有" + count + "个bean");
String[] beanDefinitionNames = beanFactory.getBeanDefinitionNames();
System.out.println("[MyBeanFactoryPostProcessor]当前beanFactory有下面组件" + Arrays.asList(beanDefinitionNames));
//获取容器中所有的beanDefinition
for (String beanName : beanDefinitionNames) {
if ("person".equals(beanName)) {
//获取PersonDefinition对象
BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);
MutablePropertyValues propertyValues = beanDefinition.getPropertyValues();
System.out.println(propertyValues.toString());
//修改定义中的name属性值
propertyValues.addPropertyValue("name", "赵四");
System.out.println("[MyBeanFactoryPostProcessor]postProcessBeanFactory方法中修改了name属性初始值了");
System.out.println(propertyValues.toString());
}
}
}
}

  4.自定义BeanPostProcessor类:

@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean,
String beanName) throws BeansException {
System.out.println("[MyBeanPostProcessor]后置处理器处理bean=【" + beanName + "】开始");
return bean;
} @Override
public Object postProcessAfterInitialization(Object bean,
String beanName) throws BeansException {
System.out.println("[MyBeanPostProcessor]后置处理器处理bean=【" + beanName + "】完毕!");
return bean;
}
}

  5.测试:

    public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ExtConfig.class);
Person bean = context.getBean(Person.class);
System.out.println(bean.toString());
context.close();
} ======运行结果======
[MyBeanFactoryPostProcessor]调用了postProcessBeanFactory
[MyBeanFactoryPostProcessor]当前beanFactory共有9个bean
[MyBeanFactoryPostProcessor]当前beanFactory有下面组件[org.springframework.context.annotation.internalConfigurationAnnotationProcessor, org.springframework.context.annotation.internalAutowiredAnnotationProcessor, org.springframework.context.annotation.internalCommonAnnotationProcessor, org.springframework.context.event.internalEventListenerProcessor, org.springframework.context.event.internalEventListenerFactory, extConfig, myBeanFactoryPostProcessor, myBeanPostProcessor, person]
PropertyValues: length=0
[MyBeanFactoryPostProcessor]postProcessBeanFactory方法中修改了name属性初始值了
PropertyValues: length=1; bean property 'name'
[MyBeanPostProcessor]后置处理器处理bean=【extConfig】开始
[MyBeanPostProcessor]后置处理器处理bean=【extConfig】完毕!
Person有参构造器:[name=张三,sex=男]
[Person]调用了BeanNameAware的setBeanName方法了:person
[Person]调用了BeanFactoryAware的setBeanFactory方法了:org.springframework.beans.factory.support.DefaultListableBeanFactory@e45f292: defining beans [org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.event.internalEventListenerProcessor,org.springframework.context.event.internalEventListenerFactory,extConfig,myBeanFactoryPostProcessor,myBeanPostProcessor,person]; root of factory hierarchy
[MyBeanPostProcessor]后置处理器处理bean=【person】开始
[Person]调用了Initailization的afterPropertiesSet方法了
[MyBeanPostProcessor]后置处理器处理bean=【person】完毕!
Person [name=赵四, sex=null]
[Person]调用了DisposableBean的destroy方法了

  从上面的运行结果可以看出:

    1)Person的name值由"张三"变为"赵四";

    2)BeanFactoryPostProcessor方法执行顺序先于BeanPostProcessor接口中方法,且在bean实例化之前执行;

    3)BeanFactoryPostProcessor改变bean的定义,实例化出来的对象变了:“Person有参构造器:[name=张三,sex=男] ”变成了“Person [name=赵四, sex=null]

    4)BeanPostProcessor在bean创建对象实例化后,初始化(bean执行afterPropertiesSet方法或init-method方法)前后进行拦截工作;

三.原理

  接下来我们通过debug代码来查看BeanFactoryPostProcessor的执行流程,从AbstractApplicationContext类的构造器方法看起,这里面对应着容器初始化的基本操作;

  1.在测试main方法中下面的代码打断点:

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ExtConfig.class);

  2.从下图可以看出容器先注册配置类ExtConfig的定义信息,然后进行refresh刷新容器;

  3.先来看看register(componentClasses)注册流程:从class文件读取信息解析成beanDefinition

AnnotationConfigApplicationContext:
public void register(Class<?>... componentClasses) {
Assert.notEmpty(componentClasses, "At least one component class must be specified");
this.reader.register(componentClasses);
} AnnotatedBeanDefinitionReader:注册beanDefinition
public void register(Class<?>... componentClasses) {
for (Class<?> componentClass : componentClasses) {
registerBean(componentClass);
}
} public void registerBean(Class<?> beanClass) {
doRegisterBean(beanClass, null, null, null, null);
} //Register a bean from the given bean class, deriving its metadata from class-declared annotations.
//从class文件中读取bean的定义信息,并注册到容器中
private <T> void doRegisterBean(Class<T> beanClass, @Nullable String name,
@Nullable Class<? extends Annotation>[] qualifiers, @Nullable Supplier<T> supplier,
@Nullable BeanDefinitionCustomizer[] customizers) {
//得到bean的所有定义信息:元数据metadata、作用域scope、初始化方法名字initMethodName等等
AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);
if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
return;
}
//为bean实例创建一个特殊的回调信号
abd.setInstanceSupplier(supplier);
//获取作用域的数据:单例
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
//设置bean为单例
abd.setScope(scopeMetadata.getScopeName());
//获取beanName
String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));
//处理一些注释信息:lazyInit、primary、dependsOn、role、description
AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
if (qualifiers != null) {//qualifiers = nul 跳过
for (Class<? extends Annotation> qualifier : qualifiers) {
if (Primary.class == qualifier) {
abd.setPrimary(true);
}
else if (Lazy.class == qualifier) {
abd.setLazyInit(true);
}
else {
abd.addQualifier(new AutowireCandidateQualifier(qualifier));
}
}
}
if (customizers != null) {//customizers = null跳过
for (BeanDefinitionCustomizer customizer : customizers) {
customizer.customize(abd);
}
}
//创建一个BeanDefinitionHolder
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
//容器中注册beanDefinition
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
}

  4.refresh刷新容器:invokeBeanFactoryPostProcessors方法用来找出所有beanFactory后置处理器,并且调用这些处理器来改变bean的定义

    public void refresh() throws BeansException, IllegalStateException {
//来个锁,不然 refresh() 还没结束,你又来个启动或销毁容器的操作,那不就乱套了嘛
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
//容器刷新前的处理方法:获取启动的系统时间、设置active活跃标识、开始打印日志、设置环境变量、设置容器监听器、设置容器事件
prepareRefresh(); // Tell the subclass to refresh the internal bean factory.
//刷新bean工厂并获取到bean工厂
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // Prepare the bean factory for use in this context.
// bean工厂的初始化操作:设置类加载器、设置bean表达式解析器、设置bean后置处理器等等;
prepareBeanFactory(beanFactory); try {
// Allows post-processing of the bean factory in context subclasses.
// 【这里需要知道 BeanFactoryPostProcessor 这个知识点,Bean 如果实现了此接口,
// 那么在容器初始化以后,Spring 会负责调用里面的 postProcessBeanFactory 方法。】
// 这里是提供给子类的扩展点,到这里的时候,所有的 Bean 都加载、注册完成了,但是都还没有初始化
// 具体的子类可以在这步的时候根据自身业务添加或修改一些特殊的 beanFactory属性
postProcessBeanFactory(beanFactory); // Invoke factory processors registered as beans in the context.
//找出所有beanFactory后置处理器,并且调用这些处理器来改变bean的定义
invokeBeanFactoryPostProcessors(beanFactory); // Register bean processors that intercept bean creation.
//注册bean后置处理器
registerBeanPostProcessors(beanFactory); // Initialize message source for this context.
//初始化容器的信息源
initMessageSource(); // Initialize event multicaster for this context.
//初始化事件监听多路广播器
initApplicationEventMulticaster(); // Initialize other special beans in specific context subclasses.
//是个空壳方法,在AnnotationApplicationContex上下文中没有实现,可能在spring后面的版本会去扩展。
//与Web上下文有关
onRefresh(); // Check for listener beans and register them.
//注册监听器
registerListeners(); // Instantiate all remaining (non-lazy-init) singletons.
//对象的创建:初始化剩下所有的(非懒加载的)单实例对象【从这里可以看出beanFactory后置处理器在初始化其他组件之前执行】
finishBeanFactoryInitialization(beanFactory); // Last step: publish corresponding event.
//刷新完成工作,包括初始化LifecycleProcessor,发布刷新完成事件等
finishRefresh();
} catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
} // Destroy already created singletons to avoid dangling resources.
//销毁已经初始化的 singleton 的 Beans,以免有些 bean 会一直占用资源
destroyBeans(); // Reset 'active' flag.
//取消刷新的标志
cancelRefresh(ex); // Propagate exception to caller.
throw ex;
} finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}

  5.打开invokeBeanFactoryPostProcessors方法,如下所示,实际操作是委托PostProcessorRegis

trationDelegate去完成的:调用getBeanFactoryPostProcessors()方法获取手工注册到ApplicationCon

text的容器后置处理器集合

    protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors()); // Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime
// (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)
if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}

  1)在调用PostProcessorRegistrationDelegate类的invokeBeanFactoryPostProcessors方法时,注意第二个入参是getBeanFactoryPostProcessors()方法,该方法返回的是applicationContext的成员变量beanFactoryPostProcessors,该成员变量的值来自AbstractApplicationContext.addBeanFactoryPostProcessor方法被调用的时候:

    private final List<BeanFactoryPostProcessor> beanFactoryPostProcessors = new ArrayList<>();
@Override
public void addBeanFactoryPostProcessor(BeanFactoryPostProcessor postProcessor) {
Assert.notNull(postProcessor, "BeanFactoryPostProcessor must not be null");
this.beanFactoryPostProcessors.add(postProcessor);
} public List<BeanFactoryPostProcessor> getBeanFactoryPostProcessors() {
return this.beanFactoryPostProcessors;
}

    2)AbstractApplicationContext.addBeanFactoryPostProcessor方法是留给业务扩展时调用的,例如在springboot初始化时,ConfigurationWarningsApplicationContextInitializer类的initialize方法中就有调用:

@Override
public void initialize(ConfigurableApplicationContext context) {
context.addBeanFactoryPostProcessor(
new ConfigurationWarningsPostProcessor(getChecks()));
}

6.看过了如何添加BeanFactoryPostProcessor,再回到PostProcessorRegistrationDelegate.invok

eBeanFactoryPostProcessors方法:实例化并调用所有已注册的BeanFactoryPostProcessor bean;

流程是:

  1)beanFactory是BeanDefinitionRegistry类型时,此条件下完成如下流程:

    1.遍历传入后置处理器集合查找类型为BeanDefinitionRegistryPostProcessor的后置处理器,调用后置处理器的postProcessBeanDefinitionRegistry方法;

    2.在容器中查找所有的实现了PriorityOrdered接口的BeanDefinition

RegistryPostProcessor集合,对后置处理器集合排序,遍历,执行后置处理的postProcessBeanDefinitionRegistry方法;

    3.在容器中查找所有实现了Ordered接口的BeanDefinitionRegistryPostProcessor集合,对后置处理器集合排序,遍历,执行后置处理的postProcessBeanDefinitionRegistry方法;

    4.在容器中查找其它(未实现排序接口)的BeanDefinitionRegistryPostProcessor并添加到集合nonOrderedPostProcessors中,对后置处理器集合排序,遍历,执行后置处理的postProcessBeanDefinitionRegistry方法;

    5.当前所有的BeanDefinitionRegistryPostProcessor处理器的方法postProcessBeanD

efinitionRegistry 执行完毕后,执行其父类postProcessBeanFactory方法;

    6.执行所有非BeanDefinitionRegistryPostProcessor类型的后置处理器的postProcessB

eanFactory方法;

  2)beanFactory非BeanDefinitionRegistry类型时,此条件下完成如下流程:

    1.遍历传入后置处理器集合,执行后置处理器的postProcessBeanFactory方法;

    2.在容器中(beanFactory.getBeanNamesForType)查找所有的实现了PriorityOrdered接口的BeanFactoryPostProcessor集合,对后置处理器集合排序,遍历,执行后置处理;

    3.在容器中查找所有实现了Ordered接口的BeanFactoryPostProcessor集合,对后置处理器集合排序,遍历,执行后置处理;

    4.在容器中查找其它(未实现排序接口)的BeanFactoryPostProcessor并添加到集合nonOrderedPostProcessors中,对后置处理器集合排序,遍历,执行后置处理;

    public static void invokeBeanFactoryPostProcessors(
ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) { // Invoke BeanDefinitionRegistryPostProcessors first, if any.
Set<String> processedBeans = new HashSet<>();
//如果beanFactory实现了BeanDefinitionRegistry
if (beanFactory instanceof BeanDefinitionRegistry) {
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>(); for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
//如果beanFactoryPostProcessor实现了BeanDefinitionRegistryPostProcessor,分别放入两个集合:registryProcessors 和 regularPostProcessors
if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
BeanDefinitionRegistryPostProcessor registryProcessor =
(BeanDefinitionRegistryPostProcessor) postProcessor;
registryProcessor.postProcessBeanDefinitionRegistry(registry);
registryProcessors.add(registryProcessor);
}
else {
regularPostProcessors.add(postProcessor);
}
} // Do not initialize FactoryBeans here: We need to leave all regular beans
// uninitialized to let the bean factory post-processors apply to them!
// Separate between BeanDefinitionRegistryPostProcessors that implement
// PriorityOrdered, Ordered, and the rest.
List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>(); // First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
//找出所有实现了BeanDefinitionRegistryPostProcessor接口和PriorityOrdered接口的bean,放入registryProcessors集合,
//放入根据Set接口来排序,然后这些bean会被invokeBeanDefinitionRegistryPostProcessors方法执行;
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear(); // Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.
//找出所有实现了BeanDefinitionRegistryPostProcessor接口和Ordered接口的bean,放入registryProcessors集合,
//放入根据Set接口来排序,然后这些bean会被invokeBeanDefinitionRegistryPostProcessors方法执行;
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear(); // Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.
//对于那些实现了BeanDefinitionRegistryPostProcessor接口,但是没有实现PriorityOrdered和Ordered的bean也被找出来,
//然后这些bean会被invokeBeanDefinitionRegistryPostProcessors方法执行;
boolean reiterate = true;
while (reiterate) {
reiterate = false;
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (!processedBeans.contains(ppName)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
reiterate = true;
}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear();
} // Now, invoke the postProcessBeanFactory callback of all processors handled so far.
//registryProcessors和regularPostProcessors集合被invokeBeanFactoryPostProcessors执行
invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
} else {
// Invoke factory processors registered with the context instance.
//入参中的BeanFactoryPostProcessor,没有实现BeanDefinitionRegistryPostProcessor的那些bean,被invokeBeanFactoryPostProcessors执行
invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
} // Do not initialize FactoryBeans here: We need to leave all regular beans
// uninitialized to let the bean factory post-processors apply to them!
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false); // Separate between BeanFactoryPostProcessors that implement PriorityOrdered,
// Ordered, and the rest.
//找出实现了BeanFactoryPostProcessor接口的bean,注意这里已将上面实现了BeanDefinitionRegistryPostProcessor接口的bean给剔除了,
//将这些bean分为三类:实现了PriorityOrdered接口的放入priorityOrderedPostProcessors,
//实现了Ordered接口的放入orderedPostProcessorNames,其他的放入nonOrderedPostProcessorNames
//自定义的实现BeanFactoryPostProcessor接口的bean就会在nonOrderedPostProcessorNames被找出来
List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
List<String> orderedPostProcessorNames = new ArrayList<>();
List<String> nonOrderedPostProcessorNames = new ArrayList<>();
for (String ppName : postProcessorNames) {
if (processedBeans.contains(ppName)) {
// skip - already processed in first phase above
}
else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
}
else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
orderedPostProcessorNames.add(ppName);
}
else {
nonOrderedPostProcessorNames.add(ppName);
}
} // First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered.
//priorityOrderedPostProcessors先排序再被invokeBeanFactoryPostProcessors执行
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory); // Next, invoke the BeanFactoryPostProcessors that implement Ordered.
//orderedPostProcessorNames先被遍历加入到orderedPostProcessors,再被排序,最后才被invokeBeanFactoryPostProcessors执行
List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
for (String postProcessorName : orderedPostProcessorNames) {
orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
sortPostProcessors(orderedPostProcessors, beanFactory);
invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory); // Finally, invoke all other BeanFactoryPostProcessors.
//nonOrderedPostProcessorNames也是先被遍历到nonOrderedPostProcessors,再被invokeBeanFactoryPostProcessors执行
List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
for (String postProcessorName : nonOrderedPostProcessorNames) {
nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
//这时才是执行自定义BeanFactoryPostProcessor的postProcessBeanFactory
invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory); // Clear cached merged bean definitions since the post-processors might have
// modified the original metadata, e.g. replacing placeholders in values...
beanFactory.clearMetadataCache();
}
    • getBeanNamesForType():根据传递的类型获取容器中的beanName

      // type:类的类型名称
      // includeNonSingletons:返回数据包含了非单例beanName
      // allowEagerInit: 可以提前加载初始化
      public String[] getBeanNamesForType(Class<?> type, boolean includeNonSingletons, boolean allowEagerInit) {
      if (!isConfigurationFrozen() || type == null || !allowEagerInit) {
      // 不可用缓存、类型无效、不允许提前加载初始化
      // 需要获取当前type的原始类型,继续获取数据
      return doGetBeanNamesForType(ResolvableType.forRawClass(type), includeNonSingletons, allowEagerInit);
      }
      Map<Class<?>, String[]> cache =
      (includeNonSingletons ? this.allBeanNamesByType : this.singletonBeanNamesByType);
      String[] resolvedBeanNames = cache.get(type);
      // 如果缓存已经存储了该数据,则无需再计算,直接返回即可
      if (resolvedBeanNames != null) {
      return resolvedBeanNames;
      }
      resolvedBeanNames = doGetBeanNamesForType(ResolvableType.forRawClass(type), includeNonSingletons, true);
      // 这一步就是真正的获取数据,遍历beanDefinitionNames的每一个数据,符合要求的就会加入到返回的列表中 if (ClassUtils.isCacheSafe(type, getBeanClassLoader())) {
      cache.put(type, resolvedBeanNames);
      // 便于下一次获取,加入缓存中
      }
      return resolvedBeanNames;
      }
    • getBean后面还有一个参数BeanFactoryPostProcessor.class,注意看这个函数,会发现返回的是一个抽象类,结论就是nonOrderedPostProcessors添加的不是bean实例,而是beandefinition,在实例化前。

  7.从上面代码中可以看出所有实现了BeanFactoryPostProcessor接口的bean,都被作为入参,然后调用了invokeBeanDefinitionRegistryPostProcessors或者invokeBeanFactoryPostProcessors方法去处理:对每个BeanFactoryPostProcessor接口的实现类,都调用了其接口方法,不同的是,对于实现了BeanDefinitionRegistryPostProcessor接口的bean,调用其postProcessBeanDefinitionRegistry方法的时候,入参是BeanDefinitionRegistry,而非BeanFactory,因此,实现了BeanDefinitionRegistryPostProcessor接口的bean,其postProcessBeanDefinitionRegistry在被调用时,可以通过入参BeanDefinitionRegistry来做更多和bean的定义有关的操作,例如注册bean;

    /**
* Invoke the given BeanDefinitionRegistryPostProcessor beans.
*/
private static void invokeBeanDefinitionRegistryPostProcessors(
Collection<? extends BeanDefinitionRegistryPostProcessor> postProcessors, BeanDefinitionRegistry registry) { for (BeanDefinitionRegistryPostProcessor postProcessor : postProcessors) {
postProcessor.postProcessBeanDefinitionRegistry(registry);
}
} /**
* Invoke the given BeanFactoryPostProcessor beans.
*/
private static void invokeBeanFactoryPostProcessors(
Collection<? extends BeanFactoryPostProcessor> postProcessors, ConfigurableListableBeanFactory beanFactory) { for (BeanFactoryPostProcessor postProcessor : postProcessors) {
postProcessor.postProcessBeanFactory(beanFactory);
}

  8.BeanFactoryPostProcessor 执行的整体流程:

    1)ApplicationContext的refresh方法

    2)ApplicationContext的invokeBeanFactoryPostProcessors方法

    3)PostProcessorRegistrationDelegate的invokeBeanFactoryPostProcessors

  9.BeanFactoryPostProcessor执行的优先级:

    1)首先是实现了PriorityOrdered接口的,排序执行

    2)下来是实现了Ordered接口的,排序执行

    3)最后是其它(未实现排序接口),顺序执行

  10.BeanFactoryPostProcessor获取机制:

    1)首先获取手动注册ApplicationContext的集合

    2)再次是通过beanFactory.getBeanNamesForType查找所有已注册的BeanFactory

PostProcessor的bean定义并实例化。

四.总结

  1. ApplicationContext扩展类可以调用AbstractApplicationContext.addBeanFactoryPostProcessor方法,将自定义的BeanFactoryPostProcessor实现类保存到ApplicationContext中;
  2. Spring容器初始化时,上一步中被加入到ApplicationContext的bean会被优先调用其postProcessBeanFactory方法;
  3. 自定义的BeanFactoryPostProcessor接口实现类,也会被找出来,然后调用其postProcessBeanFactory方法;
  4. postProcessBeanFactory方法被调用时,beanFactory会被作为参数传入,自定义类中可以使用该参数来处理bean的定义,达到业务需求;
  5. 此时的Spring容器还没有开始实例化bean,因此自定义的BeanFactoryPostProcessor实现类不要做与bean实例有关的操作,而是做一些与bean定义有关的操作,例如修改某些字段的值,这样后面实例化的bean的就会有相应的改变;

  6.Spring主要将BeanFactoryPostProcessor划分了两类:

    • 正常的BeanFactoryPostProcessor
    • BeanDefinitionRegistry类型的BeanDefinitionRegistryPostProcessor

  7.在执行流程中可以看到Spring先执行了BeanDefinitionRegistryPostProcessor类型的postProcessBeanDefinitionRegistry方法,再执行BeanDefinitionRegistryPostProcessor和正常BeanFactoryPostProcessor的postProcessBeanFactory方法。

  8.Spring对BeanDefinitionRegistryPostProcessor的解释是:允许在正常的BeanFactoryPostProcessor执行检测开始之前注册更多的自定义bean。也就是说BeanDefinitionRegistryPostProcessor的方法postProcessBeanDefinitionRegistry可以在后置处理器执行前自定义注册更多的BeanDefinition。

  例如:Spring实现的ConfigurationClassPostProcessor用于注册注解@Configuration标识的类里面定义的BeanDefinition。

Spring笔记(6) - Spring的BeanFactoryPostProcessor探究的更多相关文章

  1. Spring笔记(7) - Spring的事件和监听机制

    一.背景 事件机制作为一种编程机制,在很多开发语言中都提供了支持,同时许多开源框架的设计中都使用了事件机制,比如SpringFramework. 在 Java 语言中,Java 的事件机制参与者有3种 ...

  2. spring笔记3 spring MVC的基础知识3

    4,spring MVC的视图 Controller得到模型数据之后,通过视图解析器生成视图,渲染发送给用户,用户就看到了结果. 视图:view接口,来个源码查看:它由视图解析器实例化,是无状态的,所 ...

  3. Spring笔记1——Spring起源及其核心技术

    Spring的作用 当我们使用一种技术时,需要思考为什么要使用这门技术.而我们为什么要使用Spring呢?从表面上面SSH这三大框架中,Struts是负责MVC责任的分离,并且提供为Web层提供诸如控 ...

  4. Spring笔记(4) - Spring的编程式事务和声明式事务详解

    一.背景 事务管理对于企业应用而言至关重要.它保证了用户的每一次操作都是可靠的,即便出现了异常的访问情况,也不至于破坏后台数据的完整性.就像银行的自助取款机,通常都能正常为客户服务,但是也难免遇到操作 ...

  5. spring笔记6 spring IOC的中级知识

    1,spring ioc的整体流程,xml配置 spring ioc初始化的流程结合上图 步骤编号 完成的工作 1 spring容器读取配置文件,解析称注册表 2 根据注册表,找到相应的bean实现类 ...

  6. spring笔记5 spring IOC的基础知识1

    1,ioc的概念 Inverse of control ,控制反转,实际的意义是调用类对接口实现类的依赖,反转给第三方的容器管理,从而实现松散耦合: ioc的实现方式有三种,属性注入,构造函数注入,接 ...

  7. spring笔记4 spring MVC的基础知识4

    //todo 5,spring MVC的本地化解析,文件上传,静态资源处理,拦截器,异常处理等 spring MVC 默认使用AcceptHeaderLocalResolver,根据报文头的Accep ...

  8. spring笔记2 spring MVC的基础知识2

    2,spring MVC的注解驱动控制器,rest风格的支持 作为spring mvc的明星级别的功能,无疑是使得自己的code比较优雅的秘密武器: @RequestMapping处理用户的请求,下面 ...

  9. spring笔记1 spring MVC的基础知识1

    1,spring MVC的流程 优秀的展现层框架-Spring MVC,它最出彩的地方是注解驱动和支持REST风格的url.   流程编号 完成的主要任务 补充 1 用户访问web页面,发送一个htt ...

随机推荐

  1. Jboss未授权访问漏洞复现

    一.前言 漏洞原因:在低版本中,默认可以访问Jboss web控制台(http://127.0.0.1:8080/jmx-console),无需用户名和密码. 二.环境配置 使用docker搭建环境 ...

  2. linux(centos)环境下安装rabbitMq

    1.由于rabbitMq是用Erlang语言写的,因此要先安装Erlang环境 下载Erlang :http://www.rabbitmq.com/releases/erlang/erlang-19. ...

  3. 灵感来袭,基于Redis的分布式延迟队列(续)

    背景 上一篇(灵感来袭,基于Redis的分布式延迟队列)讲述了基于Java DelayQueue和Redis实现了分布式延迟队列,这种方案实现比较简单,应用于延迟小,消息量不大的场景是没问题的,毕竟J ...

  4. Mysql中 int(3) 类型的含义

    注意:这里的(3)代表的并不是存储在数据库中的具体的长度,以前总是会误以为int(3)只能存储3个长度的数字,int(11)就会存储11个长度的数字,这是大错特错的. 其实当我们在选择使用int的类型 ...

  5. Linux系统编程 —时序竞态

    时序竞态 什么是时序竞态?将同一个程序执行两次,正常情况下,前后两次执行得到的结果应该是一样的.但由于系统资源竞争的原因,前后两次执行的结果有可能得到不一样的结果,这个现象就是时序竞态. pause函 ...

  6. JDK1.8新特性之(二)--方法引用

    在上一篇文章中我们介绍了JDK1.8的新特性有以下几项. 1.Lambda表达式 2.方法引用 3.函数式接口 4.默认方法 5.Stream 6.Optional类 7.Nashorm javasc ...

  7. 062 01 Android 零基础入门 01 Java基础语法 07 Java二维数组 01 二维数组应用

    062 01 Android 零基础入门 01 Java基础语法 07 Java二维数组 01 二维数组应用 本文知识点:二维数组应用 二维数组的声明和创建 ? 出现空指针异常 数组的名字指向数组的第 ...

  8. VS 高级版本新建的项目如何降级使低版本 VS 可以打开

    转载:https://blog.csdn.net/u012814856/article/details/70325267 一.引言 这里因为工作的原因,公司项目使用的是 VS2015 的编译环境,但是 ...

  9. 51单片机I2C总线

    I2C总线是飞利浦公司推出的一种串行总线,所有器件共用两根信号线,实现数据的传输. 总线接口接了上拉电阻,默认为高电平,所以就可以用"当低电平出现"来标记出一种起始信号.我个人把它 ...

  10. 微型直流电机控制基本方法 L298N模块

    控制任务 让单个直流电机在L298N模块驱动下,完成制动.自由停车,正反转,加减速等基本动作 芯片模块及电路设计 图1 L298N芯片引脚 图2 L298N驱动模块 表1 L298N驱动模块的控制引脚 ...