FactoryBean、BeanFactory
BeanFactory
BeanFactory是管理和生产Bean的,它是用于访问Spring Bean容器的根接口。,定义了管理Bean的方法,获取Bean、包含Bean、是否单例Bean、获取Bean类型等。Spring根据他提供了很多实现,如 DefaultListableBeanFactory、XmlBeanFactory、ApplicationContext等。其中XmlBeanFactory就是常用的一个,该实现将以XML方式描述组成应用的对象及对象间的依赖关系。AnnotationConfigApplicationContext类是基于组件类作为输入的Spring上下文入口,比如@Configuration注解标注的类和@ComponentScan标注的类
FactorBean
FactoryBean首先是一个Bean,其次他能生产Bean,它是某个Bean的工厂类,主要用于生产这个Bean
一般情况下,Spring通过反射机制利用的class属性指定实现类实例化Bean。至于为什么会有FactoryBean?
- 实例化Bean比较复杂,单纯使用反射受限,使用FactoryBean专门来创建具体的Bean。实例化Bean过程比较复杂,如果按照传统的方式,则需要在中提供大量的配置信息。配置方式的灵活性是受限的,这时采用编码的方式可能会得到一个简单的方案。Spring为此提供了一个
org.springframework.bean.factory.FactoryBean
的工厂类接口,用户可以通过实现该接口定制实例化Bean的逻辑 - 由于第三方库不能直接注册到spring容器,于是可以实现
org.springframework.bean.factory.FactoryBean
接口,然后给出自己对象的实例化代码即可
FactoryBean表现的是一个工厂的职责。 即一个Bean A如果实现了FactoryBean接口,那么A就变成了一个工厂,根据A的名称获取到的实际上是工厂调用getObject()返回的对象,而不是A本身,如果要获取工厂A自身的实例,那么需要在名称前面加上’&'符号。
- getObject(’ name ')返回工厂中的实例
- getObject(’ &name ')返回工厂本身的实例
源码
在refresh方法的finishBeanFactoryInitialization中,是为其他还没有实例化的Bean进行实例化。preInstantiateSingletons方法来实例化单例对象。在初始化Bean实例获取Bean的时候,会判断当前BeanDefinition当前的beanName是不是FactoryBean,如果是,则会先获取FactoryBean的实例。如果该工厂Bean实现了SmartFactoryBean(一般Spring框架内部使用),则会立刻初始化工厂Bean指向的Bean。
FactoryBean——Spring的扩展点之一 - 掘金 (juejin.cn)
Bean生命周期
- 根据Bean定义创建Bean的对象
- Bean对象创建完后,设置属性值的注入
- 为当前Bean调用所有BeanPostProcessor后置处理器的初始化前的方法,此时会设置ApplicationContextAware等各种Aware
- 调用初始化方法,比如InitializingBean接口的afterPropertiesSet方法,或者配置了initMethod方法
- 为当前Bean调用所有BeanPostProcessor后置处理器的初始化后的方法
- Bean添加到单例线程池中,被容器管理
- Bean实现了DisposableBean接口,执行destory方法或调用了声明destory-method的方法
Bean创建过程
test方法----…---->refresh()
---->finishBeanFactoryInitialization()
.
---->preInstantiateSingletons()
.
---->preInstantiateSingletons()
.
---->getBean()
.
---->doGetBean()
.
----> getSingleton(beanName, new ObjectFactory()
这是一个简单的流程,可以大致看一下在容器启动的时候具体调用了哪些方法;
我们先进入doGetBean方法里面:发现其实是调用了getSingleton方法获取实例,
如果没有获取到又通过getObject()里面的 createBean(beanName, mbd, args)创建实例,总之这个实例一定要创建出来
Bean创建循环依赖
Bean在创建过程中会把自己暴露出来。一个是初始化对象之后会提前暴露处来,添加到单例工厂集合中,Bean完全实例化创建后会添加到单例对象集合中,删除单例工厂集合和暴露对象集合。暴露出来后,其他Bean就可以获取这个Bean的实例。
而在当前Bean如果依赖其他没有实例化Bean的时候,也就是@Autowire注解标注了一个没有实例化的属性。这时会在Bean初始化Bean之前(后置处理器初始化前,初始化方法,后置处理器初始化后),进行属性注入,也就是populateBean(beanName, mbd, instanceWrapper)
方法。其内部会有后置处理器AutowiredAnnotationBeanPostProcessor
来处理,检查到标注的@Autowired属性B,获取他的Bean。如果它也依赖了A,就形成了循环依赖。
如果A注入了B,B中注入了A。那么会先初始化A,暴露单例工厂自身A,注入属性的时候检查到标注了自动注入注解,则会初始化B,暴露单例工厂自身B,B进行注入属性的时候检查到依赖了A,这个时候获取A的Bean就可以走循环依赖的三级缓存,从单例工厂中获取A的Bean,并添加到暴露单例对象中。当B的Bean创建完毕后,就完成A的Bean的属性注入了,就正常创建A的。Bean创建完之后会添加到singletonObjects中,后续直接获取。
为什么需要三级缓存,通过单例工厂来创建提前Bean?
首先他俩在内存中是同一个对象,其次是为了解决AOP切面代理问题。
getEarlyBeanReference这个方法主要逻辑大概描述下如果bean被AOP切面代理则返回的是beanProxy对象,如果未被代理则返回的是原bean实例
源码
bean的获取最先是从AbstractBeanFactory.doGetBean方法中开始。第一步就是直接获取单例对象,也就是从三级缓存(三个Map)中获取,Object sharedInstance = getSingleton(beanName);
。主要是获取共享的单例Bean,也就是说共享暴露出来的。首先会从单例Bean集合(singletonObjects)中获取,获取不到就从早期暴露出Bean的集合(earlySingletonObjects)中获取,然后是从提前暴露的工厂对象中(singletonFactories)获取。如果在Bean实例集合或者提早暴露的中能获取的直接返回实例,否则看实例工厂有没有,有了就获取对象实例,并添加到暴露集合中。如果没有,最后就是空的。
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// Quick check for existing instance without full singleton lock
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
synchronized (this.singletonObjects) {
// Consistent creation of early reference within full singleton lock
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null) {
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
}
}
return singletonObject;
}
如果Bean取不到就会创建Bean
创建Bean,如果有父容器则由父容器来创建Bean,没有了,则才会用当前子容器创建Bean。
获取Bean定义,判断是否有依赖的Bean,依赖的Bean有没有创建,如果没有创建就先创建依赖Bean,也是进入这个方法中创建Bean。dependentBeanMap中定义依赖的Bean集合
依赖Bean创建完之后会创建当前Bean。创建Bean会判断是单例的,原型的,获取其他的。进入单例的判断,创建Bean就是执行的createBean方法中创建的。
// 重载方法,第二次获取单例Bean,实际上根据createBean(beanName, mbd, args);创建
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
}
});
beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
实际创建Bean的方法
内部调用Object beanInstance = doCreateBean(beanName, mbdToUse, args);
在AbstractAutowireCapableBeanFactory类中,以下是实际创建Bean的方法签名。
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
首先会根据反射或动态代理创建一个对象,将创建出来的对象构建成单例工厂,添加到三级缓存中。也就是单例工厂集合中,主要用于提前暴露自身。
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isTraceEnabled()) {
logger.trace("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
// 三级缓存那块的三个集合,添加了提早暴露Bean Map earlySingletonObjects,单例工厂singletonFactories
// SmartInstantiationAwareBeanPostProcessor.getEarlyBeanReference
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
然后会进行属性注入,也就是自动依赖注入,@Value、@Autowired的处理,如果有依赖对象,则会创建依赖的Bean。相当于又重新走了一遍创建Bean,如果这个时候发现了要注入的Bean依赖了A,就获取A这个Bean,那么A这个Bean就可以从三级缓存方法中获取。
后面,属性注入完成后,就初始化Bean的操作了。Bean初始化完成之后,就把Bean加入到一级缓存中了。后面直接从一级缓存中获取完成的Bean实例
BeanFactoryPostProcessor BeanDefinitionRegistryPostProcessor
BeanFactoryPostProcessor是在发生在bean实例化之前,BeanDefinition读取完之后。所以我们在这里可以获取到BeanDefinition,以改变他默认的实例化方式。
BeanDefinitionRegistryPostProcessor可以注册BeanDefinition。不但可以完全控制是否加入某个bean,动态加入某些bean,并且还可以控制bean的生成过程,比如像其直接注入属性等操作
实现逻辑和位置
AbstractApplicationContext类的invokeBeanFactoryPostProcessors方法就是处理实现了这两个后置处理器的类的,方法里会获取扫描到的类,并回调实现的方法。
BeanDefinitionRegistryPostProcessor扩展和BeanFactoryPostProcessor是在同一时间节点进行回调的,并且他的优先级是高于BeanFactoryPostProcessor,而他的作用是像spring容器中注册BeanDefinition。
首先是实现BeanDefinitionRegistryPostProcessor的类,会优先回调实现了PriorityOrdered接口的,然后进行排序再执行回调。然后是实现了Ordered接口的,然后排序后在执行回调,最后是其他的实现类,也会进行排序一下再执行回调。这里是直接回调postProcessBeanDefinitionRegistry方法了。等所有的都执行完了,才会统一回调postProcessBeanFactory方法。
随后才会获取实现BeanFactoryPostProcessor的类,依据顺序规则进行回调。
实现类
ApplicationContextAware ApplicationContextAwareProcessor
ApplicationContextAware接口主要用来注入容器实例的,就是ApplicationContext上下文的。
实现这个接口的类都可以通过,重写setApplicationContext方法得到参数列表上的ApplicationContext对象。
ApplicationContextAwareProcessor类是设置ApplicationContext对象的关键。他实现了BeanPostProcessor接口,重写方法postProcessBeforeInitialization里实现了其他的Spring内部对象,包括以下Aware接口。在实例化Bean(initializeBean)的时候都会执行BeanPostProcessor的操作
- EnvironmentAware
- EmbeddedValueResolverAware
- ResourceLoaderAware
- ApplicationEventPublisherAware
- MessageSourceAware
- ApplicationContextAware
- ApplicationStartupAware
在Bean初始化后调用的AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization方法里会查询全部的BeanPostProcessor实例,然后依次将当前Bean和BeanName传入执行postProcessBeforeInitialization方法。
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
invokeAwareMethods(beanName, bean);
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
// 执行所有BeanPostProcessor的postProcessBeforeInitialization方法
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null), beanName, ex.getMessage(), ex);
}
if (mbd == null || !mbd.isSynthetic()) {
// 执行所有BeanPostProcessor的postProcessAfterInitialization方法
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
@Override
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor processor : getBeanPostProcessors()) {
Object current = processor.postProcessBeforeInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
@Override
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor processor : getBeanPostProcessors()) {
Object current = processor.postProcessAfterInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
BeanPostProcessor
后置处理器,作用是在Bean对象在实例化和依赖注入完毕后,在显示调用初始化方法的前后添加我们自己的逻辑。注意是Bean实例化完毕后及依赖注入完成后触发的。
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
invokeAwareMethods(beanName, bean);
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
// 执行postProcessBeforeInitialization
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null), beanName, ex.getMessage(), ex);
}
if (mbd == null || !mbd.isSynthetic()) {
// 执行postProcessAfterInitialization
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
所有实现了BeanPostProcessor的实现类都会在每个Bean初始化的时候执行一遍。因此内部很多实现了该接口的类都会判断一下当前Bean是不是某种类型的Bean,才会执行相关操作。例如ApplicationContextAwareProcessor
子类:
- InitDestroyAnnotationBeanPostProcessor 处理初始化方法(我们初始化方法是如何执行的,如何被容器发现的,都是因为这个组件在工作,可在int-method打断点看看具体调试)
- AutowiredAnnotationBeanPostProcessor 处理自动装配
- BeanValidationPostProcessor
- ApplicationContextAwareProcessor
SmartInitializingSingleton InitializingBean
SmartInitializingSingleton
在 Spring 容器中所有单例 Bean 初始化完成后执行一些自定义的初始化逻辑。当所有单例 Bean 的依赖关系都解析完毕,并且所有单例 Bean 的实例化与初始化过程完成后,Spring 容器会自动回调 SmartInitializingSingleton
接口的实现类的 afterSingletonsInstantiated()
方法。可以在该方法中编写自己的初始化逻辑。注意,这个方法只会被调用一次。
SmartInitializingSingleton
接口的使用场景通常是在所有单例 Bean 初始化完成后,希望执行一些需要考虑所有 Bean 依赖关系的初始化逻辑,例如进行缓存预热、启动一些定时任务等操作。
preInstantiateSingletons
// 为所有单例非懒加载的Bean触发初始化后回调...调用SmartInitializingSingleton接口的afterSingletonsInstantiated方法
for (String beanName : beanNames) {
Object singletonInstance = getSingleton(beanName);
if (singletonInstance instanceof SmartInitializingSingleton smartSingleton) {
StartupStep smartInitialize = this.getApplicationStartup().start("spring.beans.smart-initialize")
.tag("beanName", beanName);
smartSingleton.afterSingletonsInstantiated();
smartInitialize.end();
}
}
事件机制
事件类型
-
ApplicationEvent 事件抽象类
-
ApplicationContextEvent 用于应用程序上下文的事件的基类
-
ContextStoppedEvent 当应用程序上下文停止时引发的事件
-
ContextRefreshedEvent 在ApplicationContext被初始化或刷新时引发的事件
-
ContextStartedEvent 当应用程序上下文启动时引发的事件
-
ContextClosedEvent 当应用程序上下文关闭时引发的事件
发布订阅,事件组播器
-
ApplicationEventMulticaster 接口由可以管理多个ApplicationListener对象的对象实现,并向它们发布事件
-
AbstractApplicationEventMulticaster 提供基本的侦听器注册功能
-
SimpleApplicationEventMulticaster 提供基本的侦听器注册功能,忽略它不感兴趣的事件
-
org.springframework.context.ApplicationEventPublisherAware 任何对象希望被其运行的ApplicationEventPublisher(通常是ApplicationContext)通知的任何对象实现的接口
-
EventPublicationInterceptor 事件发布拦截器
-
ApplicationEventPublisher 封装事件发布功能的接口
监听器
- ApplicationListener
- GenericApplicationListener
- ApplicationListenerMethodAdapter
源码
初始化组播器
组播器收集所有监听器,并在接收到事件响应后匹配对应的监听器进行处理。
refresh方法中的initApplicationEventMulticaster方法会初始化事件组播器。首先会从BeanFactory中找是否已经有自定义的id为applicationEventMulticaster的Bean,有的话把它作为事件组播器。否则就初始化一个类型为SimpleApplicationEventMulticaster的
protected void initApplicationEventMulticaster() {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
this.applicationEventMulticaster =
beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
if (logger.isTraceEnabled()) {
logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
}
}
else {
this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
if (logger.isTraceEnabled()) {
logger.trace("No '" + APPLICATION_EVENT_MULTICASTER_BEAN_NAME + "' bean, using " +
"[" + this.applicationEventMulticaster.getClass().getSimpleName() + "]");
}
}
}
注册监听器
refresh()方法的registerListeners()方法中,用于注册所有监听器。
找到所有实现了ApplicationListener接口的监听器类,并将其Bean名称添加到ApplicationEventMulticaster组播器实例的applicationListenerBeans集合中。
protected void registerListeners() {
// 注册 已在容器中的(this.applicationListeners里的) 且已被初始化的ApplicationListener
for (ApplicationListener<?> listener : getApplicationListeners()) {
getApplicationEventMulticaster().addApplicationListener(listener);
}
// Do not initialize FactoryBeans here: We need to leave all regular beans
// uninitialized to let post-processors apply to them!
String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
for (String listenerBeanName : listenerBeanNames) {
getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
}
// 发布早期应用程序事件,现在我们终于有了多路广播...
Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
this.earlyApplicationEvents = null;
if (!CollectionUtils.isEmpty(earlyEventsToProcess)) {
for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
getApplicationEventMulticaster().multicastEvent(earlyEvent);
}
}
}
EventListenerMethodProcessor处理标注EventListener注解的方法为监听器并注册
EventListenerMethodProcessor类是查找监听器的,它实现了BeanFactoryPostProcessor和SmartInitializingSingleton来做这件事。这个类的Bean名为org.springframework.context.event.internalEventListenerProcessor
,最初源自AnnotationConfigUtils.registerAnnotationConfigProcessors。他在代码第一行new上下文的时候的构造函数里就已经加到BeanDefinition中了。
因为实现了BeanFactoryPostProcessor,所以它早在invokeBeanFactoryPostProcessors的时候就已经创建了Bean。然后在refresh()中的finishBeanFactoryInitialization()中才开始执行afterSingletonsInstantiated()方法。
processBean()方法中具体处理了相关内容。扫描到有标注EventListener注解的类,根据目标类Class,方法Method和Bean名称,使用事件监听工厂创建监听器对象。并将其添加到SpringContext上下文的监听器列表和ApplicationEventMulticaster组播器中的集合中
// 有方法标注了,则根据监听所在方法注册成监听器对象,添加到组播器中
ConfigurableApplicationContext context = this.applicationContext;
Assert.state(context != null, "No ApplicationContext set");
// 获取默认的监听器工厂
List<EventListenerFactory> factories = this.eventListenerFactories;
Assert.state(factories != null, "EventListenerFactory List not initialized");
// 循环多个监听方法和多个监听器工厂,根据不同的监听器工厂创建多个监听器对象
for (Method method : annotatedMethods.keySet()) {
for (EventListenerFactory factory : factories) {
// 根据监听器工厂判断被监听非方法是否满足要求
if (factory.supportsMethod(method)) {
// 把这个方法转为一个可以执行的方法(主要和访问权限有关)
Method methodToUse = AopUtils.selectInvocableMethod(method, context.getType(beanName));
// 根据监听器工厂创建监听器实例
ApplicationListener<?> applicationListener =
factory.createApplicationListener(beanName, targetType, methodToUse);
// 如果是ApplicationListenerMethodAdapter实例,则进行初始化。默认工厂DefaultEventListenerFactory创建的就是这个实例
if (applicationListener instanceof ApplicationListenerMethodAdapter) {
((ApplicationListenerMethodAdapter) applicationListener).init(context, this.evaluator);
}
// 将监听器实例添加到spring上下,同时会添加到组播器中
context.addApplicationListener(applicationListener);
break;
}
}
}
发布事件
context.publishEvent(new AddEvent("-123"));
其中 invokeListener 方法中就调用了ApplicationEvent的onApplicationEvent方法了。
protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
Assert.notNull(event, "Event must not be null");
// 将推送的参数转换为ApplicationEvent
ApplicationEvent applicationEvent;
if (event instanceof ApplicationEvent applEvent) {
applicationEvent = applEvent;
}
else {
applicationEvent = new PayloadApplicationEvent<>(this, event, eventType);
if (eventType == null) {
eventType = ((PayloadApplicationEvent<?>) applicationEvent).getResolvableType();
}
}
// Multicast right now if possible - or lazily once the multicaster is initialized
if (this.earlyApplicationEvents != null) {
this.earlyApplicationEvents.add(applicationEvent);
}
else {
// 执行事件的推送操作
getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
}
// 如果当前容器有父容器,则也会调用父容器的事件推送
if (this.parent != null) {
if (this.parent instanceof AbstractApplicationContext abstractApplicationContext) {
abstractApplicationContext.publishEvent(event, eventType);
}
else {
this.parent.publishEvent(event);
}
}
}
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
Executor executor = getTaskExecutor();
for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
if (executor != null) {
executor.execute(() -> invokeListener(listener, event));
}
else {
invokeListener(listener, event);
}
}
}
在循环监听器中获取监听器列表方法使用了缓存的功能getApplicationListeners(event, type)
【Spring源码】事件监听机制全解_spring事件监听获取返回值-CSDN博客
动态注册Bean
可根据注解的方式,动态注入bean,而不需要显式根据Componment等注解。一般都是第三方库采用这种方式,比如Mybatis,使用的MapperScannerRegistrar类,对应的依赖注解就是@MapperScan。
使用ImportBeanDefinitionRegistrar接口可以实现,一般结合@Import注解和@Configuration注解。所有实现了该接口的类的都会被ConfigurationClassPostProcessor处理,ConfigurationClassPostProcessor实现了BeanFactoryPostProcessor接口,所以ImportBeanDefinitionRegistrar中动态注册的bean是优先与依赖其的bean初始化的,也能被aop、validator等机制处理。
动态注册Bean,其目的就是将扫描到的Bean添加到BeanFactory实例 IOC容器中,一般添加为单例Bean。
示例
以类似OpenFeign的Http调用的方式的示例来使用这个。实现细节为定义一个接口类为Http接口集合,每个方法为请求方法,根据请求注解配置相关请求地址等属性进行远程调用。即将接口类注入到Ioc容器中,依据动态代理的方式代理接口类,代理类处理每个方法进行业务处理。
而当前实现动态注册Bean只是将在Http接口集合所在的类注册Bean,通过注解扫描的方式动态注册。
我们需要定义如下类:
- 定义类似@MapperScan注解的开关扫描注解, EnableHttpUtil.java
- 定义的MapperScan注解中引入的MapperScannerRegistrar类,也就是实现ImportBeanDefinitionRegistrar接口类,此处为 HttpBeanRegistrar.java
- 定义@HttpUtil注解,被该注解标注的类就是需要动态注册的Bean。当然也可以不扫描被该注解标注的,只要是根据扫描配置类扫描到就行。
- 以上其实就可以完成动态注册Bean了。但实际注册Bean之后,后续还要处理更多的业务。比如扫描到Mapper接口类的方法可以直接调用。
- 接下来类似OpenFeign的方式,定义方法上的调用注解HttpRequest.java
- 业务处理类,发送http请求类 DemoHttpHandler.java
- 定义某个被扫描业务使用接口, IRequestDemo.java
注解类
// 开关扫描类
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Import(HttpBeanRegistrar.class)
public @interface EnableHttpUtil {
}
// 请求方法类型枚举
public enum HTTPMethod {
GET,POST,PUT,DELETE
}
// 请求方法注解,标注在方法上
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface HttpRequest {
HTTPMethod httpMethod() default HTTPMethod.GET;
String url();
}
// Http工具类,标注在类上,类似FeignClient
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
public @interface HttpUtil {
}
HttpBeanRegistrar
/**
* 动态Bean注入类,在ConfigurationClassPostProcessor中会被处理到
*/
public class HttpBeanRegistrar implements ImportBeanDefinitionRegistrar,
ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, BeanClassLoaderAware {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
registerHttpRequest(registry);
}
/**
* 动态注册Bean方法
*
* @param registry
*/
private void registerHttpRequest(BeanDefinitionRegistry registry) {
// 构建扫描类
ClassPathScanningCandidateComponentProvider classPathBeanDefinitionScanner = getClassScanner();
classPathBeanDefinitionScanner.setResourceLoader(this.resourceLoader);
// 设置只扫描HttpUtil注解的类
AnnotationTypeFilter annotationTypeFilter = new AnnotationTypeFilter(HttpUtil.class);
classPathBeanDefinitionScanner.addIncludeFilter(annotationTypeFilter);
// 定义扫描包
String basePackage = "com.cgq.dynamicbean";
Set<BeanDefinition> candidateComponents = classPathBeanDefinitionScanner.findCandidateComponents(basePackage);
for (BeanDefinition beanDefinition : candidateComponents) {
if (beanDefinition instanceof AnnotatedBeanDefinition) {
registerBeans(((AnnotatedBeanDefinition) beanDefinition));
}
}
}
/**
* 构造Class扫描器,设置了只扫描顶级接口,不扫描内部类
*
* @return
*/
private ClassPathScanningCandidateComponentProvider getClassScanner() {
return new ClassPathScanningCandidateComponentProvider(false, this.environment) {
@Override
protected boolean isCandidateComponent(
AnnotatedBeanDefinition beanDefinition) {
if (beanDefinition.getMetadata().isInterface()) {
try {
Class<?> target = ClassUtils.forName(
beanDefinition.getMetadata().getClassName(),
classLoader);
return !target.isAnnotation();
} catch (Exception ex) {
ex.printStackTrace();
}
}
return false;
}
};
}
/**
* 注册Bean方法,根据Bean定义对象获取Bean的类型,并创建该对象的代理
*
* @param beanDefinition
*/
private void registerBeans(AnnotatedBeanDefinition beanDefinition) {
String className = beanDefinition.getBeanClassName();
((DefaultListableBeanFactory) this.beanFactory).registerSingleton(className, createProxy(beanDefinition));
}
/**
* 创建代理类,内部处理请求Http的逻辑
*
* @param beanDefinition
* @return
*/
private Object createProxy(AnnotatedBeanDefinition beanDefinition) {
try {
AnnotationMetadata annotationMetadata = beanDefinition.getMetadata();
Class<?> target = Class.forName(annotationMetadata.getClassName());
InvocationHandler invocationHandler = createInvocationHandler();
Object proxy = Proxy.newProxyInstance(HttpRequest.class.getClassLoader(), new Class[]{target}, invocationHandler);
return proxy;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
private InvocationHandler createInvocationHandler() {
return new InvocationHandler() {
private DemoHttpHandler demoHttpHandler = new DemoHttpHandler();
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return demoHttpHandler.handle(method);
}
};
}
private ResourceLoader resourceLoader;
private BeanFactory beanFactory;
private ClassLoader classLoader;
private Environment environment;
@Override
public void setResourceLoader(ResourceLoader resourceLoader) {
this.resourceLoader = resourceLoader;
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
@Override
public void setBeanClassLoader(ClassLoader classLoader) {
this.classLoader = classLoader;
}
@Override
public void setEnvironment(Environment environment) {
this.environment = environment;
}
}
DemoHttpHandler
/**
* 定义业务处理类来处理注解标注的地址,并进行真实的http请求
*/
public class DemoHttpHandler {
/**
* 实际业务调用处理
* @param method
* @return
*/
public HttpResult<?> handle(Method method) {
HttpRequest request = method.getAnnotation(HttpRequest.class);
String url = request.url();
String methodName = request.httpMethod().name();
String str = String.format("http request: url=%s and method=%s", url, methodName);
return new HttpResult<String>(str, 200);
}
}
IRequestDemo
@HttpUtil
public interface IRequestDemo {
//调用test1时,会对http://abc.com发送get请求
@HttpRequest(url = "http://abc.com")
HttpResult<String> test1();
//调用test2时,会对http://test2.com发送post请求
@HttpRequest(url = "http://test2.com")
HttpResult<String> test2();
}
HttpResult
public class HttpResult<T> {
private String result;
private int status;
public HttpResult() {
}
public HttpResult(String result, int status) {
this.result = result;
this.status = status;
}
@Override
public String toString() {
return "HttpResult{" +
"result='" + result + '\'' +
", status=" + status +
'}';
}
}
Application
@EnableHttpUtil
@SpringBootApplication
public class DynamicBeanImportApplication {
public static void main(String[] args) {
ConfigurableApplicationContext run = SpringApplication.run(DynamicBeanImportApplication.class, args);
IRequestDemo bean = run.getBean(IRequestDemo.class);
HttpResult<String> stringHttpResult = bean.test1();
System.out.println(stringHttpResult);
}
}
动态注册bean,Spring官方套路:使用ImportBeanDefinitionRegistrar - 知乎 (zhihu.com)
依赖注入 DI 控制反转Ioc
Ioc
Ioc意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制。
- 谁控制谁,控制什么:传统Java SE程序设计,我们直接在对象内部通过new进行创建对象,是程序主动去创建依赖对象;而IoC是有专门一个容器来创建这些对象,即由Ioc容器来控制对 象的创建;*谁控制谁?当然是IoC 容器控制了对象;控制什么?那就是主要控制了外部资源获取(不只是对象包括比如文件等)*。
- 为何是反转,哪些方面反转了:有反转就有正转,传统应用程序是由我们自己在对象中主动控制去直接获取依赖对象,也就是正转;而反转则是由容器来帮忙创建及注入依赖对象;为何是反转?因为由容器帮我们查找及注入依赖对象,对象只是被动的接受依赖对象,所以是反转;哪些方面反转了?依赖对象的获取被反转了。
是一种思想,一个重要的面向对象编程的法则,它能指导我们如何设计出松耦合、更优良的程序
DI
组件之间依赖关系由容器在运行期决定,形象的说,即由容器动态的将某个依赖关系注入到组件之中。**依赖注入的目的并非为软件系统带来更多功能,而是为了提升组件重用的频率,并为系统搭建一个灵活、可扩展的平台。**通过依赖注入机制,我们只需要通过简单的配置,而无需任何代码就可指定目标需要的资源,完成自身的业务逻辑,而不需要关心具体的资源来自何处,由谁实现。
总结
IoC和DI由什么关系呢?其实它们是同一个概念的不同角度描述,由于控制反转概念比较含糊(可能只是理解为容器控制对象这一个层面,很难让人想到谁来维护对象关系),所以2004年大师级人物Martin Fowler又给出了一个新的名字:“依赖注入”,相对IoC 而言,“依赖注入”明确描述了“被注入对象依赖IoC容器配置依赖对象”。
所以控制反转IoC(Inversion of Control)是说创建对象的控制权进行转移,以前创建对象的主动权和创建时机是由自己把控的,而现在这种权力转移到第三方,比如转移交给了IoC容器,它就是一个专门用来创建对象的工厂,你要什么对象,它就给你什么对象,有了 IoC容器,依赖关系就变了,原先的依赖关系就没了,它们都依赖IoC容器了,通过IoC容器来建立它们之间的关系。
标签:初始化,Object,实例,Spring,beanName,接口,Bean,源码,方法 From: https://blog.csdn.net/qq_34656606/article/details/142865168