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接口设计如下:

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

  • 导入组件
  • 常用于配置类;
  • 用来导入配置类或者一些需要前置加载的类,导入指定类型组件;
  • 源码里常见。

@Conditional

  • 条件装配
  • 常用于配置类;
  • 对满足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的生命周期

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方法本质上是作用域的问题。

Bean的作用域
  • 对于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.activespring.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{
    }
    


最后

\color{blue}{\rm\small{新人制作,如有错误,欢迎指出,感激不尽!}}

\color{blue}{\rm\small{欢迎关注我,并与我交流!}}

\color{blue}{\rm\small{如需转载,请标注出处!}}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,033评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,725评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,473评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,846评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,848评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,691评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,053评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,700评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,856评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,676评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,787评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,430评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,034评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,990评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,218评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,174评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,526评论 2 343

推荐阅读更多精彩内容