BeanFactory与ApplicationContext

到底什么是BeanFactory 1.他是ApplicationContext的父接口 2.他才是Spring的核心容器,主要的ApplicationContext实现都组合了它的功能 3.ctrl+alt+u看一下关系图

spring高级用法 spring 高级教程_spring高级用法


看一下BeanFactory

1.ctrl+f12看一下方法


spring高级用法 spring 高级教程_spring高级用法_02

spring高级用法 spring 高级教程_spring高级用法_03

2.可以看到BeanFactory没有特别多常用的方法,这里我们要认识到实际上一些功能,控制反转、依赖注入、直到Bean的生命周期等功能都是由BeanFactory的实现类提供的

@SpringBootApplication
public class DemoApplication {
    public static void main(String[] args) {
       //引导类中的context就是我们的spring容器
        ConfigurableApplicationContext context = SpringApplication.run(DemoApplication.class, args);
        System.out.println(context);
        Field singletonObjects = DefaultSingletonBeanRegistry.class.getDeclaredField("singletonObjects");
        singletonObjects.setAccessible(true);
        ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
        Map<String, Object> map = (Map<String, Object>) singletonObjects.get(beanFactory);
        map.forEach((k, v) -> {
            System.out.println(k + "=" +v);
        });
    }
}

ApplicationContext功能

MessageSource翻译国际化:


@SpringBootApplication
public class DemoApplication {
    public static void main(String[] args) throws Exception {
        //引导类中的context就是我们的spring容器
        ConfigurableApplicationContext context = SpringApplication.run(DemoApplication.class, args);
        //可以从配置的翻译文本中读取不同的翻译信息,web开发时中文或者英文条件从浏览器的请求头中携带过来
        context.getMessage("hello", null, Locale.CHINA);//输出hello
        context.getMessage("hello", null, Locale.ENGLISH);//输出你好
    }

}

ResourcePatternResolver

获取源路径

spring高级用法 spring 高级教程_spring高级用法_04

@SpringBootApplication
public class DemoApplication {
    public static void main(String[] args) throws Exception {
        //引导类中的context就是我们的spring容器
        ConfigurableApplicationContext context = SpringApplication.run(DemoApplication.class, args);
        //可以从配置的翻译文本中读取不同的翻译信息
        Resource[] resources = context.getResources("classpath*:META-INF/spring.factories");
        for (Resource resource : resources) {
            System.out.println(resource);
        }
    }

}

获取环境变量信息EnvironmentCapable:


@SpringBootApplication
public class DemoApplication {
    public static void main(String[] args) throws Exception {
        //引导类中的context就是我们的spring容器
        ConfigurableApplicationContext context = SpringApplication.run(DemoApplication.class, args);
        System.out.println(context.getEnvironment().getProperty("spring.messages.basename"));
    }

}

事件发布器ApplicationEventPublisher:

spring高级用法 spring 高级教程_java_05


spring高级用法 spring 高级教程_spring_06


定义事件
import org.springframework.context.ApplicationEvent;
public class StudentRegisteredEvent extends ApplicationEvent {
    public StudentRegisteredEvent(Object source) {
        super(source);
    }
    @Override
    public String toString() {
        return super.toString();
    }
}

发布事件

@SpringBootApplication
public class DemoApplication {
    public static void main(String[] args) throws Exception {
        //引导类中的context就是我们的spring容器
        ConfigurableApplicationContext context = SpringApplication.run(DemoApplication.class, args);
        context.publishEvent(new StudentRegisteredEvent(123));
    }
}

接收事件

import com.rlw.demo.event.StudentRegisteredEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Service;
@Service
public class StudentService {
    @EventListener
    public void ask(StudentRegisteredEvent event){
        System.out.println(event);
    }
}

容器实现

BeanFactory实现的特点:beanFactory不会帮我们主动调用beanFactory的后处理器,也不会主动帮助我们调用bean的后处理器,也不会初始化单例,也不会解析${}、#{},所以ApplicationContext都帮助我们做了,接下来看ApplicationContext

package com.rlw.demo.TestBean;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.annotation.AnnotationConfigUtils;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

public class TestBeanFactory {
    public static void main(String[] args) {
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();

        //bean的定义(class, scope, 初始化, 销毁)
        AbstractBeanDefinition singleton =
                BeanDefinitionBuilder.genericBeanDefinition(Config.class).setScope("singleton").getBeanDefinition();
        beanFactory.registerBeanDefinition("config", singleton);
        //给BeanFactory添加一些常用的后处理器
        AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);
//        for (String beanDefinitionName : beanFactory.getBeanDefinitionNames()) {
//            System.out.println(beanDefinitionName);
        /**
         * 还需要让这些后处理器去工作,不然不会解析config下的bean1,bean2
         *         config
         *         org.springframework.context.annotation.internalConfigurationAnnotationProcessor
         *         org.springframework.context.annotation.internalAutowiredAnnotationProcessor
         *         org.springframework.context.annotation.internalCommonAnnotationProcessor
         *         org.springframework.context.event.internalEventListenerProcessor
         *         org.springframework.context.event.internalEventListenerFactory
         */
//        }
         //beanFactory后处理器主要功能,补充了一些bean定义
         beanFactory.getBeansOfType(BeanFactoryPostProcessor.class).values().forEach(postProcessor -> { postProcessor.postProcessBeanFactory(beanFactory); });
        for (String beanDefinitionName : beanFactory.getBeanDefinitionNames()) {
            System.out.println(beanDefinitionName);
            /**
             * config
             * org.springframework.context.annotation.internalConfigurationAnnotationProcessor   ->解析@Configuration的后处理器
             * org.springframework.context.annotation.internalAutowiredAnnotationProcessor       ->解析@Autowired的后处理器
             * org.springframework.context.annotation.internalCommonAnnotationProcessor          ->解析@Resource的后处理器
             * org.springframework.context.event.internalEventListenerProcessor                  ->
             * org.springframework.context.event.internalEventListenerFactory
             * bean1
             * bean2
             */
        }
//        System.out.println(beanFactory.getBean(Bean1.class).getBean2() + "扩展bean处理器前"); //输出null
        //Bean后处理器,针对bean的生命周期的各个阶段提供扩展,例如@Autowired @Resource
        beanFactory.preInstantiateSingletons();//提前创建好单例bean,如果没有此行代码,都是懒惰式创建,什么时候用什么时候创建实例,工厂中只是存储了bean的名称
        beanFactory.getBeansOfType(BeanPostProcessor.class).values().forEach(beanFactory::addBeanPostProcessor);//假如一个接口存在多个实现类,我们依赖注入这个接口,能否依赖注入成功?答案是一般不行,除非依赖注入的接口名称 == 要注入的实例,或者使用@Qualifier限制,假如依赖注入同时使用了@Resource与@Aotowred,@Aotowred的优先级要高,在添加bean的后处理器代码顺序@Aotowred在前,可以手动调整
        System.out.println(beanFactory.getBean(Bean1.class).getBean2() + "扩展bean处理器后"); //输出bean2对象
    }

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

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

        public Bean1() {
            System.out.println("bean1");
        }

        @Autowired
        private Bean2 bean2;

        public Bean2 getBean2() {
            return bean2;
        }
    }

    static class Bean2 {
        public Bean2() {
            System.out.println("bean2");
        }
    }
}

ApplicationContext实现:

通过类路径下的xml的方式去注入bean

<?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">

    <bean id="bean1" class="com.rlw.demo.TestBean.Bean1"></bean>
    <bean id="bean2" class="com.rlw.demo.TestBean.Bean2"></bean>
    //beanfactory的后处理器
    <context:annotation-config/>
</beans>
@SpringBootApplication
public class DemoApplication {
    public static void main(String[] args) throws Exception {
        ClassPathXmlApplicationContext context1 = new ClassPathXmlApplicationContext("b01.xml");
        for (String beanDefinitionName : context1.getBeanDefinitionNames()) {
            System.out.println(beanDefinitionName);
        }
    }
}


@SpringBootApplication
public class DemoApplication {
    public static void main(String[] args) throws Exception {
        FileSystemXmlApplicationContext fileSystemXmlApplicationContext = new FileSystemXmlApplicationContext("D:\\spring29\\src\\main\\resources\\b01.xml");
        for (String beanDefinitionName : fileSystemXmlApplicationContext.getBeanDefinitionNames()) {
            System.out.println(beanDefinitionName);
        }
    }
}

读取xml的原理,我们都知道ApplicationContext是基于BeanFactory去注入bean的,也就是基于BeanFactory去组合的功能

@SpringBootApplication
public class DemoApplication {
    public static void main(String[] args) throws Exception {
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        System.out.println("读取xml之前");
        for (String name : beanFactory.getBeanDefinitionNames()) {
            System.out.println(name);//输出null
        }
        System.out.println("读取xml之后");
        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
        reader.loadBeanDefinitions("b01.xml");
        for (String beanDefinitionName : beanFactory.getBeanDefinitionNames()) {
            System.out.println(beanDefinitionName);//输出bean1,bean2
        }
    }
}

基于java配置类:

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

    @Bean
    public Bean2 bean2() {
        return new Bean2();
    }
}
@SpringBootApplication
public class DemoApplication {
    public static void main(String[] args) throws Exception {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config2.class);
        for (String beanDefinitionName : context.getBeanDefinitionNames()) {
            System.out.println(beanDefinitionName);
        }
        /**
         * org.springframework.context.annotation.internalConfigurationAnnotationProcessor
         * org.springframework.context.annotation.internalAutowiredAnnotationProcessor
         * org.springframework.context.annotation.internalCommonAnnotationProcessor
         * org.springframework.context.event.internalEventListenerProcessor
         * org.springframework.context.event.internalEventListenerFactory
         * config2
         * bean1
         * bean2
         */
    }
}

基于java配置类来创建,用于web环境

@Configuration
public class WebConfig {
    @Bean
    public ServletWebServerFactory servletWebServerFactory() {
        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 ((request, response) -> {
            response.getWriter().printf("hello");
            return null;
        }
        );
    }
}
@SpringBootApplication
public class DemoApplication {
    public static void main(String[] args) throws Exception {
        AnnotationConfigServletWebServerApplicationContext annotationConfigServletWebServerApplicationContext = new AnnotationConfigServletWebServerApplicationContext(WebConfig.class);
    }
}

Bean的生命周期

生命周期的各个阶段:在各个阶段都可以使用bean后处理进行相应的增强功能

@Component
public class LifeCycleBean {
    public LifeCycleBean() {
        System.out.println("构造方法");
    }

    @Autowired
    public void autowired(@Value("${JAVA_HOME}") String name) {
        System.out.println("依赖注入:" + name);
    }

    @PostConstruct
    public void init() {
        System.out.println("初始化");
    }

    @PreDestroy
    public void destroy(){
        System.out.println("销毁");
    }
}

构造方法
依赖注入:C:\Program Files\Java\jdk1.8.0_201
初始化
bean1…
bean2…
2022-09-30 16:57:53.452 INFO 352996 — [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ‘’
2022-09-30 16:57:53.461 INFO 352996 — [ main] com.rlw.demo.A01Application : Started A01Application in 1.993 seconds (JVM running for 2.902)
2022-09-30 16:57:53.615 INFO 352996 — [ main] o.apache.catalina.core.StandardService : Stopping service [Tomcat]
销毁

待续