1. Processor和Aware
1.1 Processor
上一篇介绍的@PostConstruct和@PreDestroy是由Spring框架来读取的,并在Bean生命周期的相应阶段调用注解标记的方法,那么Spring框架具体是如何实现这些调用的呢?想要理解这个问题的答案,需要先了解Spring的Processor。
在Spring框架中,Processor(处理器)是一种用于定制化和拓展Spring容器的机制。它是Spring框架中重要的一环,用于增强Spring容器的功能和灵活性。Spring框架中有很多内置的Processor,如BeanPostProcessor、BeanFactoryPostProcessor等,开发者也可以通过自定义Processor来实现特定需求。
BeanFactoryPostProcessor:是一个重要的Processor,它可以在容器实例化Bean之前读取Bean的定义(configuration metadata)并可以对Bean的定义进行一些自定义操作,如修改bean的定义、删除不必要的bean等。
BeanPostProcessor:是一种比较常用的Processor,它的主要作用是在Bean实例化后、初始化前或初始化后对Bean进行一些操作,如实现特定接口、执行特定操作等。通过实现BeanPostProcessor接口,开发者可以自定义一些逻辑,从而达到增强Bean功能的目的。
1.2 CommonAnnotationBeanPostProcessor
CommonAnnotationBeanPostProcessor是Spring框架中的一个BeanPostProcessor,其作用是识别和处理通用注解(Common Annotations)。这些通用注解包括@Resource、@PostConstruct、@PreDestroy等。
CommonAnnotationBeanPostProcessor可以自动扫描Spring容器中所有的Bean,查找是否有使用上述通用注解的Bean,并自动适配和处理这些注解。其功能为:
1、查找所有使用了通用注解的组件。
2、根据注解中的信息进行自动注入或执行初始化和销毁方法等操作。
声明com.obj.spring.MyBeanFactoryPostProcessor,实现BeanFactoryPostProcessor接口:
package com.obj.spring;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.stereotype.Component;
import java.util.Arrays;
/*** 自定义的BeanFactoryPostProcessor Bean工厂后期处理器,* 其中使用一个方法 postProcessBeanFactory Bean工厂后置处理* 在加载了Bean定义信息以后,对Bean定义进行后续转换处理。* 原则上不建议自行处理* configurableListableBeanFactory 对象中封装了全部的 Bean定义信息*/
@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {/*** postProcess 后置处理 BeanFactory Bean工厂* postProcessBeanFactory 在Spring加载全部Bean定义以后执行* @param configurableListableBeanFactory 这个对象封装了全部Bean定义信息* @throws BeansException bean定义加载失败抛出异常,如果抛出异常, 则Spring初始化失败!*/@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory)throws BeansException {//获取全部的Bean定义, getBeanDefinitionNames 获取Bean定义的名称// get 获得 Bean Definition Bean的定义 Names 名字String[] beanNames =configurableListableBeanFactory.getBeanDefinitionNames();Arrays.stream(beanNames).forEach(name -> System.out.println("MBFPP: Bean Name = " + name));}
}
声明com.obj.spring. MyBeanPostProcessor,实现BeanPostProcessor接口:
package com.obj.spring;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;
/*** BeanPostProcessor Bean后期处理器(BPP), 在创建了Bean对象之后对象Bean进行处理* 其中包括两个方法* postProcessBeforeInitialization:bean后期处理,在初始化之前执行* postProcessAfterInitialization:bean后期处理,在初始化之后执行*/
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName)throws BeansException {//创建了每个一个bean以后,执行初始化方法之前,执行//bean 就是刚刚创建的Bean对象, beanName就是这个Bean IDSystem.out.println("MBPP:初始化前置处理"+beanName +", "+bean);//方法务必返回 bean 对象,否则会干扰 执行Bean初始化方法return bean;}@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName)throws BeansException {//在每个Bean初始化以后执行后置处理方法System.out.println("MBPP:初始化后置处理"+beanName +", "+bean);//方法务必返回 bean 对象,否则会干扰Bean的使用return bean;}
}
声明com.obj.spring.ProcessorDemo,创建ApplicationContext实例即可,当Spring扫描到Processor接口的实现类时,会自动加载并使之生效。
package com.obj.spring;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class ProcessorDemo {public static void main(String[] args) {ApplicationContext context =new AnnotationConfigApplicationContext(ContextConfig.class);}
}
1.3 Aware
Spring框架中的Aware接口是一组标记接口,用于将相应的资源注入到Bean中,以实现Bean对它们的感知(Awareness),以便于进行一些自定义的扩展操作。
例如,BeanNameAware接口可以让Bean对它所在的容器的名称有意识。当BeanFactory检测到某个Bean实现该接口后,会自动调用它的setBeanName()方法,将该Bean的名称作为参数传入该方法。
Spring框架提供了10余种Aware接口的子接口,每个子接口能获取到的信息不同,开发者可以根据实际情况组合这些接口。以下是其中一些较为常用的接口:
1、ApplicationContextAware:用于获取Spring容器上下文ApplicationContext对象。可以通过ApplicationContext对象获取到各种Spring容器管理的Bean实例,或者进行其他与容器相关的操作。
2、BeanNameAware:用于获取当前Bean的名称。这个Aware接口常用于在Bean内部需要获取自己的Bean名称时使用。
3、ResourceLoaderAware:用于获取ResourceLoader对象。ResourceLoader是Spring内置的一个用于加载资源(例如配置文件、图片、音频、视频等)的工具类,它可以支持多种资源的加载,包括从磁盘、网络、classpath以及URL等加载。
4、EnvironmentAware:用于获取当前应用程序所在的环境变量和系统属性。可以通过Environment对象获取当前应用程序运行的环境变量和系统属性,如当前应用程序所在的操作系统、JAVA_HOME路径、用户的home目录等。
声明com.obj.spring.AwareBean,实现BeanFactoryPostProcessor接口:
package com.obj.spring;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
@Component
public class AwareBean implements BeanNameAware, ApplicationContextAware {private ApplicationContext applicationContext;public AwareBean(){System.out.println("AwareBean构造器...");}@Overridepublic void setBeanName(String name) {System.out.println("AwareBean获取BeanName:"+name);}@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {this.applicationContext = applicationContext;}public void doSomething() {// 获取Spring容器中的另一个BeanTagService anotherBean = (TagService) applicationContext.getBean("tagService");// 执行另一个Bean的方法System.out.println(anotherBean.getTags());;}
}
声明com.obj.spring.AwareDemo:
package com.obj.spring;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class AwareDemo {public static void main(String[] args) {ApplicationContext context =new AnnotationConfigApplicationContext(ContextConfig.class);AwareBean awareBean = context.getBean(AwareBean.class);awareBean.doSomething();}
}
2. Bean的创建过程
2.1 整体阶段划分
由于Spring框架的官方文档没有明确对Bean的创建过程进行阶段划分,不同的书籍和技术类博客中对阶段的划分存在一定的差异。
下面介绍一种来自于Spring官方认证的培训文档中的划分方式。
Bean的创建步骤可以划分为三个阶段,分别是:(1)加载并处理Bean的定义,(2)Bean的实例化和(3)Bean的初始化。如下图所示:
上述划分方式与一些书籍或技术类博客中的版本的对比如下图所示:
学习Spring Bean的创建步骤,归根结底是需要掌握Spring框架中具体的执行步骤,即每一步的作用及先后顺序,阶段的划分主要起到辅助记忆的作用。在实际面试中,只要能将步骤描述清楚,使用哪个阶段划分的版本不会影响面试官对应试者的评价。
2.2 加载并处理Bean的定义
加载并处理Bean的定义阶段具体包括的步骤如下:
1、Spring启动后,根据配置文件加载Bean的定义,包括处理@Bean和@Component 注解。
2、找到Bean定义后,将转换应用于Bean定义,也就是可以进一步修改处理Bean定义。
3、在处理Bean定义的过程中调用了一系列实现了BeanFactoryPostProcessor 接口的对象。
- 其中包括处理 @PropertySource、@Value 的PropertySourcesPlaceholderConfigurer
- 其中包括处理 @Configuration 的 ConfigurationClassPostProcessor
4、可以自行扩展 BeanFactoryPostProcesser 接口,参与Bean工厂后期处理功能。
2.3 Bean的实例化
Bean的实例化阶段具体包括的步骤如下:
1、首先查找Bean的依赖关系,解决创建Bean的先后次序问题
2、实例化Bean对象,也就是创建Bean对象,这里包含构造器注入过程
3、然后进行属性注入(属性注入,方法注入)
2.4 Bean的初始化
Bean的初始化阶段具体包括的步骤如下:
1、Bean的初始化由一系列的BeanPostProcessor对象完成
2、先执行 BPP 的前置处理方法postProcessBeforeInitialization
3、然后执行Bean的自定义初始化方法
4、再执行BPP的后置处理方法postProcessAfterInitialization
这个步骤可以干预扩展,可以自行实现BeanPostProcessor。Spring的AOP代理就是在这一步添加的DefaultAdvisorAutoProxyCreator。
2.5 @Bean和 @Component
使用@Bean注解配置的Bean和使用@Component 注解配置的Bean的后处理方式是相同的。
3. 总结
1、在Spring框架中,Processor(处理器)是一种用于定制化和拓展Spring容器的机制。它是Spring框架中重要的一环,用于增强Spring容器的功能和灵活性。
- BeanPostProcessor
- BeanFactoryPostProcessor
- 开发者也可以通过自定义Processor来实现特定需求
2、Spring框架中的Aware接口是一组标记接口,用于将相应的资源注入到Bean中,以实现Bean对它们的感知(Awareness),以便于进行一些自定义的扩展操作。
- ApplicationContextAware:用于获取Spring容器上下文ApplicationContext对象
- BeanNameAware:用于获取当前Bean的名称
- ResourceLoaderAware:用于获取ResourceLoader对象
- EnvironmentAware:用于获取当前应用程序所在的环境变量和系统属性
3、Bean的创建步骤可以划分为三个阶段,分别是:(1)加载并处理Bean的定义,(2)Bean的实例化和(3)Bean的初始化。
4、加载并处理Bean的定义阶段具体包括的步骤如下:
- Spring启动后,根据配置文件加载Bean的定义,包括处理@Bean和@Component 注解
- 找到Bean定义后,将转换应用于Bean定义,也就是可以进一步修改处理Bean定义
- 在处理Bean定义的过程中调用了一系列实现了BeanFactoryPostProcessor 接口的对象
5、Bean的实例化阶段具体包括的步骤如下:
- 首先查找Bean的依赖关系,解决创建Bean的先后次序问题
- 实例化Bean对象,也就行创建Bean对象,这里包含构造器注入过程
- 然后进行属性注入(属性注入,方法注入)
6、Bean的初始化阶段具体包括的步骤如下:
- Bean的初始化由一系列的BeanPostProcessor对象完成
- 先执行 BPP 的前置处理方法postProcessBeforeInitialization
- 然后执行Bean的自定义初始化方法
- 再执行BPP的后置处理方法postProcessAfterInitialization