一、容器中注入组件

1,包扫描 + 组件标注注解

  源码:Demo01_ComponentScan

a)组件标注

  • @Controller
  • @Service
  • @Repository
  • @Component

b)包扫描@ComponentScan

  @ComponentScan中主要值的解释

  • value:扫描的包路径(数组)
  • excludeFilters:指定扫描的时候按照什么规则排除那些组件(@ComponentScan.Filter)includeFilters:指定扫描的时候只需要包含哪些组件。使用同excludeFilter。
    • FilterType.ANNOTATION:按照注解
    • FilterType.ASSIGNABLE_TYPE:按照给定的类型
    • FilterType.ASPECTJ:使用ASPECTJ表达式
    • FilterType.REGEX:使用正则指定
    • FilterType.CUSTOM:使用自定义规则
  • useDefaultFilters:是否使用默认的扫描机制。默认按照a)中组件标注扫描

2,使用@Bean导入

a)@Scope作用域

  • prototype:多实例的:ioc容器启动并不会去调用方法创建对象放在容器中。每次获取的时候才会调用方法创建对象;
  • singleton:单实例的(默认值):ioc容器启动会调用方法创建对象放到ioc容器中。以后每次获取就是直接从容器(map.get())中拿,
  • request:同一次请求创建一个实例
  • session:同一个session创建一个实例

b)@Lazy

  单实例bean:默认在容器启动的时候创建对象;

  懒加载:容器启动不创建对象。第一次使用(获取)Bean创建对象,并初始化。

c)@Conditional

  @Bean上加改注解,按照一定的条件进行判断,满足条件给容器中注册bean;如在类上加改注解,这个类中配置的所有bean注册才能生效。

  • @ConditionalOnClass 表示如果有后面的类,那么就加载这个自动配置;
  • @ConditionalOnMissingClass 如果没有后面的类,才自动配置。如果没有就配置,保证bean的唯一。

  大量运用于SpringBoot中。

3,使用@Import导入

  源码:Demo02_Import

  快速为容器中导入一个组件。

  • @Import(要导入到容器中的组件);容器中就会自动注册这个组件,id默认是全类名
  • ImportSelector:返回需要导入的组件的全类名数组
  • ImportBeanDefinitionRegistrar:手动注册bean到容器中

4,FactoryBean(工厂Bean)

  源码:Demo03_FactoryBean

  将实现FactoryBean的类加到容器中。

  • 默认从容器中获取到的是工厂bean调用getObject创建的对象。
  • 要获取工厂Bean本身,我们需要给id前面加一个&

二、Bean的生命周期

1,bean生命周期

  bean创建 --- 初始化 --- 销毁

  • 构造(对象创建)

    • 单实例:在容器启动的时候创建对象
    • 多实例:在每次获取的时候创建对象
  • 初始化:
    • 成员变量赋值,各种增强等,对象创建完成,并赋值好,调用初始化方法
  • 销毁:
    • 单实例:容器关闭的时候
    • 多实例:容器不会管理这个bean;容器不会调用销毁方法;

2,定义Bean初始化和销毁

a)定义initMethod和destroyMethod

  源码:Demo04_BeanLifeCycleCar

  • 定义初始化方法,定义@Bean的initMethod为该方法
  • 定义销毁方法,定义@Bean的destroyMethod为该方法

b)实现InitializingBean和DisposableBean接口

  源码:Demo04_BeanLifeCycleDog

  • 定义当前对象实现InitializingBean接口。其中afterPropertiesSet方法会在当前对象设置完属性之后调用。
  • 定义当前对象实现DisposableBean接口。其中destroy方法会在当前对象销毁的时候调用。

c)可以使用JSR250

  源码:Demo04_BeanLifeCycleColor

  • @PostConstruct定义在方法上,则该方法会在Bean创建并且属性赋值之后执行,为初始化方法
  • @PreDestroy定义在方法上,则该方法在容器销毁bean之前通知我们进行清理工作

d)实现BeanPostProcessor,bean的后置处理

  源码:Demo04_BeanLifeCycleDemo04_BeanPostProccessor

  在bean初始化前后进行一些处理工作;

  • postProcessBeforeInitialization:在初始化之前工作
  • postProcessAfterInitialization:在初始化之后工作

3,从源码看BeanPostProcessor后置处理器

  在Spring类AbstractAutowireCapableBeanFactory中方法doCreateBean可以看到

  1. //给bean进行属性赋值
  2. populateBean(beanName, mbd, instanceWrapper);
  3. //初始化bean
  4. exposedObject = initializeBean(beanName, exposedObject, mbd);

  在方法initializeBean中可以看到

  1. //调用applyBeanPostProcessorsBeforeInitialization进行初始化之前的处理
  2. if (mbd == null || !mbd.isSynthetic()) {
  3. wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
  4. }
  5. //调用自定义初始化方法
  6. try {
  7. invokeInitMethods(beanName, wrappedBean, mbd);
  8. }catch ...//调用applyBeanPostProcessorsAfterInitialization进行初始化之后的处理
  9. if (mbd == null || !mbd.isSynthetic()) {
  10. wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
  11. }

总结:

  BeanPostProcessor会在Bean对象创建并属性赋值完成之后,在执行init初始化方法的前后进行增加。

4,BeanPostProcessor在Spring中的应用

a)ApplicationContextAware各种Aware接口

  查看源码类ApplicationContextAwareProcessor实现了BeanPostProcessor接口,其中postProcessBeforeInitialization的实现为:

  1. //如果当前bean为各种指定的Aware的bean就会执行invokeAwareInterfaces方法
  2. this.invokeAwareInterfaces(bean);
  3.  
  4. private void invokeAwareInterfaces(Object bean) {
  5. if (bean instanceof Aware) {
  6. ...
  7. //如果当前bean为ApplicationContextAware的子类,则会调用其setApplicationContext将applicationContext进行赋值
  8. if (bean instanceof ApplicationContextAware) {
  9. ((ApplicationContextAware)bean).setApplicationContext(this.applicationContext);
  10. }
  11. }
  12. }

  所以在ApplicationContextAware时,可以通过setApplicationContext获取到ApplicationContext上下文对象

b)BeanValidationPostProcessor

  查看BeanValidationPostProcessor实现了BeanPostProcessor接口,其中不管是postProcessBeforeInitialization还是postProcessAfterInitialization,均调用了doValidate方法来验证当前bean是否合理

c)@PostConstruct和@PreDestroy方法

  查看InitDestroyAnnotationBeanPostProcessor实现了BeanPostProcessor接口,其中postProcessBeforeInitialization在当前bean初始化之前的源码为:

  1. //获取生命周期的metadata,得到标注有@PostConstruct和@PreDestroy的方法
  2. LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass());
  3. try {
  4. //这个方法会采用反射的方式,调用方法
  5. metadata.invokeInitMethods(bean, beanName);
  6. }...

d)AutowiredAnnotationBeanPostProcessor

  用来处理@Autowire注解的属性

三、属性赋值

  • @Value:给属性赋值,也可以使用SpEL和外部文件的值
  • @PropertySource:读取外部配置文件中的k/v保存到运行环境中。@PropertySource(value={"classpath:/application.yaml"})
  • @Autowried 装配优先级如下:构造器、参数、方法、属性。
    • 使用按照类型去容器中找对应的组件
    • 如果找到多个相同类型的组件,再将属性的名称作为组件的id去容器中查找
  • @Qualifier:使用@Qualifier指定需要装配的组件的id,结合@Autowried使用
  • @Primary:spring自动装配的时候,默认首先bean,配合@Bean使用
  • @Resource(JSR250):jsr规范:按照组件名称进行装配,不支持@Primary和@Autowired(reqiured=false)
  • @Inject(JSR330):jsr规范和@Autowired功能一致,不支持require=false;
  • @Profile:结合@Bean使用,默认为default环境,可以通过命令行参数来切换环境
    • 加上VM参数:-Dspring.profiles.active=dev 则采用的dev环境。多个用逗号隔开
    • 1.无参构造ApplicationContext,2.通过applicationContext.getEnvironment().setActiveProfiles("dev"),3.注册配置类applicationContext.register(Main.class),4.采用ApplicationContext.refresh()

Spring的IOC常用注解(含源码)的更多相关文章

  1. Spring提取@Transactional事务注解的源码解析

    声明:本文是自己在学习spring注解事务处理源代码时所留下的笔记: 难免有错误,敬请读者谅解!!! 1.事务注解标签 <tx:annotation-driven /> 2.tx 命名空间 ...

  2. Spring第四天,BeanPostProcessor源码分析,彻底搞懂IOC注入及注解优先级问题!

  3. Spring3 + Spring MVC+ Mybatis 3+Mysql 项目整合(注解及源码)

    Spring3 + Spring MVC+ Mybatis 3+Mysql 项目整合(注解及源码) 备注: 之前在Spring3 + Spring MVC+ Mybatis 3+Mysql 项目整合中 ...

  4. Spring 3.1新特性之二:@Enable*注解的源码,spring源码分析之定时任务Scheduled注解

    分析SpringBoot的自动化配置原理的时候,可以观察下这些@Enable*注解的源码,可以发现所有的注解都有一个@Import注解.@Import注解是用来导入配置类的,这也就是说这些自动开启的实 ...

  5. c++实现游戏开发中常用的对象池(含源码)

    c++实现游戏开发中常用的对象池(含源码) little_stupid_child2017-01-06上传   对象池的五要素: 1.对象集合 2.未使用对象索引集合 3.已使用对象索引集合 4.当前 ...

  6. 谈谈Spring的IoC之注解扫描

    问题   IoC是Inversion of Control的缩写,翻译过来即"控制反转".IoC可以说是Spring的灵魂,想要读懂Spring,必先读懂IoC.不过有时候硬着头皮 ...

  7. spring security 授权方式(自定义)及源码跟踪

    spring security 授权方式(自定义)及源码跟踪 ​ 这节我们来看看spring security的几种授权方式,及简要的源码跟踪.在初步接触spring security时,为了实现它的 ...

  8. spring MVC cors跨域实现源码解析

    # spring MVC cors跨域实现源码解析 > 名词解释:跨域资源共享(Cross-Origin Resource Sharing) 简单说就是只要协议.IP.http方法任意一个不同就 ...

  9. Spring Boot REST(二)源码分析

    Spring Boot REST(二)源码分析 Spring 系列目录(https://www.cnblogs.com/binarylei/p/10117436.html) SpringBoot RE ...

随机推荐

  1. 恢复win10 LTSC 2019 图片查看器功能

    1.开始–运行–输入"regedit"打开注册表. 2. 在打开的注册表编辑器中,从左侧依次展开:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Win ...

  2. Navicat 快捷键 for Mysql

     常用快捷键: 1. ctrl + q: 打开新查询窗口 2. ctrl + r: 运行当前窗口内的所有语句 3. ctrl + w: 关闭当前窗口 4. F6: 打开一个MySQL命令行窗口 5. ...

  3. Docker架构分解

    Docker总架构分解Docker对使用者来讲是一个C/S模式的架构,而Docker的后端是一个非常松耦合的架构,模块各司其职,并有机组合,支撑Docker的运行. 用户是使用Docker Clien ...

  4. Python_小程序

    一.开发前的准备工作 1.申请AppID:一个账号对应一个小程序,个人/个体只能申请5个小程序 2.下载开发工具 二.小程序的文件结构 三. 1.数据绑定 1.1数据的设置 Page( data:{ ...

  5. docker-理论题01

    1.什么是docker?答:docker是开源的应用容器引擎:开发人员把他们的应用及依赖包打包发布到容器当中. 2.docker和VMware的区别? 答:docker是半解耦,VMware是解耦:d ...

  6. hdu-1159 1087 1257(dp)

    本文就最长公共子序列,最长连续递增子序列的长度,最大连续递增子序列的值进行对比. hdu-1159: Common Subsequence Time Limit: 2000/1000 MS (Java ...

  7. hdoj 5971

    Wrestling Match Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)T ...

  8. nyoj-2357

    2357: 插塔憋憋乐 时间限制: 1 秒  内存限制: 128 MB提交: 107  解决: 28提交 状态 题目描述 众所不知,LLM是一位红警3大佬,打的非常厉害,但是曾经也是一位萌新,喜欢在家 ...

  9. HDU 6155 Subsequence Count(矩阵 + DP + 线段树)题解

    题意:01串,操作1:把l r区间的0变1,1变0:操作2:求出l r区间的子序列种数 思路:设DP[i][j]为到i为止以j结尾的种数,假设j为0,那么dp[i][0] = dp[i - 1][1] ...

  10. 产品经理进阶:如何用UML的顺序图表达思想?

    当大家把UML建模语言下的各图形都有所了解后会发现,通过这些图可以全面的.立体的从各个角度表达产品,让产品的表达变得更丰富.更形象. "手中无剑.心中有剑",大多数产品人并不了解计 ...