前言:
Spring主要功能创建对象(俗称IOC),
Bean的生命周期流程图
1、生成BeanDefinition
spring启动会进行扫描执行如下方法
org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider#scanCandidateComponents
Spring的扫描流程图
- 根据ResourcePatternResolver 获取指定路径下所有的.class文件【最终生成 Resource 对象】
- 遍历 Resource 集合
- 利用MetadataReaderFactory 解析 Resource 获取metadateReader
- 对metadataReader 进行 excludeFilters和 includeFilters ,
- 若excludeFilters 匹配直接返回false,
- 若 includeFiletes 匹配还要判断,是否有@Conditional ,如果有则需要判断@Conditional 注解筛选是否筛选过,不能筛选 直接false
- 筛选通过后,还要判断
- 是否独立、【不是接口或抽象】、如果是抽象,类上面是否添加@Lookup注解 【三个条件缺一不可】
- 最终将 ScannedGenericBeanDefinition 生成BeanDefinition 对象返回
其中 @Conditional 的注解的作用
@Conditional 是 Spring 4.0 引入的核心注解,用于条件化地创建 Bean。它允许根据特定条件决定是否注册 Bean 到 Spring 容器中。
除了自定义条件,Spring 还提供了一些内置的条件注解,这些注解都是 @Conditional 的扩展,使用起来更加方便:
- @ConditionalOnBean:当容器中存在指定 Bean 时。
- @ConditionalOnMissingBean:当容器中不存在指定 Bean 时。
- @ConditionalOnClass:当类路径中存在指定类时。
- @ConditionalOnMissingClass:当类路径中不存在指定类时。
- @ConditionalOnProperty:当指定的属性有指定的值时。
- @ConditionalOnResource:当类路径中存在指定资源时。
- @ConditionalOnWebApplication:当是 Web 应用时。
- @ConditionalOnNotWebApplication:当不是 Web 应用时。
- @ConditionalOnExpression:当 SpEL 表达式为 true 时。
@Conditional 注解 demo案例:
StuService Bean的创建 要依赖于 StuServiceCondition
@Component @Conditional(StuServiceCondition.class)public class StuService{publicvoidtest(){System.out.println("stu test ...");}}import org.springframework.context.annotation.Condition;import org.springframework.context.annotation.ConditionContext;import org.springframework.core.type.AnnotatedTypeMetadata;public class StuServiceCondition implements Condition{@Override public booleanmatches(ConditionContext context,AnnotatedTypeMetadata metadata){// 检查某个属性是否存在returncontext.getEnvironment().containsProperty("stu.service.enabled");}}这时获取bean 为stuService 找不到异常。
Exception in thread “main” org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named ‘stuService’ available…
MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
创建MetadataReader 注意点:
org.springframework.core.type.classreading.CachingMetadataReaderFactory#getMetadataReader
CachingMetadataReaderFactory解析某个.class文件得到 MetadataReader对象,利用的是ASM技术,并没有加载这个类到JVM。最终得到的ScannedGenericBeanDefinition对象,beanClass属性存储当前的类的名称,而不是class对象。
2、合并BeanDefinition
在通过BeanDefinition之后,就可以根据BeanDefinition创建Bean对象。在spring中支持父子BeanDefinition,和Java中继承相似
比如:
spring.xml
<bean id="parent"class="com.dx.service.Parent"scope="prototype"/><bean id="child"class="com.dx.service.Child"/>测试:
AnnotationConfigApplicationContext applicationContext=newAnnotationConfigApplicationContext(AppConfig.class);XmlBeanDefinitionReader xmlBeanDefinitionReader=newXmlBeanDefinitionReader(applicationContext);xmlBeanDefinitionReader.loadBeanDefinitions("spring.xml");System.out.println(applicationContext.getBean("child"));System.out.println(applicationContext.getBean("child"));System.out.println(applicationContext.getBean("child"));测试结果:
com.dx.service.Child@ef9296d
com.dx.service.Child@ef9296d
com.dx.service.Child@ef9296d
如果将xml修改为:
<bean id="parent"class="com.dx.service.Parent"scope="prototype"/><bean id="child"class="com.dx.service.Child"parent="parent"/>测试的结果是
com.dx.service.Child@ef9296d
com.dx.service.Child@36c88a32
com.dx.service.Child@7880cdf3
child可以继承parent的 scope,
- 子如果有scope 则使用自己的
- 子没有scope,继承父类scope,父类若没有scope有parent的属性,同样的继承逻辑
源码的大概如下: - 根据beanName判断是否合并过,合并过直接退出
- 判断当前的bean是否有父类,
- 如果没有设置 当前bean为RootBeanDefinition
- 如果有循环获取 bean的父bean
- 覆盖父定义属性(子覆盖父)
protected RootBeanDefinitiongetMergedBeanDefinition(String beanName,BeanDefinition bd,@Nullable BeanDefinition containingBd)throws BeanDefinitionStoreException{synchronized(this.mergedBeanDefinitions){// 1. 检查是否已经合并过RootBeanDefinition mbd=this.mergedBeanDefinitions.get(beanName);if(mbd==null){// 2. 如果没有父定义,直接转换为RootBeanDefinitionif(bd.getParentName()==null){mbd=newRootBeanDefinition(bd);}else{// 3. 递归合并父定义BeanDefinition pbd;try{String parentBeanName=transformedBeanName(bd.getParentName());pbd=getMergedBeanDefinition(parentBeanName);}// ...// 4. 深度拷贝父定义mbd=newRootBeanDefinition(pbd);// 5. 覆盖父定义属性(子覆盖父)mbd.overrideFrom(bd);}// 6. 缓存合并结果this.mergedBeanDefinitions.put(beanName,mbd);}returnmbd;}}3、加载类
BeanDefinition合并之后,就可以创建Bean的对象执行的方法是
org.springframework.beans.factory.support.AbstractBeanFactory#resolveBeanClass
创建bean就必须实例化对象,实例化要先加载类所对应class
Class<?>resolvedClass=resolveBeanClass(mbd,beanName);方法的主要实现是:
// 如果是beanClass就直接返回if(mbd.hasBeanClass()){returnmbd.getBeanClass();}// 如果beanClass没有被加载,会根据doResolveBeanClassif(System.getSecurityManager()!=null){returnAccessController.doPrivileged((PrivilegedExceptionAction<Class<?>>)()->doResolveBeanClass(mbd,typesToMatch),getAccessControlContext());}else{returndoResolveBeanClass(mbd,typesToMatch);}如果beanClass 属性的类型是Class 直接返回,不是则根据类名加载(doResolveBeanClass(mbd, typesToMatch))
会利用BeanFactory所设置的类加载器加载类,如果没有设置,则默认使用ClassUtils.getDefaultClassLoader()类加载
ClassUtils.getDefaultClassLoader()类加载方法:
- 优先获取当前线程的类加载器
- 当前线程类加载为空,返回ClassUtils.class.getClassLoader()
- 如果ClassUtils.class.getClassLoader() 也为空,则ClassLoader.getSystemClassLoader()
4、实例化前
BeanDefinition 对应的类加载成功后,实例化对象前 Spring提供一个扩展点允许某个对象、某些对象实例化前做些额外的工作
org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation
import com.zhouyu.service.StuService;import org.springframework.beans.BeansException;import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;import org.springframework.stereotype.Component;@Component public class DxBeanPostProcessor implements InstantiationAwareBeanPostProcessor{@Override public ObjectpostProcessBeforeInstantiation(Class<?>beanClass,String beanName)throws BeansException{if("stuService".equals(beanName)){System.out.println("加载 stuService 初始化之前");// Spring将直接使用这个对象returnnewStuService();}// 返回null则走正常流程returnnull;}}InstantiationAwareBeanPostProcessor 的
postProcessBeforeInstantiation 除了常见的创建代理对象外,还有以下重要作用:
1,完全绕过spring的生命周期
@Override public ObjectpostProcessBeforeInstantiation(Class<?>beanClass,String beanName){// 如果返回非null对象,Spring将:// 1. 跳过默认构造函数调用// 2. 跳过后置处理器链的后续处理// 3. 跳过属性注入if(beanName.equals("specialBean")){returnnewSpecialBean();// Spring将直接使用这个对象}returnnull;// 返回null则走正常流程}2、根据条件Bean创建
@Override public ObjectpostProcessBeforeInstantiation(Class<?>beanClass,String beanName){// 根据条件决定是否创建Beanif(shouldSkipCreation(beanClass,beanName)){returnnewNoOpBean();// 返回一个占位对象}// 根据环境变量/配置决定实现类if(beanClass.isAssignableFrom(Service.class)){returnisProduction()?newProductionService():newMockService();}returnnull;}3、对象池/缓存管理
@Override public ObjectpostProcessBeforeInstantiation(Class<?>beanClass,String beanName){if(beanClass.isAnnotationPresent(Poolable.class)){// 从对象池获取实例,而不是新建Object pooledInstance=objectPool.acquire(beanClass);if(pooledInstance!=null){returnpooledInstance;// 返回池中对象}}returnnull;}4、性能优化场景
@Override public ObjectpostProcessBeforeInstantiation(Class<?>beanClass,String beanName){// 对于频繁创建的原型Bean,使用对象复用策略if(isHighFrequencyPrototype(beanClass)){returnprototypeReuseStrategy.createOrReuse(beanClass);}// 对于已知的无状态Bean,直接返回共享实例if(isStateless(beanClass)){returngetSharedInstance(beanClass);}returnnull;}postProcessBeforeInstantiation 使用注意点
1、跳过正常的生命周期 :返回null 会跳过
- postProcessAfterInstantiation
- 属性注入 (populateBean)
- 初始化回调 (afterPropertiesSet, init-method)
- postProcessBeforeInitialization
- postProcessAfterInitialization
2、需要手动处理依赖
@Override public ObjectpostProcessBeforeInstantiation(Class<?>beanClass,String beanName){MyBean bean=newMyBean();// 需要手动注入依赖bean.setDependency(manualLookup());// 手动调用初始化bean.init();returnbean;}3、与 AOP 的协调:如果在此创建代理,需要确保与其他 AOP 配置协调一致
5、实例化
会根据 BeanDefinition 创建一个对象。
5.1 Supplier创建对象
判断Beandefinition 中是否设置Supplier,如果设置了 则调用Supplier的get() 设置 Supplier
AnnotationConfigApplicationContext applicationContext=newAnnotationConfigApplicationContext(AppConfig.class);GenericBeanDefinition beanDefinition=newGenericBeanDefinition();beanDefinition.setBeanClass(Person.class);// 设置 supplierbeanDefinition.setInstanceSupplier(new Supplier<Object>(){@Override public Objectget(){// 这里可以编写创建逻辑Person person=newPerson();person.setAge(18);person.setName("张三");returnperson;}});// 注册beanapplicationContext.registerBeanDefinition("person",beanDefinition);System.out.println(applicationContext.getBean("person"));======执行结果=====Person{age=18,name='张三'}Supplier 基础概念和作用
1,Supplier 是什么
是 Java 8 引入的函数式接口,表示一个结果的提供者:
@FunctionalInterface public interface Supplier<T>{/** * Gets a result. * * @return a result */Tget();}1.2 在Spring中作用:
1.延迟实例化:将 Bean 的创建逻辑封装起来,按需调用
2.灵活性:允许运行时动态决定如何创建 Bean
3.与 BeanDefinition 解耦:将创建逻辑从 BeanDefinition 中分离
2、工厂方法创建对象
如果没有设置Supplier,检查是否BeanDefinition中是否设置 factory-method
sprin.xml
<bean id="stuService"class="com.zhouyu.service.StuService"factory-method="createStuServiceFactory"/>public class StuService{publicstaticStuServicecreateStuServiceFactory(){System.out.println("this StuService createFactory");returnnewStuService();}publicvoidtest(){System.out.println("stu test ...");}}AnnotationConfigApplicationContext applicationContext=newAnnotationConfigApplicationContext(AppConfig.class);newXmlBeanDefinitionReader(applicationContext).loadBeanDefinitions("spring.xml");System.out.println(applicationContext.getBean("stuService"));3、推断方法 @Lookup注解
import org.springframework.stereotype.Component;@Component public class StuService{publicvoidtest(){System.out.println("stu test ...");}}创建一个Spring容器 AnnotationConfigApplicationContext applicationContext=newAnnotationConfigApplicationContext(AppConfig.class);StuService stuService=(StuService)applicationContext.getBean("stuService");stuService.test();执行结果
stu test …
测试@Conditional注解
import org.springframework.context.annotation.Conditional;import org.springframework.stereotype.Component;@Component @Conditional(StuServiceCondition.class)public class StuService{publicvoidtest(){System.out.println("stu test ...");}}import org.springframework.context.annotation.Condition;import org.springframework.context.annotation.ConditionContext;import org.springframework.core.type.AnnotatedTypeMetadata;public class StuServiceCondition implements Condition{@Override public booleanmatches(ConditionContext context,AnnotatedTypeMetadata metadata){// 检查某个属性是否存在returncontext.getEnvironment().containsProperty("stu.service.enabled");}}执行结果报:
Exception in thread “main” org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named ‘stuService’ available…
6、BeanDefinition的后置处理器
比如Spring中使用
@Component public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationAwareBeanPostProcessor,MergedBeanDefinitionPostProcessor,PriorityOrdered,BeanFactoryAware{@Override publicvoidpostProcessMergedBeanDefinition(RootBeanDefinition beanDefinition,Class<?>beanType,String beanName){System.out.println(" AutowiredAnnotationBeanPostProcessor postProcessMergedBeanDefinition method ");}}7、实例化后
postProcessAfterInstantiation 作用
- 在Bean的实例化后、属性注入前执行
- 可以返回false阻止Spring对该Bean进行属性注入
- 适合用于自定义初始化逻辑或条件判断
典型应用场景: - 动态控制属性注入
- 实现延迟注入
- 属性值验证和转换
- 特殊Bean的预处理
属性填充案例:
@Component public class DxInstanceAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor{@Override public booleanpostProcessAfterInstantiation(Object bean,String beanName)throws BeansException{if("stuService".equals(beanName)){PerSon perSon=newPerSon();perSon.setAge(12);perSon.setName("张三");System.out.println(perSon);}returntrue;}}8、自动注入
9、处理属性
InstantiationAwareBeanPostProcessor.postProcessProperties() 是Spring框架中一个非常重要的扩展点,它在Bean的生命周期中扮演着关键角色。
主要作用包括:
1.处理注解驱动的依赖注入:例如,@Autowired、@Value、@Inject、@Resource等注解的解析和注入。
2.属性值的后处理:可以对属性值进行转换、验证、加密/解密等操作。
3.动态添加属性:根据某些条件动态添加属性。
4.跳过某些属性的注入:通过返回null或修改PropertyValues来控制哪些属性需要注入。
比如Spring内置实现
AutowiredAnnotationBeanPostProcessor
// 主要职责:处理 @Autowired、@Value、@Inject 注解public class AutowiredAnnotationBeanPostProcessor{@Override public PropertyValuespostProcessProperties(PropertyValues pvs,Object bean,String beanName){// 1. 获取或构建注入元数据InjectionMetadata metadata=findAutowiringMetadata(beanName,bean.getClass(),pvs);try{// 2. 执行实际的注入操作metadata.inject(bean,beanName,pvs);}catch(Throwable ex){throw newBeanCreationException(beanName,"Injection failed",ex);}// 3. 返回可能被修改的 PropertyValuesreturnpvs;}privatevoidinject(Object bean,@Nullable String beanName,@Nullable PropertyValues pvs){// 字段注入for(AutowiredFieldElement field:this.autowiredFields){field.inject(bean,beanName,pvs);}// 方法注入for(AutowiredMethodElement method:this.autowiredMethods){method.inject(bean,beanName,pvs);}}}注解解析
处理各种依赖注入注解属性处理
修改、添加、删除属性值值转换
类型转换、占位符解析、SpEL计算
条件控制:根据条件决定是否注入某些属性
验证检查:属性值验证和约束检查
10、执行Aware
1.获取Bean在容器中的名称:通过实现BeanNameAware接口,Bean可以知道自己在容器中配置的名称。
2.获取BeanFactory:通过实现BeanFactoryAware接口,Bean可以获取到BeanFactory,从而可以手动获取其他Bean,或者进行一些高级操作。
3.获取ApplicationContext:通过实现ApplicationContextAware接口,Bean可以获取到ApplicationContext,从而可以访问容器上下文,例如获取其他Bean、发布事件、访问环境变量等。
4.获取环境配置:通过实现EnvironmentAware接口,Bean可以获取到Environment对象,从而可以访问配置属性、profiles等。
5.资源加载:通过实现ResourceLoaderAware接口,Bean可以获取到ResourceLoader,从而可以加载类路径或文件系统中的资源。
6.国际化:通过实现MessageSourceAware接口,Bean可以获取到MessageSource,从而可以进行国际化消息的解析。
7.应用事件发布:通过实现ApplicationEventPublisherAware接口,Bean可以获取到ApplicationEventPublisher,从而可以发布应用事件。
8.嵌入式值解析:通过实现EmbeddedValueResolverAware接口,Bean可以获取到StringValueResolver,从而可以解析嵌入式值(例如SpEL表达式)。
使用 Aware 的场景清单
import org.springframework.beans.factory.BeanClassLoaderAware;import org.springframework.beans.factory.BeanNameAware;import org.springframework.stereotype.Component;@Component public class BeanIdentityService implements BeanNameAware,BeanClassLoaderAware{private String beanName;private ClassLoader classLoader;@Override publicvoidsetBeanClassLoader(ClassLoader classLoader){this.classLoader=classLoader;System.out.println("current classLoader :"+classLoader);}@Override publicvoidsetBeanName(String name){// 场景:日志记录、监控、动态配置this.beanName=beanName;System.out.println("current bean name :"+beanName);}}11、初始化前
BeanPostProcessor.postProcessBeforeInitialization()
import org.springframework.beans.BeansException;import org.springframework.beans.factory.config.BeanPostProcessor;import org.springframework.stereotype.Component;@Component public class DxPostProcessor implements BeanPostProcessor{@Override public ObjectpostProcessBeforeInitialization(Object bean,String beanName)throws BeansException{if("stuService".equals(beanName)){System.out.println("初始化之前");}returnbean;}}12、初始化
// 1. @PostConstruct 注解方法@PostConstruct publicvoidinitMethod1(){// JSR-250 标准,最先执行}// 2. InitializingBean 接口的 afterPropertiesSet 方法@Override publicvoidafterPropertiesSet()throws Exception{// Spring 接口方式,第二执行}// 3. XML/@Bean 配置的 init-method// XML: <bean id="demo" class="com.xx.xx.Demo" init-method="customInit"/>// @Bean: @Bean(initMethod = "customInit")publicvoidcustomInit(){// 自定义方法,最后执行}13、初始化后
这个是bean创建的生命周期最后一步。
import org.springframework.beans.BeansException;import org.springframework.beans.factory.config.BeanPostProcessor;import org.springframework.stereotype.Component;@Component public class DxPostProcessor implements BeanPostProcessor{@Override public ObjectpostProcessAfterInitialization(Object bean,String beanName)throws BeansException{if("stuService".equals(beanName)){System.out.println("初始化之后");}returnbean;}}