写点什么

Spring 的 IOC 常用注解 (含源码)

用户头像
Java王路飞
关注
发布于: 2021 年 03 月 09 日
Spring的IOC常用注解(含源码)

一、容器中注入组件


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_BeanLifeCycle、Car


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

  • 定义销毁方法,定义 @Bean 的 destroyMethod 为该方法


b)实现 InitializingBean 和 DisposableBean 接口


  源码:Demo04_BeanLifeCycle、Dog


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

  • 定义当前对象实现 DisposableBean 接口。其中 destroy 方法会在当前对象销毁的时候调用。


c)可以使用 JSR250


  源码:Demo04_BeanLifeCycle、Color


  • @PostConstruct 定义在方法上,则该方法会在 Bean 创建并且属性赋值之后执行,为初始化方法

  • @PreDestroy 定义在方法上,则该方法在容器销毁 bean 之前通知我们进行清理工作


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


  源码:Demo04_BeanLifeCycle、Demo04_BeanPostProccessor


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


  • postProcessBeforeInitialization:在初始化之前工作

  • postProcessAfterInitialization:在初始化之后工作


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


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


//给bean进行属性赋值populateBean(beanName, mbd, instanceWrapper);//初始化beanexposedObject = initializeBean(beanName, exposedObject, mbd);
复制代码


  在方法 initializeBean 中可以看到


//调用applyBeanPostProcessorsBeforeInitialization进行初始化之前的处理if (mbd == null || !mbd.isSynthetic()) {    wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);}//调用自定义初始化方法try {    invokeInitMethods(beanName, wrappedBean, mbd);}catch ...//调用applyBeanPostProcessorsAfterInitialization进行初始化之后的处理if (mbd == null || !mbd.isSynthetic()) {    wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);}
复制代码


总结:


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


4,BeanPostProcessor 在 Spring 中的应用


a)ApplicationContextAware 各种 Aware 接口


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


//如果当前bean为各种指定的Aware的bean就会执行invokeAwareInterfaces方法this.invokeAwareInterfaces(bean);
private void invokeAwareInterfaces(Object bean) { if (bean instanceof Aware) { ... //如果当前bean为ApplicationContextAware的子类,则会调用其setApplicationContext将applicationContext进行赋值 if (bean instanceof ApplicationContextAware) { ((ApplicationContextAware)bean).setApplicationContext(this.applicationContext); } }}
复制代码


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


b)BeanValidationPostProcessor


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


c)@PostConstruct 和 @PreDestroy 方法


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


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


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()


发布于: 2021 年 03 月 09 日阅读数: 18
用户头像

Java王路飞

关注

需要资料添加小助理vx:17375779923 即可 2021.01.29 加入

Java领域;架构知识;面试心得;互联网行业最新资讯

评论

发布
暂无评论
Spring的IOC常用注解(含源码)