【观察者模式】BeanFactory与ApplicationContext基本介绍

接口定义能力,抽象类实现接口的一些重要方法,最后实现类可以实现自己的一些逻辑

BeanFactory简介

仅仅是一个接口,Spring 的核心容器,并不是IOC容器的具体实现,它的一些具体实现类才是

BeanFactory 与 ApplicationContext 的区别

  • BeanFactory 是 ApplicationContext 的父接口
  • BeanFactory才是 Spring 的核心容器, 主要的 ApplicationContext 实现和【组合】了它的功能

image-20230709003040397

BeanFactory的作用

image-20230709000235024

  • 表面上只有 getBean(通过名称或者类型)
  • 实际上控制反转、基本的依赖注入、直至 Bean 的生命周期的各种功能, 都由它的实现类提供

SpringBoot启动方法返回对象就是BeanFactory实现类之一ConfigurableApplicationContext

image-20230709003144875

@SpringBootApplication
public class SpringDemoApplication {

    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(SpringDemoApplication.class, args);
        System.out.println(context);
    }
}

DefaultListableBeanFactory是一个比较重要的实现类

image-20230708225041588

使用反射,通过其一个父类DefaultSingletonBeanRegistry获得spring容器中以component名称开头的Bean对象:

public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {
    // beanName -> 单例对象
    private final Map<String, Object> singletonObjects = new ConcurrentHashMap(256);
    // ...
}
        ConfigurableApplicationContext context = SpringApplication.run(SpringDemoApplication.class, args);
        Field singletonObjects = DefaultSingletonBeanRegistry.class.getDeclaredField("singletonObjects");
        // 私有属性设置可访问
        singletonObjects.setAccessible(true);
        ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
		// 通过反射获得类中属性
        Map<String, Object> map = (Map<String, Object>) singletonObjects.get(beanFactory);
        map.entrySet().stream().filter(e -> e.getKey().startsWith("component"))
                .forEach(e -> {
                    System.out.println(e.getKey() + "=" + e.getValue());
                });

ApplicationContext的主要功能

四大功能

来源于四个父接口

image-20230709015433475

MessageSource-国际化资源

准备不同国际语言配置文件:

image-20230709004645884

打印不同配置文件的内容:

        System.out.println(context.getMessage("hi", null, Locale.CHINA));
        System.out.println(context.getMessage("hi", null, Locale.ENGLISH));
        System.out.println(context.getMessage("hi", null, Locale.JAPANESE));

ResourcePatternResolver-通配符匹配资源

获取指定路径下的资源:

        Resource[] resources = context.getResources("classpath*:META-INF/spring.factories");
        for (Resource resource : resources) {
            System.out.println(resource);
        }

EnvironmentCapable-处理环境信息

打印配置信息:

        // java配置信息
		System.out.println(context.getEnvironment().getProperty("java_home"));
		// yml配置信息
        System.out.println(context.getEnvironment().getProperty("server.port"));

【观察者模式】ApplicationEventPublisher-发布事件对象【事件解耦】

首先定义不同事件对象

// 继承类且无需@Component注解,也可以自定义属性在事件对象中
public class UserRegisteredEvent extends ApplicationEvent {
    public UserRegisteredEvent(Object source) {
        super(source);
    }
}

其次发布者发布事件

@Component
public class ComponentPublisher {

    private static final Logger log = LoggerFactory.getLogger(ComponentPublisher.class);

	// 实际上是该类 ApplicationContext
    @Autowired
    private ApplicationEventPublisher publisher;

    public void register() {
        log.debug("用户注册");
        // source:发布消息
        publisher.publishEvent(new UserRegisteredEvent(this));
    }
}

最后不同对象处理事件(监听事件)

@Component
public class ComponentListener {

    private static final Logger log = LoggerFactory.getLogger(ComponentListener.class);

    // 注解,监听事件对象
    @EventListener(UserRegisteredEvent.class)
    public void sendMsg(UserRegisteredEvent event) {
        log.debug("{}", event);
        log.debug("发送短信操作");
    }
}

或者:用这种方式监听事件(两者二选一),如一个事件有多个监听器,可以使用@Order注解,决定执行顺序,越小越先执行

@Order(0) // 越小越先执行
@Component
// 实现接口
public class ComponentListener1 implements ApplicationListener<UserRegisteredEvent> {

    private static final Logger log = LoggerFactory.getLogger(ComponentListener1.class);
    
    public void sendMsg(UserRegisteredEvent event) {
        log.debug("{}", event);
        log.debug("发送短信操作");
    }
}

BeanFactory常见实现类

image-20230709011539214

DefaultListableBeanFactory

DefaultListableBeanFactory只是一个空的容器,需要往容器里注册一些bean,默认没有一些后置处理器,要想具备这些功能,需要手动添加后置处理器并且执行

public class TestBeanFactory {

    public static void main(String[] args) {
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        // bean 的定义(class, scope, 初始化, 销毁)
        AbstractBeanDefinition beanDefinition =
BeanDefinitionBuilder.genericBeanDefinition(Config.class).setScope("singleton").getBeanDefinition();
        beanFactory.registerBeanDefinition("config", beanDefinition);

        // 给 BeanFactory 添加一些常用的后处理器 同时也会设置比较器
        AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);

        // BeanFactory 后处理器主要功能,补充了一些 bean 定义
        beanFactory.getBeansOfType(BeanFactoryPostProcessor.class).values().forEach(beanFactoryPostProcessor -> {
            beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);
        });

        // Bean 后处理器, 针对 bean 的生命周期的各个阶段提供扩展, 例如 @Autowired @Resource ...
        beanFactory.getBeansOfType(BeanPostProcessor.class).values().stream()
                // 这里就可以获取比较器了
                .sorted(beanFactory.getDependencyComparator())
                .forEach(beanPostProcessor -> {
            System.out.println(">>>>" + beanPostProcessor);
            beanFactory.addBeanPostProcessor(beanPostProcessor);
        });

        for (String name : beanFactory.getBeanDefinitionNames()) {
            System.out.println(name);
        }

        // 准备好所有单例	
        beanFactory.preInstantiateSingletons(); 
        System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ");
//        默认延迟创建bean对象
//        System.out.println(beanFactory.getBean(Bean1.class).getBean2());
        System.out.println(beanFactory.getBean(Bean1.class).getInter());

        System.out.println("Common:" + (Ordered.LOWEST_PRECEDENCE - 3));
        System.out.println("Autowired:" + (Ordered.LOWEST_PRECEDENCE - 2));
    }

    @Configuration
    static class Config {
        @Bean
        public Bean1 bean1() {
            return new Bean1();
        }

        @Bean
        public Bean2 bean2() {
            return new Bean2();
        }

        @Bean
        public Bean3 bean3() {
            return new Bean3();
        }

        @Bean
        public Bean4 bean4() {
            return new Bean4();
        }
    }

    interface Inter {

    }

    static class Bean3 implements Inter {

    }

    static class Bean4 implements Inter {

    }

    static class Bean1 {
        private static final Logger log = LoggerFactory.getLogger(Bean1.class);

        public Bean1() {
            log.debug("构造 Bean1()");
        }

        @Autowired
        private Bean2 bean2;

        public Bean2 getBean2() {
            return bean2;
        }

        @Autowired
        @Resource(name = "bean4")
        private Inter bean3;

        public Inter getInter() {
            return bean3;
        }
    }

    static class Bean2 {
        private static final Logger log = LoggerFactory.getLogger(Bean2.class);

        public Bean2() {
            log.debug("构造 Bean2()");
        }
    }
}

image-20230709010752587

image-20230709010939901

小结

  • beanFactory 不会做的事

  • 不会主动添加、调用 BeanFactory 后置处理器

  • 不会主动添加 Bean 后置处理器

  • 不会主动初始化单例

  • 不会解析beanFactory 还不会解析 ${ } 与 #{ }

  • bean 后处理器会有排序的逻辑 根据order排序

ApplicationContext常见实现类

image-20230709013020574

ApplicationContext相当于会自动给BeanFactory容器后置处理器,操作更加方便一点

public class TestApplicationContext {
    private static final Logger log = LoggerFactory.getLogger(TestApplicationContext.class);

    public static void main(String[] args) {
        testClassPathXmlApplicationContext();
//        testFileSystemXmlApplicationContext();
//        testAnnotationConfigApplicationContext();
//        testAnnotationConfigServletWebServerApplicationContext();

        /*
            学到了什么
                a. 常见的 ApplicationContext 容器实现
                b. 内嵌容器、DispatcherServlet 的创建方法、作用
         */
    }

    // 较为经典的容器, 基于 classpath 下 xml 格式的配置文件来创建
    private static void testClassPathXmlApplicationContext() {
        ClassPathXmlApplicationContext context =
                new ClassPathXmlApplicationContext("spring-beans.xml");

        for (String name : context.getBeanDefinitionNames()) {
            System.out.println(name);
        }

        System.out.println(context.getBean(Bean2.class).getBean1());
    }

    // 基于磁盘路径下 xml 格式的配置文件来创建
    private static void testFileSystemXmlApplicationContext() {
        FileSystemXmlApplicationContext context =
                new FileSystemXmlApplicationContext(
                        "src\\main\\resources\\spring-beans.xml");
        for (String name : context.getBeanDefinitionNames()) {
            System.out.println(name);
        }

        System.out.println(context.getBean(Bean2.class).getBean1());
    }

    // 较为经典的容器, 基于 java 配置类来创建
    private static void testAnnotationConfigApplicationContext() {
        AnnotationConfigApplicationContext context =
                new AnnotationConfigApplicationContext(Config.class);

        for (String name : context.getBeanDefinitionNames()) {
            System.out.println(name);
        }

        System.out.println(context.getBean(Bean2.class).getBean1());
    }

    // 较为经典的容器, 基于 java 配置类来创建, 用于 web 环境
    private static void testAnnotationConfigServletWebServerApplicationContext() {
        AnnotationConfigServletWebServerApplicationContext context =
                new AnnotationConfigServletWebServerApplicationContext(WebConfig.class);
        for (String name : context.getBeanDefinitionNames()) {
            System.out.println(name);
        }
    }

    @Configuration
    static class WebConfig {

        /**
         * 注册Tomcat服务器
         */
        @Bean
        public ServletWebServerFactory servletWebServerFactory(){
            return new TomcatServletWebServerFactory();
        }

        /**
         * 注册 DispatcherServlet
         */
        @Bean
        public DispatcherServlet dispatcherServlet() {
            return new DispatcherServlet();
        }

        /**
         * 注册 DispatcherServlet路径 到 Tomcat 服务器上
         */
        @Bean
        public DispatcherServletRegistrationBean registrationBean(DispatcherServlet dispatcherServlet) {
            return new DispatcherServletRegistrationBean(dispatcherServlet, "/");
        }
        @Bean("/hello")
        public Controller controller1() {
            return (request, response) -> {
                response.getWriter().print("hello");
                return null;
            };
        }
    }

    @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;
        }
    }

    static class Bean1 {
    }

    static class Bean2 {

        private Bean1 bean1;

        public void setBean1(Bean1 bean1) {
            this.bean1 = bean1;
        }

        public Bean1 getBean1() {
            return bean1;
        }
    }
}

ClassPathXmlApplicationContext

较为经典的容器, 基于 classpath 下 xml 格式的配置文件来创建

	private static void testClassPathXmlApplicationContext() {
        ClassPathXmlApplicationContext context =
                new ClassPathXmlApplicationContext("spring-beans.xml");

        for (String name : context.getBeanDefinitionNames()) {
            System.out.println(name);
        }

        System.out.println(context.getBean(Bean2.class).getBean1());
    }


	// 以上代码相当于
    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 ClassPathResource("spring-beans.xml"));
    for (String name : beanFactory.getBeanDefinitionNames()) {
        System.out.println(name);
    }

spring-beans.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!-- 控制反转, 让 bean1 被 Spring 容器管理 -->
    <bean id="bean1" class="com.lkl.spring.chapter2.TestApplicationContext.Bean1"/>

    <!-- 控制反转, 让 bean2 被 Spring 容器管理 -->
    <bean id="bean2" class="com.lkl.spring.chapter2.TestApplicationContext.Bean2">
        <!-- 依赖注入, 建立与 bean1 的依赖关系 -->
        <property name="bean1" ref="bean1"/>
    </bean>
</beans>

FileSystemXmlApplicationContext

基于磁盘路径下 xml 格式的配置文件来创建

	private static void testFileSystemXmlApplicationContext() {
        FileSystemXmlApplicationContext context =
                new FileSystemXmlApplicationContext(
                        "src\\main\\resources\\spring-beans.xml");
        for (String name : context.getBeanDefinitionNames()) {
            System.out.println(name);
        }

        System.out.println(context.getBean(Bean2.class).getBean1());
    }

	// 相当于
    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-beans.xml"));
    for (String name : beanFactory.getBeanDefinitionNames()) {
        System.out.println(name);
    }

AnnotationConfigApplicationContext

较为经典的容器,基于 java 配置类来创建

	private static void testAnnotationConfigApplicationContext() {
        AnnotationConfigApplicationContext context =
                new AnnotationConfigApplicationContext(Config.class);

        for (String name : context.getBeanDefinitionNames()) {
            System.out.println(name);
        }

        System.out.println(context.getBean(Bean2.class).getBean1());
    }
    @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;
        }
    }

    static class Bean1 {
    }

    static class Bean2 {

        private Bean1 bean1;

        public void setBean1(Bean1 bean1) {
            this.bean1 = bean1;
        }

        public Bean1 getBean1() {
            return bean1;
        }
    }

AnnotationConfigServletWebServerApplicationContext

较为经典的容器,基于 java 配置类来创建,用于 web 环境【内嵌Tomcat】

	private static void testAnnotationConfigServletWebServerApplicationContext() {
        AnnotationConfigServletWebServerApplicationContext context =
                new AnnotationConfigServletWebServerApplicationContext(WebConfig.class);
        for (String name : context.getBeanDefinitionNames()) {
            System.out.println(name);
        }
    }
    @Configuration
    static class WebConfig {

        /**
         * 注册Tomcat服务器
         */
        @Bean
        public ServletWebServerFactory servletWebServerFactory() {
            return new TomcatServletWebServerFactory();
        }

        /**
         * 注册 DispatcherServlet
         */
        @Bean
        public DispatcherServlet dispatcherServlet() {
            return new DispatcherServlet();
        }

        /**
         * 注册 DispatcherServlet路径 到 Tomcat 服务器上
         */
        @Bean
        public DispatcherServletRegistrationBean registrationBean(DispatcherServlet dispatcherServlet) {
            return new DispatcherServletRegistrationBean(dispatcherServlet, "/");
        }

        /**
         * 提供一个web访问接口
         */
        @Bean("/hello")
        public Controller controller1() {
            return (request, response) -> {
                response.getWriter().print("hello");
                return null;
            };
        }
    }

启动容器,访问http://localhost:8080/hello可以得到相应的响应

image-20230709015152350

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不进大厂不改名二号

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值