当前位置: 首页 > news >正文

郑州网站优化的微博_腾讯微博企业网站建设策划书范文

郑州网站优化的微博_腾讯微博,企业网站建设策划书范文,网站开发成功案例,南宁工程建设信息网一、引言 在Java企业级开发领域#xff0c;Spring Boot凭借其简洁、快速、高效的特点#xff0c;迅速成为了众多开发者的首选框架。Spring Boot通过自动配置、起步依赖等特性#xff0c;极大地简化了Spring应用的搭建和开发过程。而在Spring Boot的众多核心特性中#xff…一、引言 在Java企业级开发领域Spring Boot凭借其简洁、快速、高效的特点迅速成为了众多开发者的首选框架。Spring Boot通过自动配置、起步依赖等特性极大地简化了Spring应用的搭建和开发过程。而在Spring Boot的众多核心特性中Bean的管理与解析无疑是重中之重。本文将从IOC思想出发深入探讨Spring Boot 3中Bean的解析过程包括XML和注解两种配置方式、refresh方法的解析以及Bean实例化过程。 说明本文分析使用的Spring Boot源码版本为3.3.5 二、IOC思想 IOCInversion of Control控制反转是Spring框架的核心思想之一。它意味着对象之间的关系不再由传统的程序控制而是由Spring容器来统一管理对象的创建、协调和销毁。通过这种方式对象的依赖关系被解耦提高了代码的可维护性和可扩展性。 在Spring Boot 3中IOC容器负责实例化、配置和组装Bean。Bean是Spring框架中构成应用程序的基本组件Spring容器通过配置文件或注解等方式来定义和管理这些Bean。 三、XML方式配置Bean介绍 在Spring Boot中虽然推荐使用基于Java的配置例如使用Configuration和Bean注解但XML配置仍然是支持的特别是对于需要与遗留系统集成或偏好XML配置的场景。以下是使用XML配置bean和注入bean的几种方式 无参构造有参构造静态工厂方法实例工厂方法 1. 无参构造 XML配置 beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd!-- 通过无参构造方法创建bean --bean idmyBean classcom.example.MyBean//beansJava类 package com.example;public class MyBean {public void doSomething() {System.out.println(Doing something in MyBean);} }2. 有参构造 XML配置 beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd!-- 通过有参构造方法创建bean使用constructor-arg指定参数 --bean idmyBeanWithArgs classcom.example.MyBeanWithArgsconstructor-arg valueArgument1/constructor-arg valueArgument2//bean/beansJava类 package com.example;public class MyBeanWithArgs {private String arg1;private String arg2;public MyBeanWithArgs(String arg1, String arg2) {this.arg1 arg1;this.arg2 arg2;}public void doSomething() {System.out.println(Doing something with arguments: arg1 , arg2);} }3. 静态工厂方法 XML配置 beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd!-- 通过静态工厂方法创建bean --bean idmyStaticFactoryBean classcom.example.MyStaticFactoryBean factory-methodcreateMyBean//beansJava类 package com.example;public class MyStaticFactoryBean {public static MyBean createMyBean() {return new MyBean();} }class MyBean {public void doSomething() {System.out.println(Doing something in MyBean created by static factory);} }4. 实例工厂方法 XML配置 beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd!-- 先创建工厂bean --bean idmyInstanceFactoryBean classcom.example.MyInstanceFactoryBean/!-- 通过实例工厂方法创建bean使用factory-bean和factory-method属性 --bean idmyBeanFromFactory factory-beanmyInstanceFactoryBean factory-methodcreateMyBean//beansJava类 package com.example;public class MyInstanceFactoryBean {public MyBean createMyBean() {return new MyBean();} }class MyBean {public void doSomething() {System.out.println(Doing something in MyBean created by instance factory);} }5. 测试 在测试类上使用ContextConfiguration注解并指定要加载的配置文件或配置类的位置。例如如果你有一个名为applicationContext.xml的XML配置文件可以这样写 SpringBootTest ContextConfiguration(locations {classpath:applicationContext.xml}) public class MyBeanTest {Autowiredprivate MyBean myBean;Testpublic void testMyBean() {// 调用myBean的方法并进行断言myBean.doSomething();// 根据需要添加更多的断言来验证myBean的行为} }在这些示例中XML配置文件定义了bean的创建方式和依赖注入。Java类则定义了bean的逻辑。请注意对于现代Spring Boot应用通常推荐使用基于Java的配置因为它提供了更强大的类型检查和重构支持。然而在需要与遗留系统或特定库集成时XML配置仍然是一个有用的选项。 四、注解方式配置Bean介绍 在Spring Boot中有多种方式可以配置和注册Bean。下面介绍五种方式 ComponentConfigurationBean实现FactoryBean实现BeanDefinitionRegistryPostProcessor实现ImportBeanDefinitionRegistrar 1. 使用 Component 注解 Component 注解用于自动检测和注册Bean。通常用于类级别。以下几种注解都是同类型 Component用于标识一个普通的Spring Bean组件。 Service用于标识业务逻辑层的Bean。 Repository用于标识数据访问层的Bean。 Controller用于标识控制层的Bean。 import org.springframework.stereotype.Component;Component public class MyComponent {public void doSomething() {System.out.println(Doing something in MyComponent);} }使用Autowired或者Resource注解在其他类中注入。 2. 使用 Configuration 和 Bean 注解 Configuration 注解用于定义配置类Bean 注解用于在配置类中声明Bean。 import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration;Configuration public class MyConfiguration {Beanpublic MyBean myBean() {return new MyBean();} }class MyBean {public void doSomething() {System.out.println(Doing something in MyBean);} }在这个例子中MyConfiguration是一个配置类其中Bean注解的方法myBean用于声明一个Bean。当Spring容器启动时它会调用这个方法并注册返回的Bean实例。 使用Autowired或者Resource注解在其他类中注入。 3. 实现 FactoryBean 接口 FactoryBean 接口允许你自定义Bean的创建过程。 import org.springframework.beans.factory.FactoryBean; import org.springframework.stereotype.Component;Component public class MyFactoryBean implements FactoryBeanMyBean {Overridepublic MyBean getObject() throws Exception {return new MyBean();}Overridepublic Class? getObjectType() {return MyBean.class;}Overridepublic boolean isSingleton() {return true;} }class MyBean {public void doSomething() {System.out.println(Doing something in MyBean created by MyFactoryBean);} }使用Autowired或者Resource注解在其他类中注入。 4. 实现 BeanDefinitionRegistryPostProcessor 接口 BeanDefinitionRegistryPostProcessor 接口允许你在Spring容器启动时动态地添加、修改或删除Bean定义。 import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.BeanDefinitionRegistry; import org.springframework.beans.factory.config.BeanDefinitionRegistryPostProcessor; import org.springframework.context.annotation.Configuration; import org.springframework.stereotype.Component;Component public class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {Overridepublic void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {BeanDefinition beanDefinition new RootBeanDefinition(MyDynamicBean.class);registry.registerBeanDefinition(myDynamicBean, beanDefinition);}Overridepublic void postProcessBeanFactory(org.springframework.beans.factory.config.ConfigurableListableBeanFactory beanFactory) throws BeansException {// No-op} }class MyDynamicBean {public void doSomething() {System.out.println(Doing something in MyDynamicBean);} }使用Autowired或者Resource注解在其他类中注入。 5. 实现 ImportBeanDefinitionRegistrar 接口 ImportBeanDefinitionRegistrar 接口允许你在使用 Import 注解时动态地注册Bean定义。 首先创建一个实现 ImportBeanDefinitionRegistrar 的类 import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; import org.springframework.core.type.AnnotationMetadata;public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {Overridepublic void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {BeanDefinition beanDefinition new RootBeanDefinition(MyImportedBean.class);registry.registerBeanDefinition(myImportedBean, beanDefinition);} }class MyImportedBean {public void doSomething() {System.out.println(Doing something in MyImportedBean);} }然后在配置类中使用 Import 注解导入这个注册器 import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import;Configuration Import(MyImportBeanDefinitionRegistrar.class) public class MyImportingConfiguration {// No additional bean definitions needed here }五、XML配置方式和注解配置方式对比 使用XML配置Bean和使用注解方式是Spring框架中两种常见的配置方式它们各有优缺点。 XML配置Bean的优缺点 优点 集中式管理XML配置文件是集中式的可以方便地对所有Bean进行统一管理不需要和代码绑定降低了类之间的耦合度。清晰明了XML配置方式能够清晰地展示对象之间的关系和业务类之间的调用使得配置信息一目了然。易于扩展XML配置方式具有良好的扩展性可以通过添加新的XML文件或修改现有文件来扩展配置。与其他系统交互方便XML作为一种标准的数据交换格式使得Spring应用可以方便地与其他系统进行数据交互和共享。 缺点 解析开销大XML配置文件需要解析这会占用一定的系统资源可能会影响应用程序的性能。维护成本高XML配置文件与代码分离需要同时维护代码和配置文件增加了维护成本。类型不安全XML配置文件中的配置信息在编译期间无法验证其正确性只能在运行时发现错误这增加了排查问题的难度。不支持复杂的依赖注入XML配置方式在处理复杂的依赖注入关系时可能不够灵活和直观。 注解方式配置Bean的优缺点 优点 简化配置注解方式将配置信息直接写在代码中简化了配置文件降低了维护成本。 类型安全注解方式可以在编译期间验证配置信息的正确性减少了运行时错误的可能性。 提高开发效率注解方式使得配置信息与代码紧密结合开发者可以更快地理解和修改配置提高了开发效率。 支持复杂的依赖注入注解方式可以更灵活和直观地处理复杂的依赖注入关系。 缺点 修改麻烦如果需要对注解进行修改通常需要重新编译整个项目这可能会增加开发周期。可读性较差注解方式将配置信息嵌入代码中可能会降低代码的可读性特别是当注解较多时。可能引入潜在问题如果注解使用不当可能会引入一些潜在的问题如循环依赖、配置错误等。 六、refresh方法解析 Spring Boot依赖于Spring。Bean的管理和实例化是在Spring的org.springframework.context.support.AbstractApplicationContext#refresh方法完成的。 在Spring Boot 3中refresh方法是Spring容器初始化的核心步骤之一。当Spring容器创建后它会调用refresh方法来完成一系列的配置和初始化工作。 通过上图可以看到Spring Boot启动时会调用Spring的org.springframework.context.support.AbstractApplicationContext#refresh方法加载Bean。 下面是refresh方法的源码说明。 核心内容是 加载或刷新配置的持久化表示到内存该配置可能来自基于Java的配置、XML文件、属性文件、关系数据库模式或其他格式。 由于这是一个启动方法如果失败它应该销毁已经创建的单例以避免资源悬空。换句话说调用此方法后要么所有单例都被实例化要么根本没有单例被实例化。 该方法的源码如下 Overridepublic void refresh() throws BeansException, IllegalStateException {this.startupShutdownLock.lock();try {this.startupShutdownThread Thread.currentThread();StartupStep contextRefresh this.applicationStartup.start(spring.context.refresh);// Prepare this context for refreshing.prepareRefresh();// Tell the subclass to refresh the internal bean factory.ConfigurableListableBeanFactory beanFactory obtainFreshBeanFactory();// Prepare the bean factory for use in this context.prepareBeanFactory(beanFactory);try {// Allows post-processing of the bean factory in context subclasses.postProcessBeanFactory(beanFactory);StartupStep beanPostProcess this.applicationStartup.start(spring.context.beans.post-process);// Invoke factory processors registered as beans in the context.invokeBeanFactoryPostProcessors(beanFactory);// Register bean processors that intercept bean creation.registerBeanPostProcessors(beanFactory);beanPostProcess.end();// Initialize message source for this context.initMessageSource();// Initialize event multicaster for this context.initApplicationEventMulticaster();// Initialize other special beans in specific context subclasses.onRefresh();// Check for listener beans and register them.registerListeners();// Instantiate all remaining (non-lazy-init) singletons.finishBeanFactoryInitialization(beanFactory);// Last step: publish corresponding event.finishRefresh();}catch (RuntimeException | Error ex ) {if (logger.isWarnEnabled()) {logger.warn(Exception encountered during context initialization - cancelling refresh attempt: ex);}// Destroy already created singletons to avoid dangling resources.destroyBeans();// Reset active flag.cancelRefresh(ex);// Propagate exception to caller.throw ex;}finally {contextRefresh.end();}}finally {this.startupShutdownThread null;this.startupShutdownLock.unlock();}}refresh方法的主要步骤包括 1、prepareRefresh为刷新操作做准备 设置容器的启动时间和状态撤销关闭状态初始化属性设置检查必备属性是否存在等 2、obtainFreshBeanFactory 设置BeanFactory序列化ID获取新的BeanFactory实例 3、prepareBeanFactory 对BeanFactory进行配置如设置类加载器、忽略的依赖等添加后置处理器设置忽略的自动装配接口注册一些组件 4、postProcessBeanFactory允许上下文子类对BeanFactory进行后置处理。 5、invokeBeanFactoryPostProcessors调用已注册的BeanFactoryPostProcessor实现。 调用BeanDefinitionRegistryPostProcessor实现向容器内添加Bean定义调用BeanFactoryPostProcessor实现向容器内Bean的定义添加属性 6、registerBeanPostProcessors注册BeanPostProcessor实现用于拦截Bean的创建过程。 找到BeanPostProcessor的实现排序后注册进容器 7、initMessageSource初始化国际化相关的属性。 8、initApplicationEventMulticaster初始化事件多播器。 9、onRefresh这是一个空实现留给子类来创建Web容器等特定操作。 10、registerListeners将事件监听器注册到事件多播器中。 添加容器内的事件监听器到事件多播器派发早期事件 11、finishBeanFactoryInitialization实例化所有剩余的非懒加载单例Bean。 12、finishRefresh完成刷新操作如发布刷新事件、清空缓存等。 初始化生命周期处理器调用生命周期处理器onRefresh方法发布ContextRefreshedEvent事件 七、refresh方法中的Bean实例化解析 在refresh方法的finishBeanFactoryInitialization步骤中Spring容器会实例化所有剩余的非懒加载单例Bean。下面是该方法的源码 protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {// Initialize conversion service for this context.if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {beanFactory.setConversionService(beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));}// Register a default embedded value resolver if no BeanFactoryPostProcessor// (such as a PropertySourcesPlaceholderConfigurer bean) registered any before:// at this point, primarily for resolution in annotation attribute values.if (!beanFactory.hasEmbeddedValueResolver()) {beanFactory.addEmbeddedValueResolver(strVal - getEnvironment().resolvePlaceholders(strVal));}// Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.String[] weaverAwareNames beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);for (String weaverAwareName : weaverAwareNames) {try {beanFactory.getBean(weaverAwareName, LoadTimeWeaverAware.class);}catch (BeanNotOfRequiredTypeException ex) {if (logger.isDebugEnabled()) {logger.debug(Failed to initialize LoadTimeWeaverAware bean weaverAwareName due to unexpected type mismatch: ex.getMessage());}}}// Stop using the temporary ClassLoader for type matching.beanFactory.setTempClassLoader(null);// Allow for caching all bean definition metadata, not expecting further changes.beanFactory.freezeConfiguration();// Instantiate all remaining (non-lazy-init) singletons.beanFactory.preInstantiateSingletons();}上面代码逻辑如下 1、初始化转换服务如果存在 ConversionService 类型的Bean则将其设置为BeanFactory的转换服务。 2、注册默认的嵌入值解析器如果没有其他BeanFactoryPostProcessor注册过嵌入值解析器则注册一个默认的解析器用于解析注解属性值中的占位符。 3、初始化 LoadTimeWeaverAware 类型的 Bean提前初始化这些Bean以便它们可以尽早注册其转换器。 4、停止使用临时类加载器停止使用临时类加载器进行类型匹配。 5、冻结配置允许缓存所有Bean定义元数据不再期望进一步的更改。 6、预实例化单例 Bean实例化所有剩余的非懒加载单例Bean。 其中第6步对单例的Bean进行实例化。调用方法org.springframework.beans.factory.support.DefaultListableBeanFactory#preInstantiateSingletons实例化单例Bean下面是该方法的源码 public void preInstantiateSingletons() throws BeansException {if (logger.isTraceEnabled()) {logger.trace(Pre-instantiating singletons in this);}// Iterate over a copy to allow for init methods which in turn register new bean definitions.// While this may not be part of the regular factory bootstrap, it does otherwise work fine.ListString beanNames new ArrayList(this.beanDefinitionNames);// Trigger initialization of all non-lazy singleton beans...for (String beanName : beanNames) {RootBeanDefinition bd getMergedLocalBeanDefinition(beanName);if (!bd.isAbstract() bd.isSingleton() !bd.isLazyInit()) {if (isFactoryBean(beanName)) {Object bean getBean(FACTORY_BEAN_PREFIX beanName);if (bean instanceof SmartFactoryBean? smartFactoryBean smartFactoryBean.isEagerInit()) {getBean(beanName);}}else {getBean(beanName);}}}// Trigger post-initialization callback for all applicable beans...for (String beanName : beanNames) {Object singletonInstance getSingleton(beanName);if (singletonInstance instanceof SmartInitializingSingleton smartSingleton) {StartupStep smartInitialize getApplicationStartup().start(spring.beans.smart-initialize).tag(beanName, beanName);smartSingleton.afterSingletonsInstantiated();smartInitialize.end();}}}preInstantiateSingletons方法的主要功能是在Spring容器启动时预实例化所有非懒加载的单例Bean。代码解释如下 1、日志记录如果启用了跟踪日志记录预实例化的开始信息。 2、获取 Bean 名称列表创建一个Bean名称列表的副本以便在初始化过程中可以安全地注册新的Bean定义。 3、初始化非懒加载的单例 Bean 遍历Bean名称列表获取每个Bean的定义。检查Bean是否是非抽象的、单例的且不是懒加载的。如果是FactoryBean先获取FactoryBean实例再根据条件决定是否获取实际的Bean实例。 否则直接获取Bean实例。 4、触发后初始化回调 再次遍历Bean名称列表获取每个单例Bean实例。如果Bean实现了SmartInitializingSingleton接口调用其afterSingletonsInstantiated方法。Bean的实例化是调用org.springframework.beans.factory.support.AbstractBeanFactory#getBean(java.lang.String)方法实现的源码如下 public Object getBean(String name) throws BeansException {return doGetBean(name, null, null, false);} 调用doGetBean方法实现Bean的实例化源码如下protected T T doGetBean(String name, Nullable ClassT requiredType, Nullable Object[] args, boolean typeCheckOnly)throws BeansException {String beanName transformedBeanName(name);Object beanInstance;// Eagerly check singleton cache for manually registered singletons.Object sharedInstance getSingleton(beanName);if (sharedInstance ! null args null) {if (logger.isTraceEnabled()) {if (isSingletonCurrentlyInCreation(beanName)) {logger.trace(Returning eagerly cached instance of singleton bean beanName that is not fully initialized yet - a consequence of a circular reference);}else {logger.trace(Returning cached instance of singleton bean beanName );}}beanInstance getObjectForBeanInstance(sharedInstance, name, beanName, null);}else {// Fail if were already creating this bean instance:// Were assumably within a circular reference.if (isPrototypeCurrentlyInCreation(beanName)) {throw new BeanCurrentlyInCreationException(beanName);}// Check if bean definition exists in this factory.BeanFactory parentBeanFactory getParentBeanFactory();if (parentBeanFactory ! null !containsBeanDefinition(beanName)) {// Not found - check parent.String nameToLookup originalBeanName(name);if (parentBeanFactory instanceof AbstractBeanFactory abf) {return abf.doGetBean(nameToLookup, requiredType, args, typeCheckOnly);}else if (args ! null) {// Delegation to parent with explicit args.return (T) parentBeanFactory.getBean(nameToLookup, args);}else if (requiredType ! null) {// No args - delegate to standard getBean method.return parentBeanFactory.getBean(nameToLookup, requiredType);}else {return (T) parentBeanFactory.getBean(nameToLookup);}}if (!typeCheckOnly) {markBeanAsCreated(beanName);}StartupStep beanCreation this.applicationStartup.start(spring.beans.instantiate).tag(beanName, name);try {if (requiredType ! null) {beanCreation.tag(beanType, requiredType::toString);}RootBeanDefinition mbd getMergedLocalBeanDefinition(beanName);checkMergedBeanDefinition(mbd, beanName, args);// Guarantee initialization of beans that the current bean depends on.String[] dependsOn mbd.getDependsOn();if (dependsOn ! null) {for (String dep : dependsOn) {if (isDependent(beanName, dep)) {throw new BeanCreationException(mbd.getResourceDescription(), beanName,Circular depends-on relationship between beanName and dep );}registerDependentBean(dep, beanName);try {getBean(dep);}catch (NoSuchBeanDefinitionException ex) {throw new BeanCreationException(mbd.getResourceDescription(), beanName, beanName depends on missing bean dep , ex);}catch (BeanCreationException ex) {if (requiredType ! null) {// Wrap exception with current bean metadata but only if specifically// requested (indicated by required type), not for depends-on cascades.throw new BeanCreationException(mbd.getResourceDescription(), beanName,Failed to initialize dependency ex.getBeanName() of requiredType.getSimpleName() bean beanName : ex.getMessage(), ex);}throw ex;}}}// Create bean instance.if (mbd.isSingleton()) {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);}else if (mbd.isPrototype()) {// Its a prototype - create a new instance.Object prototypeInstance null;try {beforePrototypeCreation(beanName);prototypeInstance createBean(beanName, mbd, args);}finally {afterPrototypeCreation(beanName);}beanInstance getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);}else {String scopeName mbd.getScope();if (!StringUtils.hasLength(scopeName)) {throw new IllegalStateException(No scope name defined for bean beanName );}Scope scope this.scopes.get(scopeName);if (scope null) {throw new IllegalStateException(No Scope registered for scope name scopeName );}try {Object scopedInstance scope.get(beanName, () - {beforePrototypeCreation(beanName);try {return createBean(beanName, mbd, args);}finally {afterPrototypeCreation(beanName);}});beanInstance getObjectForBeanInstance(scopedInstance, name, beanName, mbd);}catch (IllegalStateException ex) {throw new ScopeNotActiveException(beanName, scopeName, ex);}}}catch (BeansException ex) {beanCreation.tag(exception, ex.getClass().toString());beanCreation.tag(message, String.valueOf(ex.getMessage()));cleanupAfterBeanCreationFailure(beanName);throw ex;}finally {beanCreation.end();if (!isCacheBeanMetadata()) {clearMergedBeanDefinition(beanName);}}}return adaptBeanInstance(name, beanInstance, requiredType);}doGetBean方法的主要功能是从BeanFactory中获取指定名称的Bean实例。具体步骤如下 1、转换 Bean 名称将传入的Bean名称转换为标准形式。 String beanName transformedBeanName(name);2、检查 Singleton 缓存如果缓存中存在Singleton实例且没有参数则直接返回。 Object sharedInstance getSingleton(beanName); if (sharedInstance ! null args null) {// 返回缓存实例 }3、检查原型创建状态如果当前正在创建原型Bean则抛出异常。 if (isPrototypeCurrentlyInCreation(beanName)) {throw new BeanCurrentlyInCreationException(beanName); }4、查找父工厂如果当前工厂没有定义该Bean则委托给父工厂处理。 BeanFactory parentBeanFactory getParentBeanFactory(); if (parentBeanFactory ! null !containsBeanDefinition(beanName)) {// 委托给父工厂 }5、标记 Bean 创建标记Bean已经被创建。 if (!typeCheckOnly) {markBeanAsCreated(beanName); }6、初始化依赖初始化当前Bean所依赖的其他Bean。 String[] dependsOn mbd.getDependsOn(); if (dependsOn ! null) {for (String dep : dependsOn) {// 初始化依赖} }7、创建 Bean 实例 if (mbd.isSingleton()) {// 单例 } else if (mbd.isPrototype()) {// 原型 } else {// 其他作用域 }如果是Singleton则从缓存中获取或创建并缓存。如果是Prototype则每次调用时都创建新的实例。其他作用域的Bean通过相应的Scope对象创建。 8、处理异常捕获并处理创建Bean时的异常。 catch (BeansException ex) {// 处理异常 }9、清理元数据如果不需要缓存元数据则清除合并后的Bean定义。 if (!isCacheBeanMetadata()) {clearMergedBeanDefinition(beanName); }10、返回 Bean 实例 return adaptBeanInstance(name, beanInstance, requiredType);上面代码调用AbstractAutowireCapableBeanFactory#createBean(String, RootBeanDefinition, Object[])实例化Bean,之后调用SimpleInstantiationStrategy#instantiate(RootBeanDefinition, String, BeanFactory)方法初始化Bean调用栈如下 SimpleInstantiationStrategy#instantiate源码如下 public Object instantiate(RootBeanDefinition bd, Nullable String beanName, BeanFactory owner) {// Dont override the class with CGLIB if no overrides.if (!bd.hasMethodOverrides()) {Constructor? constructorToUse;synchronized (bd.constructorArgumentLock) {constructorToUse (Constructor?) bd.resolvedConstructorOrFactoryMethod;if (constructorToUse null) {Class? clazz bd.getBeanClass();if (clazz.isInterface()) {throw new BeanInstantiationException(clazz, Specified class is an interface);}try {constructorToUse clazz.getDeclaredConstructor();bd.resolvedConstructorOrFactoryMethod constructorToUse;}catch (Throwable ex) {throw new BeanInstantiationException(clazz, No default constructor found, ex);}}}return BeanUtils.instantiateClass(constructorToUse);}else {// Must generate CGLIB subclass.return instantiateWithMethodInjection(bd, beanName, owner);}}BeanUtils.instantiateClass(constructorToUse)使用 BeanUtils 类的 instantiateClass 方法传入已经找到的构造函数 constructorToUse通过反射机制创建并返回一个新的对象实例。 获得实例化的Bean之后会在AbstractAutowireCapableBeanFactory#doCreateBean方法接着调用AbstractAutowireCapableBeanFactory#populateBean给Bean填充属性***源码如下*** protected void populateBean(String beanName, RootBeanDefinition mbd, Nullable BeanWrapper bw) {if (bw null) {if (mbd.hasPropertyValues()) {throw new BeanCreationException(mbd.getResourceDescription(), beanName, Cannot apply property values to null instance);}else {// Skip property population phase for null instance.return;}}if (bw.getWrappedClass().isRecord()) {if (mbd.hasPropertyValues()) {throw new BeanCreationException(mbd.getResourceDescription(), beanName, Cannot apply property values to a record);}else {// Skip property population phase for records since they are immutable.return;}}// Give any InstantiationAwareBeanPostProcessors the opportunity to modify the// state of the bean before properties are set. This can be used, for example,// to support styles of field injection.if (!mbd.isSynthetic() hasInstantiationAwareBeanPostProcessors()) {for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {if (!bp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {return;}}}PropertyValues pvs (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);int resolvedAutowireMode mbd.getResolvedAutowireMode();if (resolvedAutowireMode AUTOWIRE_BY_NAME || resolvedAutowireMode AUTOWIRE_BY_TYPE) {MutablePropertyValues newPvs new MutablePropertyValues(pvs);// Add property values based on autowire by name if applicable.if (resolvedAutowireMode AUTOWIRE_BY_NAME) {autowireByName(beanName, mbd, bw, newPvs);}// Add property values based on autowire by type if applicable.if (resolvedAutowireMode AUTOWIRE_BY_TYPE) {autowireByType(beanName, mbd, bw, newPvs);}pvs newPvs;}if (hasInstantiationAwareBeanPostProcessors()) {if (pvs null) {pvs mbd.getPropertyValues();}for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {PropertyValues pvsToUse bp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);if (pvsToUse null) {return;}pvs pvsToUse;}}boolean needsDepCheck (mbd.getDependencyCheck() ! AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);if (needsDepCheck) {PropertyDescriptor[] filteredPds filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);checkDependencies(beanName, mbd, filteredPds, pvs);}if (pvs ! null) {applyPropertyValues(beanName, mbd, bw, pvs);}}populateBean 方法的主要作用是填充Bean的属性。在Spring中Bean的属性可以通过多种方式设置比如通过构造器注入Constructor Injection、属性注入Setter Injection或者字段注入Field Injection。populateBean 方法负责根据Bean的定义和配置将这些属性正确地设置到Bean实例中。具体步骤如下 1、检查 BeanWrapper 是否为空如果BeanWrapper为空且有属性值则抛出异常否则跳过属性填充阶段。 2、检查是否为记录类型如果BeanWrapper包装的是记录类型且有属性值则抛出异常否则跳过属性填充阶段。 3、调用 InstantiationAwareBeanPostProcessors 在设置属性之前允许InstantiationAwareBeanPostProcessors 修改bean的状态。 4、自动装配属性根据配置的自动装配模式按名称或按类型添加相应的属性值。 5、再次调用 InstantiationAwareBeanPostProcessors 在设置属性之后允许InstantiationAwareBeanPostProcessors修改属性值。 6、依赖检查如果需要进行依赖检查则执行依赖检查。 7、应用属性值将最终的属性值应用到BeanWrapper中。 下面举个例子来说明populateBean 方法的作用。 在类Demo中注入了Depd执行完BeanUtils.instantiateClass(constructorToUse)后Demo的depd属性为null。 执行populateBean填充属性后depd属性就获取了注入的值。 Demo和Depd源码 Component public class Demo {Autowiredprivate Depd depd;private String name demo;}Component public class Depd {private String nameDependency; }虽然 populateBean 方法负责填充Bean的属性但是Bean的完全初始化比如执行自定义的初始化方法通常是在这个方法之后进行的。 我们回到AbstractAutowireCapableBeanFactory#doCreateBean方法根据源码在调用完populateBean方法后接着调用了AbstractAutowireCapableBeanFactory#initializeBean(String, Object, RootBeanDefinition)方法。 该方法的源码如下 /*** Initialize the given bean instance, applying factory callbacks* as well as init methods and bean post processors.* pCalled from {link #createBean} for traditionally defined beans,* and from {link #initializeBean} for existing bean instances.* param beanName the bean name in the factory (for debugging purposes)* param bean the new bean instance we may need to initialize* param mbd the bean definition that the bean was created with* (can also be {code null}, if given an existing bean instance)* return the initialized bean instance (potentially wrapped)* see BeanNameAware* see BeanClassLoaderAware* see BeanFactoryAware* see #applyBeanPostProcessorsBeforeInitialization* see #invokeInitMethods* see #applyBeanPostProcessorsAfterInitialization*/SuppressWarnings(deprecation)protected Object initializeBean(String beanName, Object bean, Nullable RootBeanDefinition mbd) {invokeAwareMethods(beanName, bean);Object wrappedBean bean;if (mbd null || !mbd.isSynthetic()) {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()) {wrappedBean applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);}return wrappedBean;}initializeBean 方法的主要作用是完成Bean的初始化工作。这包括执行任何由Bean定义指定的初始化回调比如 init-method以及调用任何由用户定义的 BeanPostProcessor 接口实现所指定的初始化方法。步骤如下 1、调用Aware方法通过 invokeAwareMethods 方法调用bean的Aware方法例如 BeanNameAware、BeanClassLoaderAware 和 BeanFactoryAware。 2、应用 BeanPostProcessor 的前置初始化回调在正式初始化 Bean 之前Spring 会调用所有注册的 BeanPostProcessor 的 3】3、postProcessBeforeInitialization 方法。这允许在Bean初始化之前对其进行一些自定义的处理。 3、执行 Bean 的初始化回调如果Bean定义中指定了 init-methodSpring会调用这个方法来完成Bean的初始化工作。此外如果Bean实现了 InitializingBean 接口Spring也会调用其 afterPropertiesSet 方法。 4、应用 BeanPostProcessor 的后置初始化回调在Bean初始化完成后Spring会调用所有注册的 BeanPostProcessor 的 postProcessAfterInitialization 方法。这允许在Bean初始化之后对其进行一些额外的处理。 5、Bean 初始化完成经过上述步骤后Bean的初始化工作就完成了。此时Bean已经准备好被应用程序使用。 最后我们将上面Bean实例化过程整理为一张流程图如下 八、面试题 介绍一下IOC思想 IOCInversion of Control控制反转是Spring以及Spring Boot框架的核心理念之一。它极大地改变了传统的开发方式帮助开发者更高效、更灵活地构建模块化、可测试的应用。IOC是一种设计原则旨在将程序中对象创建和依赖管理的控制权从手动管理转移到框架或容器如Spring容器中。简单来说程序中的对象不再由开发者手动创建或管理它们之间的依赖而是交给Spring容器来负责。通过这种方式IOC实现了模块间的解耦提高了代码的灵活性和可维护性。 在Spring Boot中IOC主要通过依赖注入Dependency InjectionDI的方式实现。依赖注入是指在运行时由容器动态地将依赖对象注入到组件中。Spring Boot提供了三种常见的依赖注入方式构造函数注入、setter方法注入和字段注入。其中构造函数注入是最推荐的方式因为它可以保证依赖注入的不可变性并且能让Spring Boot检查依赖是否完整。 Spring Boot有哪些配置Bean的方式有何区别 Spring Boot配置Bean的方式主要有两种使用注解Bean注入到Spring IOC容器中以及使用Component扫描装配Bean到IOC容器中。 使用Bean注解的方式这种方式需要在配置类中定义一个方法并使用Bean注解来标记该方法。该方法的返回值将是一个Bean实例Spring容器会将其装配到IOC容器中。这种方式通常用于需要手动创建Bean实例的场景。使用Component注解的方式这种方式是通过在类上使用Component或其子注解如Service、Repository等来标记该类为Spring容器的一个Bean。然后Spring容器会在启动时自动扫描这些注解并将对应的类实例化后装配到IOC容器中。这种方式通常用于自动装配的场景无需手动创建Bean实例。 两者的主要区别在于使用Bean注解的方式需要手动编写配置方法更加灵活但相对繁琐而使用Component注解的方式则更加简洁适用于自动装配的场景。 介绍以下refresh方法的流程 refresh方法是Spring容器初始化过程中的核心方法之一。它负责完成容器的初始化工作包括Bean的实例化、初始化等。以下是refresh方法的主要流程 准备刷新进行一些刷新前的准备工作如设置容器的活动状态、初始化一些属性等。获取Bean工厂从容器中获取BeanFactory实例这是Spring容器的基础设施之一负责Bean的创建和管理。准备Bean工厂对BeanFactory进行一些配置和初始化工作如设置Bean的类加载器、属性编辑器等。后处理BeanFactory允许用户通过实现BeanFactoryPostProcessor接口来自定义BeanFactory的初始化过程。注册Bean后处理器注册一些Bean后处理器如InstantiationAwareBeanPostProcessor等这些后处理器将在Bean的创建和初始化过程中发挥作用。初始化消息源初始化应用程序的国际化资源。初始化事件多播器初始化Spring的事件多播器用于发布和监听事件。创建Bean根据配置信息创建Bean实例并将它们装配到IOC容器中。完成刷新进行一些刷新后的工作如发布刷新完成事件等。 介绍一下Bean的实例化过程 Bean的实例化过程是Spring容器创建Bean实例的过程。以下是Bean实例化过程的主要步骤 获取Bean定义从Bean定义仓库中获取目标Bean的定义信息。这些信息包括Bean的类名、作用域、依赖等。检查Bean定义对Bean定义进行检查确保Bean可以被正确创建和初始化。实例化Bean根据Bean的定义信息创建Bean实例。Spring容器提供了多种实例化策略如直接调用构造方法、使用工厂方法等。设置Bean属性对Bean实例的属性进行赋值。这包括通过依赖注入将其他Bean注入到当前Bean中以及通过配置属性为Bean的字段赋值等。初始化Bean调用Bean的初始化方法如PostConstruct注解的方法完成Bean的初始化工作。 Bean实例化的扩展点及其作用 在Spring容器中Bean实例化的扩展点主要包括以下几个 ApplicationContextInitializer 在容器刷新之前调用允许用户在整个Spring容器还没被初始化之前做一些事情如激活配置、动态字节码注入等。BeanDefinitionRegistryPostProcessor 在读取项目中的BeanDefinition之后执行提供一个补充的扩展点允许用户动态注册自己的BeanDefinition。BeanFactoryPostProcessor 在读取BeanDefinition信息之后、实例化Bean之前调用允许用户通过实现这个扩展接口来自行处理一些东西如修改已经注册的BeanDefinition的元信息。InstantiationAwareBeanPostProcessor 在Bean的实例化阶段和属性注入阶段提供扩展点允许用户通过实现这个接口来自定义Bean的实例化过程和属性注入过程。 这些扩展点的作用在于提供了灵活的机制允许用户在Spring容器的不同阶段进行自定义操作从而满足各种复杂的应用场景需求。
http://www.sczhlp.com/news/163845/

相关文章:

  • 一级a做爰片免费网站迅雷下载青岛网站制作公司 网络服务
  • 北京丰台区做网站公司做网站公司宁波上市
  • 微网站建设平台wordpress主题proland
  • 黄骗免费网站郑州汉狮公司做网站
  • 学工系统网站建设的意义html用什么软件
  • 韩国原生ip站群服务器外贸英文网站制作
  • 买布做衣裳 在哪个网站买好世界互联网乌镇峰会
  • 旅游网站建设维护php网站建设制作
  • 成都电子商务平台网站制作报价汕头网站制作怎么做
  • 南宁世尊商贸网站建设做网站为什么选择竞网智赢
  • 郑州房地产网站建设wordpress 网盘 插件
  • 专业做网站专业网站定制价格
  • 宁夏建设厅网站领导wordpress如何分类栏
  • 网站建设pdfwordpress 编辑器 空格
  • cnzz网站建设微博登录网站开发
  • 杭州的设计网站大全个人做网站时不要做什么样的网站
  • 昆明网站如何制作广西论坛网站建设
  • 商城网站开发用什么框架微信小程序云开发费用
  • 大型网站技术架构演进与性能优化做衣服网站有哪些
  • 网站建设完成的时间洛阳自助建站
  • 成都软件网站开发优化大师下载安装免费
  • 推广网站制作怎么做换了家公司做网站如何接入备案
  • 完整教程:精读C++20设计模式——行为型设计模式:解释器模式
  • js疑惑
  • 西樵网站建设公司网页设计图片居中
  • 网站新闻发布后前台不显示注册网站要求
  • 环保公司网站建设内容汽车网页制作素材
  • 江西新余网站建设建设上线网站
  • 网站策划的基本过程门窗网站源码
  • 网站建设前期如何做好市场定位分析西安app开发公司排名