零、本文纲要
- 一、容器接口
1、BeanFactory与ApplicationContext
2、BeanFactory接口
① DefaultListableBeanFactory类
3、ApplicationContext接口
① 实现MessageSource接口
② 实现ResourcePatternResolver接口
③ 实现EnvironmentCapable接口
④ 实现ApplicationEventPublisher接口
- 二、容器实现
1、BeanFactory实现
① DefaultListableBeanFactory类
② 注册各类后置处置处罚器
③ beanFactory后置处置处罚器
④ bean后置处置处罚器
⑤ preInstantiateSingletons初始化
增补:AnnotationConfigUtils类
2、ApplicationContext实现
① ClassPathXmlApplicationContext类
② FileSystemXmlApplicationContext类
增补:XmlBeanDefinitionReader类
③ AnnotationConfigApplicationContext类
增补:<context:annotation-config/>
④ AnnotationConfigServletWebServerApplicationContext类
一、容器接口
0、底子准备
添加最底子的Spring Boot依赖,如下:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId></dependency><dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId></dependency><dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope></dependency>1、BeanFactory与ApplicationContext
SpringApplication.run(A01.class, args);的返回值为ConfigurableApplicationContext对象,如下:
@SpringBootApplicationpublic class SpringOriginDemoApplication { public static void main(String[] args) { ConfigurableApplicationContext context = SpringApplication.run(SpringOriginDemoApplication.class, args); }}
BeanFactory是:
Ⅰ ApplicationContext 的父接口;
Ⅱ 是 Spring 的焦点容器, 重要的 ApplicationContext 实现都【组合】了它的功能。
2、BeanFactory接口
BeanFactory接口,最底子的待实现方法是getBean();方法。
别的,像控制反转、基本的依赖注入、直至 Bean 的生命周期的各种功能,都是依赖于BeanFactory接口实现的。
- ① DefaultListableBeanFactory类
是Spring项目中BeanFactory功能最美满的实现类,关系图如下:
- ② 通过反射获取singletonObjects成员变量案例
DefaultSingletonBeanRegistry类,如下:
通过反射获取beanFactory中的singletonObjects,如下:
// 通过反射获取 Field 对象singletonObjectsField singletonObjects = DefaultSingletonBeanRegistry.class.getDeclaredField("singletonObjects");// 暴力反射singletonObjects.setAccessible(true);// 获取beanFactory中的singletonObjects,并遍历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()));3、ApplicationContext接口
Ⅰ 在/resources目次下编写设置文件
语言代码表:Language Code Table (lingoes.cn),此处设置设置文件地域可以省略不写,一样平常写成zh、ja、en就可以(保举)。
Ⅱ 编写测试代码
System.out.println(context.getMessage("hi", null, Locale.ENGLISH));System.out.println(context.getMessage("hi", null, Locale.CHINA));System.out.println(context.getMessage("hi", null, Locale.JAPAN));
- ② 实现ResourcePatternResolver接口
Ⅰ 获取类路径下指定资源classpath:
Resource[] resources = context.getResources("classpath:application.properties");for (Resource resource : resources) { System.out.println(resource); // 输出 class path resource [application.properties]}Ⅱ 获取jar包其他资源classpath*:
Resource[] resources = context.getResources("classpath*:META-INF/spring.factories");
Ⅰ 获取变量键值
该方法可以获取设置文件(如:application.properties)内的键值,也可以拿到环境变量的键值,如下:
System.out.println(context.getEnvironment().getProperty("java_home")); // 输出 C:\Program Files\Java\jdk1.8.0_311System.out.println(context.getEnvironment().getProperty("server.port")); // 输出 8080
- ④ 实现ApplicationEventPublisher接口
Ⅰ 编写变乱类(实现ApplicationEvent )
public class UserRegisterEvent extends ApplicationEvent { public UserRegisterEvent(Object source) { super(source); }}Ⅱ 编写变乱发布类
@Componentpublic class Component1 { private static final Logger log = LoggerFactory.getLogger(Component1.class); @Autowired private ApplicationEventPublisher context; public void register() { log.debug("用户注册"); context.publishEvent(new UserRegisteredEvent(this)); }}Ⅲ 编写变乱监听类
@Componentpublic class Component2 { private static final Logger log = LoggerFactory.getLogger(Component2.class); @EventListener public void aaa(UserRegisteredEvent event) { log.debug("{}", event); log.debug("发送短信"); }}此处我们是debug输出的,在application.properties中自界说一下日记输出:logging.level.com.stone=debug。
Ⅳ 测试
context.getBean(Component1.class).register();实际利用场景中的作用:解耦合。
ApplicationContext接口拓展功能:
Ⅰ 国际化支持(MessageSource);
Ⅱ 通配符获取资源(ResourcePatternResolver);
Ⅲ 获取环境变量(EnvironmentCapable);
Ⅳ 发送变乱(ApplicationEventPublisher)。
二、容器实现
1、BeanFactory实现
- ① DefaultListableBeanFactory类
Ⅰ 准备测试类
public class TestBeanFactory { @Configuration static class Config{ @Bean public Bean1 bean1(){ return new Bean1(); } @Bean public Bean2 bean2(){ return new Bean2(); } } 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; } } static class Bean2{ private static final Logger log = LoggerFactory.getLogger(Bean1.class); public Bean2(){ log.debug("构造 Bean2()"); } }}Ⅱ 编写main方法
public static void main(String[] args) { DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); // Bean 的界说信息 class、scope、initMethod、destroyMethod 等 AbstractBeanDefinition bd = BeanDefinitionBuilder.genericBeanDefinition(Config.class).setScope("singleton").getBeanDefinition(); beanFactory.registerBeanDefinition("config", bd); for (String definitionName : beanFactory.getBeanDefinitionNames()) { System.out.println(definitionName); }}可以看到我们@Configuration注解的设置类并没有被扫描,以是@Bean相关的Bean没有输出,如下:
至此,我们可以看出底子的DefaultListableBeanFactory类并不直接支持此类注解扫描。
// 给 beanFactory 添加常用的后置处置处罚器AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);
可以看到,此时bean1和bean2仍旧没有被扫描放入容器。以为还没有调用beanFactory的后置处置处罚器。添加的后置处置处罚器:
a、ConfigurationAnnotationProcessor;(BeanFactory后置处置处罚器)
b、AutowiredAnnotationProcessor;
c、CommonAnnotationProcessor;
d、EventListenerProcessor;
e、EventListenerFactory。
获取beanFactory的后置处置处罚器,并调用,如下:
beanFactory.getBeansOfType(BeanFactoryPostProcessor.class).values() .forEach(beanFactoryPostProcessor -> { beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);});
至此,我们知道BeanFactoryPostProcessor是对BeanDifinition的一些增补。别的,我们实验获取一下bean1、bean2,如下:
System.out.println(beanFactory.getBean(Bean1.class).getBean2());Creating shared instance of singleton bean 'bean1'可以看到Bean对象在我们获取的时间才去创建,并且bean1对象内部并没有注入构造好的bean2。此时我们就须要用到Bean后置处置处罚器。
其作用是对bean生命周期的各个阶段提供拓展,比方:@Autowired...
beanFactory.getBeansOfType(BeanPostProcessor.class).values() .forEach(beanFactory::addBeanPostProcessor);
此时可以看到,装配bean1时须要bean2,容器就去沟通bean2完成注入。但是,实际利用Spring的时间,实在bean都是在我们利用前已经创建好的,我们还需处置处罚。
- ⑤ preInstantiateSingletons初始化
beanFactory.preInstantiateSingletons();System.out.println("==== before we get these beans ====");System.out.println(beanFactory.getBean(Bean1.class).getBean2());
Ⅰ 不会主动调用 BeanFactory 后处置处罚器;
Ⅱ 不会主动添加 Bean 后处置处罚器;
Ⅲ 不会主动初始化单例;
Ⅳ 不会分析beanFactory 还不会分析 ${ } 与 #{ }(如:@Value注解内利用)。
增补:AnnotationConfigUtils类
Ⅰ Config类添加:
@Beanpublic Bean3 bean3(){ return new Bean3();}@Beanpublic Bean4 bean4(){ return new Bean4();}Ⅱ 编写接口&内部类:
interface Inter{}static class Bean3 implements Inter{}static class Bean4 implements Inter{}Ⅲ Bean1内注入:
a、同一接口差别实现,@Autowired按照字段名注入,如下:
@Autowiredprivate Inter bean3;b、同一接口差别实现,@Resource(name = "bean4")指定注入,如下:
c、同时开启,按照@Autowired注入,如下:
d、通过比力器修改注入,如下:
Ⅰ 修改前
beanFactory.getBeansOfType(BeanPostProcessor.class).values() .forEach(beanPostProcessor -> { System.out.println("[!!!LOOK HERE!!!] Added BeanPostProcessor is ---> " + beanPostProcessor); beanFactory.addBeanPostProcessor(beanPostProcessor); });
Ⅱ 修改后
添加了.stream().sorted(beanFactory.getDependencyComparator());
beanFactory.getBeansOfType(BeanPostProcessor.class).values() .stream().sorted(beanFactory.getDependencyComparator()) .forEach(beanPostProcessor -> { System.out.println("[!!!LOOK HERE!!!] Added BeanPostProcessor is ---> " + beanPostProcessor); beanFactory.addBeanPostProcessor(beanPostProcessor); });2、ApplicationContext实现
- ① ClassPathXmlApplicationContext类
Ⅰ 编写内部类
public class Demo02 { static class Bean1{} static class Bean2{ private Bean1 bean1; public void setBean1(Bean1 bean1) { this.bean1 = bean1; } public Bean1 getBean1() { return bean1; } }}Ⅱ 编写b01.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"> <!--设置bean--> <bean name="bean1"
- ② FileSystemXmlApplicationContext类
public static void testFileSystemXmlApplicationContext(){ FileSystemXmlApplicationContext context // 绝对路径 D:\JavaStudy\Level1\spring_origin_demo\src\main\resources\b01.xml // 相对路径 src/main/resources/b01.xml = new FileSystemXmlApplicationContext("src/main/resources/b01.xml"); for (String definitionName : context.getBeanDefinitionNames()) { System.out.println(definitionName); } System.out.println(context.getBean(Bean2.class).getBean1());}增补:XmlBeanDefinitionReader类
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();System.out.println("[!!!LOOK HERE!!!] Before reader works :");for (String definitionName : beanFactory.getBeanDefinitionNames()) { System.out.println(definitionName);}XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);// reader.loadBeanDefinitions(new ClassPathResource("b01.xml"));reader.loadBeanDefinitions(new FileSystemResource("src/main/resources/b01.xml"));System.out.println("[!!!LOOK HERE!!!] After reader worked :");for (String definitionName : beanFactory.getBeanDefinitionNames()) { System.out.println(definitionName);}
- ③ AnnotationConfigApplicationContext类
Ⅰ 编写Config类
@Configurationstatic class Config{ @Bean public Bean1 bean1(){ return new Bean1(); } @Bean public Bean2 bean2(Bean1 bean1){ Bean2 bean2 = new Bean2(); bean2.setBean1(bean1); return bean2; }}Ⅱ 编写测试方法
public static void testAnnotationConfigApplicationContext(){ AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class); for (String definitionName : context.getBeanDefinitionNames()) { System.out.println(definitionName); } System.out.println(context.getBean(Bean2.class).getBean1());}增补:<context:annotation-config/>
可以看到AnnotationConfigApplicationContext类主动添加了后置处置处罚器,其作用类似于设置<context:annotation-config/>。
<!--添加注解驱动--><context:annotation-config/>
- ④ AnnotationConfigServletWebServerApplicationContext类
Ⅰ 编写WebConfig类
@Configurationstatic 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(){ // org.springframework.web.servlet.mvc.Controller return (request, response) -> { response.getWriter().println("Hello, context!"); return null; }; }}Ⅱ 编写测试方法
public static void testAnnotationConfigServletWebServerApplicationContext(){ AnnotationConfigServletWebServerApplicationContext context = new AnnotationConfigServletWebServerApplicationContext(WebConfig.class); for (String definitionName : context.getBeanDefinitionNames()) { System.out.println(definitionName); }}三、末了
以上即为Spring原理分析-容器&Bean(一)的全部内容,感谢阅读。 |