SpringBoot | 1.2 全注解下的Spring IoC
前言
在学习SpringBoot之前,有几个Spring的重要的基础概念需要提一下,SpringBoot对这些基础概念做进一步的封装,完成自动配置。首先就是Spring的控制反转IOC,由于SpringBoot不建议使用XML,因此本小节旨在关注全注解下的Spring IoC。
其中比较重要的是第二点与第三点:第二点里的注解要么常用于业务开发,要么在源码里常见;第四点的@Autowired需要关注。
注:在说明注解时,第一点加粗为注解中文含义,第二点为一般加在哪身上,缩进或代码块为示例,如:
@注解
- 中文含义
 - 加在哪
 - 其他……
语句示例
//代码示例
 
1. Ioc容器概念
Spring的IoC容器其实就是一个Bean管理的容器。
所有的IoC容器都要实现顶层接口BeanFactory(Bean工厂),该工厂定义了一些操作Bean实例的基本方法,源码如下:
public interface BeanFactory {
   //前缀
   String FACTORY_BEAN_PREFIX = "&";
   //根据类型、名称等获取Bean
   Object getBean(String var1) throws BeansException;
   <T> T getBean(String var1, Class<T> var2) throws BeansException;
   Object getBean(String var1, Object... var2) throws BeansException;
   <T> T getBean(Class<T> var1) throws BeansException;
   <T> T getBean(Class<T> var1, Object... var2) throws BeansException;
   <T> ObjectProvider<T> getBeanProvider(Class<T> var1);
   <T> ObjectProvider<T> getBeanProvider(ResolvableType var1);
   //是否包含Bean
   boolean containsBean(String var1);
   //Bean是否单例
   boolean isSingleton(String var1) throws NoSuchBeanDefinitionException;
   //Bean是否原型
   boolean isPrototype(String var1) throws NoSuchBeanDefinitionException;
   //是否类型匹配
   boolean isTypeMatch(String var1, ResolvableType var2) throws NoSuchBeanDefinitionException;
   boolean isTypeMatch(String var1, Class<?> var2) throws NoSuchBeanDefinitionException;
   //获取Bean类型
   @Nullable
   Class<?> getType(String var1) throws NoSuchBeanDefinitionException;
   //获取Bean别名
   @Nullable
   Class<?> getType(String var1, boolean var2) throws NoSuchBeanDefinitionException;
   String[] getAliases(String var1);
}
从上述源码可知,顶层接口定义了一些基本方法,其中需要注意的点有:
isSingleton方法判断Bean是否在Spring IoC中为单例。默认情况下Bean都是以单例存在,即:调用getBean方法返回同一个对象;(详情见第五点Bean的作用域)isPrototype方法判断原型,若返回true,则调用getBean方法时IoC会创建一个新的Bean返回,与Bean的作用域相关;(详情见第五点Bean的作用域)
在BeanFactory基础上,有一些高级接口,可以用个实现接口完成定制化操作。
Spring IoC接口设计如下:

需要关注ApplicationContext接口,其的实现类有:
FileSystemXmlApplicationContext: 表示从文件绝对路径加载配置文件;ClassPathXmlApplicationContext:表示 从classpath下加载配置文件(适合于相对路径方式加载) 。
//Spring里常用获取Bean的方法
@Test
public void testBean() {
   ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
   Orders orders = context.getBean("orders", Orders.class);
}
2. 往IoC容器添加组件
通常意义上讲的Spring IoC控制反转就是往容器中添加组件过程,针对添加的组件类型不同,有相应不同的注解实现。该点下很多注解在源码里常见。
| 注解 | 功能介绍 | 
|---|---|
| @Repository | 数据库层组件,常用于DAO层; | 
| @Service | 业务逻辑组件,常用于业务逻辑层; | 
| @Controller | 控制器,常用于页面展示层;控制器默认方法返回的是页面跳转; | 
| @RestController | REST风格控制器, 常用于响应字符串,是@ResponseBody和@Controller的组合注解;默认方法返回的是json数据; | 
| @Component | 注册组件,常用于POJO层。可以配置Bean的名称,如@Component("XXX");不配置时Ioc容器将类名第一个字母小写,其他不变放入容器中; | 
| @Bean | 给容器注册组件。常用于第三方包,源码里常见。 | 
@ComponentScan:
- 开启注解扫描
 - 常用于配置类;
 - 用于开启注解扫描,只会扫描当前包和其子包下的注解,可以自定义包扫描路径;
 - 可以通过excludeFilters配置指定哪些类型或类不被扫描进IoC容器;
- 自定义路径:
@ComponentScan(basePackages = {"com.dlhjw"}) - 排除扫描:
@ComponentScan(basePackages = "com.dlhjw.*", excludeFilters = {@Filter{classes = {Service.class}}}) 
 - 自定义路径:
 
@Import
- 导入组件
 - 常用于配置类;
 - 用来导入配置类或者一些需要前置加载的类,导入指定类型组件;
 - 源码里常见。
@Import({User.class, DBHelper.class}):给容器中自动创建出这两个类型的组件、默认组件的名字就是全类名@Import高级用法:https://www.bilibili.com/video/BV1gW411W7wy?p=8
 
@Conditional
- 条件装配
 - 常用于配置类;
 - 对满足Conditional指定的条件,则进行组件注入;
 - 源码里常见。
 

3. Full模式(单实例)与Lite模式(原型)
Full模式与Lite模式针对spring配置而言的,和xml配置无关。单实例可以理解成每次从IoC容器中取出同一个对象,原型则对应每次取出时都会new一个新对象。
Full模式(默认,单实例):
- 标注有
@Configuration或者@Configuration(proxyBeanMethods = true)的类被称为Full模式的配置类;proxyBeanMethods:代理bean的方法;
 - 单实例是IoC容器启动时就会去实例化bean并添加到容器当中去,每次获取都是从容器中获取同一个对象;
 - 单例模式能有效避免Lite模式下的错误。性能没有Lite模式好;
 
Lite模式(多实例):
- 类上有
@Component注解; - 类上有
@ComponentScan注解; - 类上有
@Import注解; - 类上有
@ImportResource注解; - 类上没有任何注解,但是类中存在
@Bean方法; - 类上有
@Configuration(proxyBeanMethods = false)注解; - 多实例是去获取对象的时候才回去实例化bean,每次获取都会去实例化bean;
 - 运行时不用生成CGLIB子类,提高运行性能,降低启动时间,可以作为普通类使用。但是不能声明@Bean之间的依赖。
 
4. 依赖注入DI
依赖注入讨论的是Bean之间的依赖关系,例如一个类里包含另一个类。上面第二点讨论的是添加组件,如果把它理解成创建对象的话,那么依赖注入就是获取这个对象并使用。依赖注入的前提是往容器添加组件,也就是说只有容器中有这个组件,才能取出来使用。
@Autowired
- 自动注入
 - 常用在属性、set方法与方法的参数上;
 - 最常用的注解之一,根据属性类型(by type)找到对应的Bean,如果对应的Bean不是唯一的,则会根据其属性名称和Bean的名称匹配;
 - 其默认必须找到对应的Bean;如果不能确定其标注属性是否存在,并且允许这个被标注的属性为null,可以配置@Autowired属性required为false,如:
@Autowired(required = false)
 
@Primary
- 优先注入
 - 常用于类或组件上;
 - 当获取的Bean不是唯一时,优先注入被@Primary标注的类或组件;
 
@Quelifier
- 限定注入
 - 与@Autowired一同使用;
 - 配置需要注入的名称即可;
@Autowired //根据类型Animal
@Quelifier("dog") //根据名称dog
private Animal animal;
 
5. Bean的生命周期
大致分为Bean的定义、Bean的初始化、Bean的生存期和Bean的销毁是个过程。
Bean的生命周期

- 在@ComponentScan注解里对配置项lazyInit配置true可以对Bean的初始化延迟,即Spring不会在发布Bean定义后马上进行实例化与依赖注入;
@ComponentScan(lazyInit = true)
 - 可以通过实现上图的接口,进行自定义Bean的生命周期各项属性;
 - 注解
@PostConstruct定义了初始化方法,注解@PreDestroy定义了销毁方法; 
6. Bean的属性配置
这里指如何给Bean的属性赋值
@Value
- 属性值
 - 常用于属性与方法上;
 - 可以使用Spring EL表达式对需要配置的属性进行运算;
${......}:表示占位符,读取上下文(application配置文件)的属性值进行装配;#{......}:表示启用Spring表达式,具有运算功能;T(......):表示引入类;
 - 表示给Bean赋值,可以用${xxx}占位符读取application配置文件的内容;
//获取application里的database.driverName值装配进方法里
@Value("${database.driverName}")
private String driverName; //赋值字符串,同理可以赋值整形、浮点数等
@Value("#{'赋值字符串'}")
private String str; //str后跟着?,表示判断str是否为空,不为空才执行toUpperCase方法
@Value("#{beanName.str?.toUpperCase()}")
private String otherBeanProp; //字符串比较
@Value("#{beanName.str eq 'SpringBoot'}")
private boolean strFlag; //调用方法,System是Java默认加载的包,不用写全类名;其他包要
@Value("#{T(System).currentTimeMillis()}")
private Long initTime;
 
@ConfigurationProperties
- 配置属性
 - 常标注在类上;
 - 解决@Value过多问题;
@ConfigurationProperties(“database”)
public class DataBaseProperties{
}
 
@PropertySource
- 配置来源
 - 添加在主程序类上;
 - 当配置文件不在properties时,例jdbc.properties,需要在主程序类上标注该注解;
 - value可配置多个文件,使用classpath前缀说明在类路径下找;
 - ignoreResourceNotFound默认值false,表示没要找到配置文件就报错。
@PropertySource(value={"classpath:jdbc.properties"}, ignoreResourceNotFound=true)
 
7. Bean的作用域
在Bean的作用域里,常用的是以下加粗的四种。前面IoC容器里讨论的isSingleton与isPrototype方法本质上是作用域的问题。

- 对于
application域而言,完全可以使用单例替代; 
@Scope
- 作用域
 - 常加在类上;
 - 用于修改作用域;
 ConfigurableBeanFactory仅提供SCOPE_PROTOTYPE (原型)和SCOPE_SINGLETON(单例)两种;- 在SpringMVC环境中,
WebApplicationContext提供SCOPE_REQUEST(请求)、SCOPE_SESSION(会话)、SCOPE_APPLICATION(应用)三种。@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class ScopeBean{
}
//在同一个请求范围内去获取Bean时,只会共用一个Bean,第二次请求会产生新的Bean
@Scope(WebApplicationContext.SCOPE_REQUEST)
public class ScopeBean{
}
 
8. 环境切换
在实际开发中,项目往往需要在开发环境、测试环境、准生产环境和生产环境中切换,Spring提供了Profile机制,方便在各个环境间切换。
@Profile
- 配置切换
 - 常用于不同环境下需要不用配置的方法或类上;
 - 可以在application中配置两个参数修改Profile机制,
spring.profiles.active与spring.profiles.default,当这两个属性都没配置情况下,Spring不会启动Profile机制。其中,前者优先级高。spring.profiles.active=dev
@Profile("dev")
public DataSource getDataSource( ) {
} @Profile("dev")
public DataSource getDataSource( ) {
}
 
9. 引入XML文件
虽然SpringBoot不建议使用XML来进行属性配置,但在某些情况下我们又不得不使用XML来进行配置,如:Dubbo框架基于Spring的XML方式进行开发。需要将其引入才能作用。
@ImportResources
- 导入资源
 - 常用于需要XML装配是配置类上;
@ImportResources(value = {" classpath:spring-other.xml"})
public class AppConfig{
}
 
最后
新人制作,如有错误,欢迎指出,感激不尽!
欢迎关注公众号,会分享一些更日常的东西!
如需转载,请标注出处!

SpringBoot | 1.2 全注解下的Spring IoC的更多相关文章
- 【Spring】非Spring IOC容器下获取Spring IOC上下文的环境
		
前言 在Spring Web项目中,有些特殊的时候需要在非Spring IOC容器下获取Spring IOC容器的上下文环境,比如获取某个bean. 版本说明 声明POM文件,指定需引入的JAR. & ...
 - 纯注解快速使用spring IOC容器
		
使用spring的ioc容器实现对bean的管理与基本的依赖注入是再经典的应用了.基础使用不在详述. 这里主要介绍下使用注解实现零配置的spring容器.我相信你也会更喜欢使用这种方式.Spring ...
 - 手写@Service、@Autowired、@Transactional注解,实现spring ioc和spring事务
		
自定义@Service注解 @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface Custom ...
 - java spring mvc 全注解
		
本人苦逼学生一枚,马上就要毕业,面临找工作,实在是不想离开学校.在老师的教导下学习了spring mvc ,配置文件实在繁琐,因此网上百度学习了spring mvc 全注解方式完成spring的装配工 ...
 - Spring IOC 常用注解与使用
		
@Component 注解@component代表spring ioc 会把这个类扫描生成Bean实例 @Component public class Role{ @Value("1&quo ...
 - Spring学习进阶(二)Spring IoC
		
在使用Spring所提供的各种丰富而神奇的功能之前,必须在Spring IoC容器中装配好Bean,并建立Bean与Bean之间的关联关系.控制反转(Inverser of Control ioc)是 ...
 - Spring IoC容器与应用上下文的设计与实现
		
一.前言 写这篇博文的主要目的如下: 通过相关类和接口分析IoC容器到底长什么样. 阐述笔者对Spring上下文和容器的理解. 介绍重要的类辅助理解SpringBoot的启动流程. 二.Spring ...
 - 案例学编程系列:案例认识 Spring IOC
		
本文spring libs 地址:https://github.com/yizhiamumu/springlibs Spring 能帮我们做什么 ①.Spring 能帮我们根据配置文件创建及组装对象之 ...
 - 框架源码系列六:Spring源码学习之Spring IOC源码学习
		
Spring 源码学习过程: 一.搞明白IOC能做什么,是怎么做的 1. 搞明白IOC能做什么? IOC是用为用户创建.管理实例对象的.用户需要实例对象时只需要向IOC容器获取就行了,不用自己去创建 ...
 
随机推荐
- 如果你想设置无人自动升级,我们推荐你将这个值修改为security,它会告诉 yum 仅仅升级修复安全问题的软件包。
			
定期升级你的 CentOS 系统,是所有系统安全中最重要的措施之一.如果你不使用最新的安全补丁升级你的操作系统软件包,你将会让你的机器很容易被攻击. 如果你管理者多个 CentOS 机器,手动升级系统 ...
 - Linux 使用命令发送邮件
			
1.关闭本机的sendmail服务或者postfix服务 #执行下面的命令,关闭sendmail和postfix服务 #sendmial [root@db-backup ~]# service sen ...
 - 校准仪的开发 ---等下整理  迪文屏的ICO文件  和输出配置问题
			
要有ICO文件才能
 - Java - Java 8 新特性
			
一.Java8新特性 Java8概述:Java8,也就是jdk1.8版本,是意义深远的一个新版本.是Java5之后一个大的版本升级,让Java语言和库仿佛获得了新生. 二.Lambda表达式 Lamb ...
 - 在 Kubernetes 集群在线部署 KubeSphere
			
https://github.com/kubesphere/ks-installer/blob/master/README_zh.md https://kubesphere.com.cn/docs/i ...
 - Hadoop系列番外篇之一文搞懂Hadoop RPC框架及细节实现
			
@ 目录 Hadoop RPC 框架解析 1.Hadoop RPC框架概述 1.1 RPC框架特点 1.2 Hadoop RPC框架 2.Java基础知识回顾 2.1 Java反射机制与动态代理 2. ...
 - GO学习-(28) Go语言操作influxDB
			
Go语言操作influxDB 本文介绍了influxDB时序数据库及Go语言操作influxDB. InfluxDB是一个开源分布式时序.事件和指标数据库.使用Go语言编写,无需外部依赖.其设计目标是 ...
 - GO学习-(9) Go语言基础之切片
			
Go语言基础之切片 本文主要介绍Go语言中切片(slice)及它的基本使用. 引子 因为数组的长度是固定的并且数组长度属于类型的一部分,所以数组有很多的局限性. 例如: func arraySum(x ...
 - THINKPHP_(5)_THINKPHP6接收ajax下拉菜单提交的数据,存在的bug
			
反思: 国产总是不尽人意,但是要支持国产. ThinkPHP的6接收ajax的post数据,存在一个bug.即ajax传递的json数据,在thinkphp后端解析出来后,并非直接的json格式. 描 ...
 - Redux/Mobx/Akita/Vuex对比 - 选择更适合低代码场景的状态管理方案
			
近期准备开发一个数据分析 SDK,定位是作为数据中台向外输出数据分析能力的载体,前端的功能表现类似低代码平台的各种拖拉拽.作为中台能力的载体,SDK 未来很大概率会需要支持多种视图层框架,比如Vue2 ...