BeanFactory
- Spring之BeanFactory
- 什么是BeanFactory
- ApplicationContext相對BeanFactory實現的功能性擴展
- 1. MessageSource
- 2. ResourcePatternResolver
- 3. ApplicationEventPublisher
- 4. EnvironmentCapable
- 通用ApplicationContext實踐實現BeanFactory
- BeanFactory后處理器排序讓誰優先執行
- 第一種實現通過xml等方式實現的bean注入原理
- 第二種基于磁盤路徑下 xml 格式的配置文件來創建
- 第三種較為經典的容器,基于java配置類來創建
- 第四種較為經典的容器,基于java配置類來創建,并且還可以用于web環境
Spring之BeanFactory
什么是BeanFactory
BeanFactory是SpringApplication類的父類接口
BeanFactory才是Spring的核心容器,主要的SpringApplication類都組合了他的功能。
通過Ctrl+alt+u可以看到
可以從圖片中看到SpringApplication是繼承了BeanFactory接口對BeanFactory進行了功能性的擴展。
比如SpringApplication獲取一個bean的對象
run.getBean(BreadRollMallServer.class);
他實際上是通過組合了BeanFactory實現找個獲取對象的功能,可以看出來SpringApplication是間接的調用了BeanFactory的功能
ApplicationContext相對BeanFactory實現的功能性擴展
1. MessageSource
MessageSource 是 Spring 框架里用于消息解析與國際化的核心接口。借助它,你能夠依據不同的語言環境獲取對應的文本消息,從而實現國際化支持。像錯誤消息、提示信息這類文本內容,就可以通過 MessageSource 進行管理。
2. ResourcePatternResolver
ResourcePatternResolver 接口可用來解析資源路徑,并且支持使用通配符來匹配多個資源。它是 ResourceLoader 的擴展,能夠依據給定的資源路徑模式查找多個資源。在加載配置文件、靜態資源等場景中會經常用到。
3. ApplicationEventPublisher
ApplicationEventPublisher 接口提供了發布應用事件的功能。在 Spring 應用里,事件機制是一種重要的設計模式,允許組件之間以松耦合的方式進行通信。通過 ApplicationEventPublisher,你可以發布自定義的應用事件,其他組件可以監聽這些事件并做出響應。
應用場景:用戶注冊時候的發短信發郵件。
4. EnvironmentCapable
EnvironmentCapable 接口表明一個對象具備獲取 Environment 對象的能力。Environment 對象封裝了應用程序運行時的環境信息,包含系統屬性、環境變量、配置文件屬性等。借助 Environment,你可以方便地獲取和管理這些屬性。
通用ApplicationContext實踐實現BeanFactory
public class TestBeanFactory {public static void main(String[] args) {DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();// bean 的定義(class(類型), scope(單例or多例), 初始化方法, 銷毀方法)// BeanDefinitionBuilder..xxx.xxx.xxx.getBeanDefinition()AbstractBeanDefinition beanDefinition =BeanDefinitionBuilder.genericBeanDefinition(Config.class).setScope("singleton").getBeanDefinition();//(beanName,xxx)將bean注冊到bean工廠中beanFactory.registerBeanDefinition("config", beanDefinition);// 【重點】給 BeanFactory 添加一些常用的后處理器(對BeanFactory的擴展) //將后處理添加到bean工廠AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);// BeanFactory 后處理器主要功能,補充了一些 bean 定義// beanFactory.getBeansOfType 根據類型獲取多個bean//BeanFactoryPostProcessor.class拿到bean工廠的所有后處理器,對bean工廠做出擴展就可以解析@bean注解等。beanFactory.getBeansOfType(BeanFactoryPostProcessor.class).values().forEach(beanFactoryPostProcessor -> {//拿到bean工廠的所有后處理器并且執行beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);//執行BeanFactory后置處理器});// 添加 BeanPostProcessor 也就是添加bean的后處理器//bean后處理器 針對bean的生命周期各個階段進行擴展,例如@Autowire @ResousebeanFactory.getBeansOfType(BeanPostProcessor.class).values().forEach(beanFactory::addBeanPostProcessor);for (String name : beanFactory.getBeanDefinitionNames()) {System.out.println(name);}}@Configurationstatic class Config {@Beanpublic Bean1 bean1() {return new Bean1();}@Beanpublic Bean2 bean2() {return new Bean2();}}static class Bean1 {private static final Logger log = LoggerFactory.getLogger(Bean1.class);@Autowiredprivate Bean2 bean2;}static class Bean2 {private static final Logger log = LoggerFactory.getLogger(Bean2.class);}
}
通過這個案例,你可以看到如何使用 DefaultListableBeanFactory 創建和管理 Bean,以及如何使用后置處理器在 Bean 的生命周期中執行自定義邏輯。
區別對比
- 作用時機
BeanFactoryPostProcessor:在 BeanFactory 完成 Bean 定義的加載之后,但在 Bean 實例化之前執行。也就是說,它處理的是 Bean 的定義信息,而不是 Bean 實例。
BeanPostProcessor:在 Bean 實例化之后,初始化前后執行。它作用于已經創建好的 Bean 實例。 - 作用對象
BeanFactoryPostProcessor:作用于 BeanFactory 本身,主要用于修改 BeanFactory 中 Bean 的定義信息,例如修改 Bean 的屬性值、作用域等。
BeanPostProcessor:作用于具體的 Bean 實例,允許開發者在 Bean 初始化前后對其進行定制化處理。 - 功能側重點
BeanFactoryPostProcessor:側重于對 Bean 定義的全局修改和擴展,例如動態添加或修改 Bean 定義,調整 Bean 的配置等。
BeanPostProcessor:側重于對 Bean 實例的個性化處理,例如對 Bean 進行增強、驗證、日志記錄等。
總結:
1.bean工廠不會主動調用beanFactory后處理器
2.bean不會主動添加后處理器
3.不會主動初始化單例
4.不會解析BeanFactory
BeanFactory后處理器排序讓誰優先執行
第一種實現通過xml等方式實現的bean注入原理
通過xml注入bean容器
// ??1.最為經典的容器,基于classpath 下 xml 格式的配置文件來創建public void testClassPathXmlApplicationContext() {ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring_bean.xml");for (String name : context.getBeanDefinitionNames()) {System.out.println(name);}System.out.println(context.getBean(Bean2.class).getBean1());}
第二種基于磁盤路徑下 xml 格式的配置文件來創建
//基于磁盤路徑下 xml 格式的配置文件來創建DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();System.out.println("讀取之前");for (String name : beanFactory.getBeanDefinitionNames()) {System.out.println(name);}System.out.println("讀取之后");XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);;reader.loadBeanDefinitions(new FileSystemResource("src\\main\\resources\\spring_bean.xml"));for (String name : beanFactory.getBeanDefinitionNames()) {System.out.println(name);}
第三種較為經典的容器,基于java配置類來創建
較為經典的容器,基于java配置類來創建,通過這個配置類創建會幫我們創建后處理器了來解析@Bean注解
// ??3.較為經典的容器,基于java配置類來創建public void testAnnotationConfigApplicationContext() {// 會自動加上5個后處理器// org.springframework.context.annotation.internalConfigurationAnnotationProcessor// org.springframework.context.annotation.internalAutowiredAnnotationProcessor// org.springframework.context.annotation.internalCommonAnnotationProcessor// org.springframework.context.event.internalEventListenerProcessor// org.springframework.context.event.internalEventListenerFactoryAnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);for (String name : context.getBeanDefinitionNames()) {System.out.println(name);}System.out.println(context.getBean(Bean2.class).getBean1());}
// 單元測試的過程中如果要解析一些Spring注解,比如@Configuration的時候不要把相關類定義到寫單元測試類的內部類,會讀取不到
@Configuration
class Config {@Beanpublic Bean1 bean1() {return new Bean1();}@Beanpublic Bean2 bean2(Bean1 bean1) {Bean2 bean2 = new Bean2();bean2.setBean1(bean1);return bean2;}
}class Bean1 {}class Bean2 {private Bean1 bean1;public Bean1 getBean1() {return bean1;}public void setBean1(Bean1 bean1) {this.bean1 = bean1;}
}
第四種較為經典的容器,基于java配置類來創建,并且還可以用于web環境
// 模擬了 springboot web項目內嵌Tomcat的工作原理public void testAnnotationConfigServletWebServerApplicationContext() throws IOException {AnnotationConfigServletWebServerApplicationContext context = new AnnotationConfigServletWebServerApplicationContext(WebConfig.class);// 防止程序終止System.in.read();}@Configuration
class WebConfig {@Bean// 1. WebServer工廠public ServletWebServerFactory servletWebServerFactory() {return new TomcatServletWebServerFactory();}@Bean// 2. web項目必備的DispatcherServletpublic DispatcherServlet dispatcherServlet() {return new DispatcherServlet();}@Bean// 3. 將DispatcherServlet注冊到WebServer上public DispatcherServletRegistrationBean dispatcherServletRegistrationBean(DispatcherServlet dispatcherServlet) {return new DispatcherServletRegistrationBean(dispatcherServlet, "/");}@Bean("/hello")public Controller controller1() {return (request, response) -> {response.getWriter().println("hello");return null;};}
}