BeanFactory与ApplicationContext的实现
本文为学习笔记
BeanFactory和ApplicationContext 的实现
1、@Bean注解是BeanFactory 的后处理器的Buff 2、@AutoWire、@Resource是Bean的后处理器,bean 的后处理器是针对Bean的生命周期的扩展 3、beanFactory默认情况下读到@bean、@autowired 是不会创建对象的,而只是保留一个名字,getBean()时才会创建对象。可以使用beanfactory.preInstantiateSignletons()来初始化单例对象 4、不会主动解析 ${} 和 #{}
1、BeanFactory 的实现
1、最重要的实现:DefaultListBeanFactory 要创建bean,首先要定义Bean,(class、scope(单例、多例)、初始化、销毁等信息) 2、首先使用BeanDefinitionBuilder.genericBeanDefinition(Config.class).setScope("singleton").getBeanDefinition()创建一个单例的Config beanDefinition 。在使用Beanfactory 创建一个指定名字和Beanfinition 的类。注意:BeanFactory默认情况下不会读取注解,即不会创建Config 里面的@Bean声明的对象 3、解决BeanFactory 不能做到的事: AnnotationConfigUtils.registerAnnotationConfigProfessor 添加后处理器
源码:
public class TestConfig { public static void main(String[] args) { //创建工厂,之前说过这个类可以创建众多类型的 Bean 如何实现: DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); //创建类的定义 AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(MyConfig.class).setScope("singleton").getBeanDefinition(); //把类的定义交给工厂创建一个 bean :config beanFactory.registerBeanDefinition("config",beanDefinition); //遍历:在这里还没有给 beanFactory 加Buff 它只能创建config 而不能创建 bean1 和 bean2 System.out.println("解析之前=================================="); for (int i = 0; i < beanFactory.getBeanDefinitionNames().length; i++) { System.out.println(beanFactory.getBeanDefinitionNames()[i]); } //给 beanFactory 加一些后处理器 AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory); //使这些处理器生效,根据type 获取后处理器 依次执行 beanFactory.getBeansOfType(BeanFactoryPostProcessor.class).values().stream().forEach((pro->{ pro.postProcessBeanFactory(beanFactory); })); System.out.println("解析之后=================================="); for (int i = 0; i < beanFactory.getBeanDefinitionNames().length; i++) { System.out.println(beanFactory.getBeanDefinitionNames()[i]); } //添加Bean的后处理器,使 @autowired 、@resource 生效 beanFactory.getBeansOfType(BeanPostProcessor.class).values().forEach(beanFactory::addBeanPostProcessor); //调用 getBean()之前 beanFactory.preInstantiateSingletons(); System.out.println("调用 getBean()之前>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"); System.out.println(beanFactory.getBean(Bean1.class).getBean2()); } @Configuration static class MyConfig{ @Bean public Bean1 bean1(){ return new Bean1(); } @Bean public Bean2 bean2(){ return new Bean2(); } } static class Bean1{ private Logger logger = LoggerFactory.getLogger(Bean1.class); public Bean1(){ logger.debug("bean1 create ---"); } @Autowired private Bean2 bean2; public Bean2 getBean2(){return bean2;}; } static class Bean2{ private Logger logger = LoggerFactory.getLogger(Bean2.class); public Bean2(){ logger.debug("bean2 create ---"); } } }
结果:
1、添加BeanFactoryPostProcessor
2、添加BeanPostProcessor
3、添加preInstantiateSignletons()
2、applicationContext 的 实现
四个实现类: classpathApplicationContext:基于classpath 下的 xml 配置文件来创建 Bean filesystemApplicationContext:基于磁盘路径下的 xml 配置文件来创建 Bean annotationConfigApplicationContext :基于 java 配置类来创建Bean AnnotationConfigServletWebServerApplicationContext:基于java配置类来创建Bean,用于 web 环境
类结构:
public class testApplicationContext { public static void main(String[] args) { } static class Bean1{ } static class Bean2{ private Bean1 bean1; public Bean1 getBean1() { return bean1; } public void setBean1(Bean1 bean1) { this.bean1 = bean1; } } }
2.1、classpathApplicationContext 和 filesystemApplicationContext
-
还是要先创建类定义再创建类和类的对象,不过这次是通过 xml 文件配置类的定义而不是代码
-
classpathApplicationContext 查找的是resource目录下的文件, filesystemApplicationContext查找的是绝对路径,可以直接从盘符写,也可以从src目录写,后者前提是当前路径是本项目的路径
代码:
public static void main(String[] args) { classpathXmlApplicationContext(); fileSystemXmlApplicationContext(); } public static void classpathXmlApplicationContext(){ System.out.println("这是classpathXmlApplicationContext-------------------"); ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("a1.xml"); Arrays.stream(context.getBeanDefinitionNames()).forEach(System.out::println); System.out.println(context.getBean(Bean2.class).getBean1()); } public static void fileSystemXmlApplicationContext(){ System.out.println("这是fileSystemXmlApplicationContext-------------------"); FileSystemXmlApplicationContext context = new FileSystemXmlApplicationContext("src/main/resources/a1.xml"); Arrays.stream(context.getBeanDefinitionNames()).forEach(System.out::println); System.out.println(context.getBean(Bean2.class).getBean1()); } <bean id="bean1" class="com.test.testApplicationContext.Bean1"/> <bean id="bean2" class="com.test.testApplicationContext.Bean2"> <property name="bean1" ref="bean1"/> </bean> 指定项目工作目录
-
原理:这哥俩里面还是内置了beanFactory ,另外加上了 XmlBeanDefinitionReader 来读取xml 里面的内容就好了
//getBeanName 是自己写的遍历方法 DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); System.out.println("读取xml文件之前-------------"); getBeanName(beanFactory); //读取xml文件的对象 XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory); reader.loadBeanDefinitions(new ClassPathResource("a1.xml")); System.out.println("读取xml文件之后-------------"); getBeanName(beanFactory);
2.2、annotationConfigApplicationContext
-
添加 config 类 ,加上 @Configuration 注解。自动扫描配置类,追加关于注解扫秒的后处理器
-
作用等同于在前面两个的 spring.xml 文件里面添加
<bean:annotation-config/> public static void annotationConfigApplicationContext(){ AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(config.class); Arrays.stream(context.getBeanDefinitionNames()).forEach(System.out::println); } @Configuration static class config{ @Bean public Bean1 bean1(){ return new Bean1(); } @Bean public Bean2 bean2(Bean1 bean1){ Bean2 bean2 = new Bean2(); bean2.setBean1(bean1); return bean2; } }
2.3、AnnotationConfigServletWebServerApplicationContext
至少需要三个 Bean 来实现 web 功能: 他们都来自 springframework.web.servlet 包 1、创建web容器:ServletWebServerFactory 2、创建servlet: DispatcherServlet 3、将 servlet 注册到容器中:DispatcherServletRegistrationBean 4、添加controller 访问路径:Controller (不必要)
public static void annotationConfigServletWebServerApplicationContext(){ AnnotationConfigServletWebServerApplicationContext context = new AnnotationConfigServletWebServerApplicationContext(webConfig.class); Arrays.stream(context.getBeanDefinitionNames()).forEach(System.out::println); } @Configuration static class webConfig{ //三个必要的 Bean : @Bean public ServletWebServerFactory serverFactory(){ return new TomcatServletWebServerFactory(); } @Bean public DispatcherServlet dispatcherServlet(){ return new DispatcherServlet(); } @Bean public DispatcherServletRegistrationBean registrationBean(DispatcherServlet dispatcherServlet){ return new DispatcherServletRegistrationBean(dispatcherServlet,"/"); } @Bean("/hello") public Controller controller(){ return (HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) ->{ httpServletResponse.getWriter().println("hello , AnnotationConfigServletWebServerApplicationContext"); return null; }; } }
观察控制台:创建顺序:关于的注解和事件监听的后处理器 --> servletFactory --> 配置类webConfig --> 初始化Tomcat -->初始化webApplicationContext --> 创建registrationBean --> 创建dispatcherServlet并注册 / -->创建 controller Bean -->启动 tomcat 和 webservletGracefulShutdown Bean
容器里面的 BeanDefinition :
访问:
分类:
Spring原理
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具