Spring笔记(6) - Spring的BeanFactoryPostProcessor探究
一.背景
在说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,在实例化前。
- getBeanNamesForType():根据传递的类型获取容器中的beanName
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探究的更多相关文章
- Spring笔记(7) - Spring的事件和监听机制
一.背景 事件机制作为一种编程机制,在很多开发语言中都提供了支持,同时许多开源框架的设计中都使用了事件机制,比如SpringFramework. 在 Java 语言中,Java 的事件机制参与者有3种 ...
- spring笔记3 spring MVC的基础知识3
4,spring MVC的视图 Controller得到模型数据之后,通过视图解析器生成视图,渲染发送给用户,用户就看到了结果. 视图:view接口,来个源码查看:它由视图解析器实例化,是无状态的,所 ...
- Spring笔记1——Spring起源及其核心技术
Spring的作用 当我们使用一种技术时,需要思考为什么要使用这门技术.而我们为什么要使用Spring呢?从表面上面SSH这三大框架中,Struts是负责MVC责任的分离,并且提供为Web层提供诸如控 ...
- Spring笔记(4) - Spring的编程式事务和声明式事务详解
一.背景 事务管理对于企业应用而言至关重要.它保证了用户的每一次操作都是可靠的,即便出现了异常的访问情况,也不至于破坏后台数据的完整性.就像银行的自助取款机,通常都能正常为客户服务,但是也难免遇到操作 ...
- spring笔记6 spring IOC的中级知识
1,spring ioc的整体流程,xml配置 spring ioc初始化的流程结合上图 步骤编号 完成的工作 1 spring容器读取配置文件,解析称注册表 2 根据注册表,找到相应的bean实现类 ...
- spring笔记5 spring IOC的基础知识1
1,ioc的概念 Inverse of control ,控制反转,实际的意义是调用类对接口实现类的依赖,反转给第三方的容器管理,从而实现松散耦合: ioc的实现方式有三种,属性注入,构造函数注入,接 ...
- spring笔记4 spring MVC的基础知识4
//todo 5,spring MVC的本地化解析,文件上传,静态资源处理,拦截器,异常处理等 spring MVC 默认使用AcceptHeaderLocalResolver,根据报文头的Accep ...
- spring笔记2 spring MVC的基础知识2
2,spring MVC的注解驱动控制器,rest风格的支持 作为spring mvc的明星级别的功能,无疑是使得自己的code比较优雅的秘密武器: @RequestMapping处理用户的请求,下面 ...
- spring笔记1 spring MVC的基础知识1
1,spring MVC的流程 优秀的展现层框架-Spring MVC,它最出彩的地方是注解驱动和支持REST风格的url. 流程编号 完成的主要任务 补充 1 用户访问web页面,发送一个htt ...
随机推荐
- Jboss未授权访问漏洞复现
一.前言 漏洞原因:在低版本中,默认可以访问Jboss web控制台(http://127.0.0.1:8080/jmx-console),无需用户名和密码. 二.环境配置 使用docker搭建环境 ...
- linux(centos)环境下安装rabbitMq
1.由于rabbitMq是用Erlang语言写的,因此要先安装Erlang环境 下载Erlang :http://www.rabbitmq.com/releases/erlang/erlang-19. ...
- 灵感来袭,基于Redis的分布式延迟队列(续)
背景 上一篇(灵感来袭,基于Redis的分布式延迟队列)讲述了基于Java DelayQueue和Redis实现了分布式延迟队列,这种方案实现比较简单,应用于延迟小,消息量不大的场景是没问题的,毕竟J ...
- Mysql中 int(3) 类型的含义
注意:这里的(3)代表的并不是存储在数据库中的具体的长度,以前总是会误以为int(3)只能存储3个长度的数字,int(11)就会存储11个长度的数字,这是大错特错的. 其实当我们在选择使用int的类型 ...
- Linux系统编程 —时序竞态
时序竞态 什么是时序竞态?将同一个程序执行两次,正常情况下,前后两次执行得到的结果应该是一样的.但由于系统资源竞争的原因,前后两次执行的结果有可能得到不一样的结果,这个现象就是时序竞态. pause函 ...
- JDK1.8新特性之(二)--方法引用
在上一篇文章中我们介绍了JDK1.8的新特性有以下几项. 1.Lambda表达式 2.方法引用 3.函数式接口 4.默认方法 5.Stream 6.Optional类 7.Nashorm javasc ...
- 062 01 Android 零基础入门 01 Java基础语法 07 Java二维数组 01 二维数组应用
062 01 Android 零基础入门 01 Java基础语法 07 Java二维数组 01 二维数组应用 本文知识点:二维数组应用 二维数组的声明和创建 ? 出现空指针异常 数组的名字指向数组的第 ...
- VS 高级版本新建的项目如何降级使低版本 VS 可以打开
转载:https://blog.csdn.net/u012814856/article/details/70325267 一.引言 这里因为工作的原因,公司项目使用的是 VS2015 的编译环境,但是 ...
- 51单片机I2C总线
I2C总线是飞利浦公司推出的一种串行总线,所有器件共用两根信号线,实现数据的传输. 总线接口接了上拉电阻,默认为高电平,所以就可以用"当低电平出现"来标记出一种起始信号.我个人把它 ...
- 微型直流电机控制基本方法 L298N模块
控制任务 让单个直流电机在L298N模块驱动下,完成制动.自由停车,正反转,加减速等基本动作 芯片模块及电路设计 图1 L298N芯片引脚 图2 L298N驱动模块 表1 L298N驱动模块的控制引脚 ...