> 文章列表 > 深入学习Spring——笔记

深入学习Spring——笔记

深入学习Spring——笔记

实习之余多学点,希望一个月之内能够完成这个笔记

Spring笔记

  • 3-8
    • BeanFactory && ApplicationContext
      • BeanFactory
      • ApplicationContext
  • 3-9
    • BeanFactory && ApplicationContext
      • BeanFactory的实现

3-8

BeanFactory && ApplicationContext

BeanFactory

首先,从SpringBoot的主启动类来看

@SpringBootApplication
public class DemoApplication {public static void main(String[] args) {ConfigurableApplicationContext run = SpringApplication.run(DemoApplication.class, args);}
}

在IDEA中将光标放到ConfigurableApplication上,ctrl + alt + u。 可查看该类的相关类图如下:
深入学习Spring——笔记
可以看到ConfigurableApplication、ApplicationContext、BeanFactory。从图中可以看出ApplicationContext间接实现了BeanFactory而ConfigurableApplication实现ApplicationContext。也就是更核心的其实就是BeanFactory

使用Debug对ConfigableApplication的实例进行查看,可以看到示例中包含beanFactory对象
深入学习Spring——笔记
然而单纯的看BeanFactory,其名下并没有太多的方法
深入学习Spring——笔记

最主要的其实是BeanFactory的实现类DefaultListableBeanFactory。其继承、实现的接口、类的情况如下
深入学习Spring——笔记

虽然BeanFactory表面上看着比较简单,但是实际上控制反转、依赖注入、Bean的生命周期等功能,都是由他的实现类来提供的
以DefaultListableBeanFactory间接继承的父类DefauleSingletonBeanRegistry为例,获取对应的单例bean

 public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {ConfigurableApplicationContext run = SpringApplication.run(DemoApplication.class, args);System.out.println(run);//因为singletonObjects是私有的,所以通过反射,获取DefaultSingletonBeanRegistry类中的名为singletonObjects的属性。Field singletonObjects = DefaultSingletonBeanRegistry.class.getDeclaredField("singletonObjects");//设置私有属性在类外面允许被访问singletonObjects.setAccessible(true);//获取当前Springboot实例的Bean FactoryConfigurableListableBeanFactory beanFactory = run.getBeanFactory();//根据beanFactory对象获取其对应的单例Bean的Map 键表示Bean的名称,值表示Bean的实例Map<String,Object> map = (Map<String, Object>) singletonObjects.get(beanFactory);//输出key valuemap.forEach((k,v)->System.out.println(k + "=" + v));}

可以使用@commpent @service等注解来注入对应的类,这些注解都会被Spring Boot识别,前提是放到类上,不要放到接口上,接口也不能实例化

ApplicationContext

MessageSource: getMessage().主要是读取对应的properties文件,进行一个语言的转化
ResourcePatternResolver:getResources() 读取对应通配符路径下的文件,参数例classpath:application.properties,通配符如:classpath: \\ filed:
EnvironmentCapable:getEnvironment() 主要是获取环境中的键值相关的信息,如环境变量、yaml文件中的某个键的值,例run.getEnvironment().getProperty("server.port")
ApplicationEventPublisher:publishEvent()事件监听,主要可以用来解耦合,可以通过@EventListener注解来监听

3-9

BeanFactory && ApplicationContext

BeanFactory的实现

首先,如下测试代码

public class BeanFactoryTest {public static void main(String[] args) {//创建一个factory实例对象,当前的factory中并没有任何的BeanDefaultListableBeanFactory factory = new DefaultListableBeanFactory();//Bean的定义(class、scope、初始化、销毁等),定义一些Bean放入到factory中//BeanDefinitionBuilder是一个工具类,用于构架一个BeanDefinition对象AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(Config.class).getBeanDefinition();//将定义的Bean加入到factory中,需要为其命名factory.registerBeanDefinition("config",beanDefinition);//输出已经注入的BeanArrays.stream(factory.getBeanDefinitionNames()).forEach(System.out::println);}@Configurationstatic class Config{public Bean1 bean1(){return  new Bean1();}public Bean2 bean2(){return new Bean2();}}static class Bean1{private static final Logger log   = LoggerFactory.getLogger(Bean1.class);public Bean1(){log.debug("bean1");}@Autowiredprivate Bean2 bean2;public Bean2 getBean2() {return bean2;}}static class Bean2{private static final Logger log   = LoggerFactory.getLogger(Bean1.class);public Bean2(){log.debug("bean2");}}
}

执行该代码后发现,只有我们手动定义的Config被注入到beanfactory中。@Configuration注解、@Bean注解并没有起到作用。由此可以看出,注解标注的类等,并不是有beanfactory直接注入的,而是由别的类来完成

修改后:

    public static void main(String[] args) {//创建一个factory实例对象,当前的factory中并没有任何的BeanDefaultListableBeanFactory factory = new DefaultListableBeanFactory();//Bean的定义(class、scope、初始化、销毁等),定义一些Bean放入到factory中//BeanDefinitionBuilder是一个工具类,用于构架一个BeanDefinition对象AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(Config.class).getBeanDefinition();//将定义的Bean加入到factory中,需要为其命名factory.registerBeanDefinition("config",beanDefinition);//注册注解处理器,注册Spring上下问的注解,向beanFactory中注册所需的注解处理器AnnotationConfigUtils.registerAnnotationConfigProcessors(factory);/* BeanFactoryPostProcessor 是一种特殊的 Bean,* 用于在 Spring 容器实例化所有其他 Bean 之前,对 BeanFactory 进行修改。* 这些修改可能包括添加、修改或删除 Bean 的属性,修改 Bean 的定义等*///获取BeanFactoryPostProcessor相关的已经注入的Bean,@Configuration、@Autowired、@PostConstruct、@PreDestroy等注解都属于该类型factory.getBeansOfType(BeanFactoryPostProcessor.class).values().stream().forEach(item->{item.postProcessBeanFactory(factory);});Arrays.stream(factory.getBeanDefinitionNames()).forEach(System.out::println);}

但是在该代码的基础上,调用factory.getBean(Bean1.class).getBean2()方法,得到的结果是null,因为getBean2返回的是一个Bean2对象,而在Bean1的class中,Bean2对象使用的是@Autowired注解进行注入,也就表示,该注入并未成功。也就表示BeanFactoryPostProcessor.class没有对@Autowired进行处理。
修改后如下:


//bean后置处理器,针对的是Bean的生命周期的各个阶段提供扩展。如@Autowired、@Resource等factory.getBeansOfType(BeanPostProcessor.class).values().forEach(factory::addBeanPostProcessor);System.out.println(factory.getBean(Bean1.class).getBean2());Arrays.stream(factory.getBeanDefinitionNames()).forEach(System.out::println);

BeanFactoryPostProcessor 针对的是Bean工厂,先将其加入Bean工厂,BeanPostProcessor针对的是Bean ,再与Bean建立联系