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 :

访问:

posted @   心是冰冰的  阅读(80)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示