SpringBoot——bean解析
发布时间:2023-04-06 14:51:41 312
相关标签: # less# java# spring# java# 软件
IOC思想解析
IOC(控制反转):全称为:Inverse of Control。从字面上理解就是控制反转了,将对在自身对象中的一个内置对象的控制反转,反转后不再由自己本身的对象进行控制这个内置对象的创建,而是由第三方系统去控制这个内置对象的创建。
DI(依赖注入):全称为Dependency Injection,意思自身对象中的内置对象是通过注入的方式进行创建。
那么IOC和DI这两者又是什么关系呢? IOC就是一种软件设计思想,DI是这种软件设计思想的一个实现。 把本来在类内部控制的对象,反转到类外部进行创建后注入,不再由类本身进行控制,这就是IOC的本质。
xml方式配置bean
利用标签进行注入
<bean id="..." class="...">
<constructor-arg index="0" value="..."></constructor-arg>
<property name="..." value="..."></property>
<property name="...">
<list>
<value>...</value>
<value>...</value>
</list>
</property>
</bean>
优点:
- 低耦合
- 对象关系清晰
- 集中管理
缺点:
- 配置繁琐
- 开发效率较低
- 文件解析耗时
注解方式配置bean
1、使用@Component声明
2、配置类中使用@Bean
3、实现FactoryBean
@Component
public class MyCat implements FactoryBean {
@Override
public Animal getObject() throws Exception {
return new Cat();
}
@Override
public Class<?> getObjectType() {
return Animal.class;
}
}
4、实现BeanDefinitionRegistryPostProcessor
@Component
public class MyBeanRegister implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {
RootBeanDefinition rootBeanDefinition = new RootBeanDefinition();
rootBeanDefinition.setBeanClass(Dog.class);
beanDefinitionRegistry.registerBeanDefinition("dog",rootBeanDefinition);
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
}
}
5、实现ImportBeanDefinitionRegistry
public class MyBeanImport implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
RootBeanDefinition rootBeanDefinition = new RootBeanDefinition();
rootBeanDefinition.setBeanClass(Bird.class);
registry.registerBeanDefinition("bird",rootBeanDefinition);
}
}
@Component
public class HelloService {
@Autowired
@Qualifier("bird")
private Animal animal;
public String hello(){
return animal.getName();
}
}
@RunWith(SpringRunner.class)
@SpringBootTest
@Import(MyBeanImport.class)
public class ApplicationTest {
@Autowired
private HelloService helloService;
@Test
public void test(){
System.out.println(helloService.hello());
}
}
优点:
- 使用简单
- 开发效率高
- 高内聚
缺点:
- 配置分散
- 对象关系不清晰
- 修改配置需要重新编译工程
refresh方法解析
完成了SpringApplication的run方法:
public ConfigurableApplicationContext run(String... args) {
// 计时工具
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection exceptionReporters = new ArrayList();
this.configureHeadlessProperty();
// 第一步:获取并启动监听器
SpringApplicationRunListeners listeners = this.getRunListeners(args);
listeners.starting();
Collection exceptionReporters;
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
// 第二步:根据SpringApplicationRunListeners以及参数来准备环境
ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
this.configureIgnoreBeanInfo(environment);
// 准备Banner打印器 - 就是启动Spring Boot的时候打印在console上的ASCII艺术字体
Banner printedBanner = this.printBanner(environment);
// 第三步:创建Spring容器
context = this.createApplicationContext();
exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context);
// 第四步:Spring容器前置处理
this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
// 第五步:刷新容器
this.refreshContext(context);
// 第六步:Spring容器后置处理
this.afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
(new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
}
// 第七步:发出结束执行的事件
listeners.started(context);
this.callRunners(context, applicationArguments);
} catch (Throwable var10) {
this.handleRunFailure(context, var10, exceptionReporters, listeners);
throw new IllegalStateException(var10);
}
try {
// 第八步:执行Runners
listeners.running(context);
// 返回容器
return context;
} catch (Throwable var9) {
this.handleRunFailure(context, var9, exceptionReporters, (SpringApplicationRunListeners)null);
throw new IllegalStateException(var9);
}
}
- 第一步:获取并启动监听器
- 第二步:根据SpringApplicationRunListeners以及参数来准备环境
- 第三步:创建Spring容器
- 第四步:Spring容器前置处理
- 第五步:刷新容器
- 第六步:Spring容器后置处理
- 第七步:发出结束执行的事件
- 第八步:执行Runners
这里从创建Spring容器说起:
context = createApplicationContext();
继续跟进该方法:
protected ConfigurableApplicationContext createApplicationContext() {
Class<?> contextClass = this.applicationContextClass;
if (contextClass == null) {
try {
switch (this.webApplicationType) {
case SERVLET:
contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
break;
case REACTIVE:
contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
break;
default:
contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
}
}
catch (ClassNotFoundException ex) {
throw new IllegalStateException(
"Unable create a default ApplicationContext, " + "please specify an ApplicationContextClass",
ex);
}
}
return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
}
这里创建容器的类型 还是根据webApplicationType进行判断的,该类型为SERVLET类型,所以会通过反射装载对应的字节码,也就是AnnotationConfigServletWebServerApplicationContext
第四步:Spring容器前置处理
这一步主要是在容器刷新之前的准备动作。包含一个非常关键的操作:将启动类注入容器,为后续开启自动化配置奠定基础。
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
继续跟进该方法:
private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) { //设置容器环境,包括各种变量 context.setEnvironment(environment); //执行容器后置处理 postProcessApplicationContext(context); //执行容器中的ApplicationContextInitializer(包括 spring.factories和自定义的实例) applyInitializers(context); //发送容器已经准备好的事件,通知各监听器 listeners.contextPrepared(context); if (this.logStartupInfo) { logStartupInfo(context.getParent() == null); logStartupProfileInfo(context); } // Add boot specific singleton beans //注册启动参数bean,这里将容器指定的参数封装成bean,注入容器 ConfigurableListableBeanFactory beanFactory = context.getBeanFactory(); beanFactory.registerSingleton("springApplicationArguments", applicationArguments); //设置banner if (printedBanner != null) { beanFactory.registerSingleton("springBootBanner", printedBanner); } if (beanFactory instanceof DefaultListableBeanFactory) { ((DefaultListableBeanFactory) beanFactory) .setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding); } // Load the sources //获取我们的启动类指定的参数,可以是多个 Set<Object> sources = getAllSources(); Assert.notEmpty(sources, "Sources must not be empty"); //加载我们的启动类,将启动类注入容器 load(context, sources.toArray(new Object[0])); //发布容器已加载事件。 listeners.contextLoaded(context); }
文章来源: https://blog.51cto.com/u_14014612/6007656
特别声明:以上内容(图片及文字)均为互联网收集或者用户上传发布,本站仅提供信息存储服务!如有侵权或有涉及法律问题请联系我们。
举报