Spring主要装配机制

1、在XML中进行显式配置

2、在Java中进行显式配置

3、隐式的的bean发现机制和自动装配

自动化装配bean

Spring从两个角度来实现自动化装配

1、组件扫描:Spring会自动发现应用上下文中所创建的Bean

2、自动装配:Spring自动满足bean之间的依赖。

组件扫描

相关注解

@Component

表明该类会作为组件类,告知Spring要为这个类创建bean

@Component("lonelyHeartsClub")

Spring应用上下文中的所有的bean都会给定一个ID,默认情况下为将类名的第一个字母变成小写,该注解给bean设置ID

@ComponentScan

启用组件扫描,默认扫描与配置类相同的包

用于JavaConfig配置类中,当然也可以使用xml配置的方式启用组件扫描,但是在此不做记录

@ComponentScan("soundsystem")

参数可指定要扫描的包名

@ComponentScan(basePackages={"soundsystem","video"})

参数可指定多个要扫描的包名组成的数组

@ComponentScan(basePackagesClasses={CDPlayer.class,DVDPlayer.class})

还可以使用包中所包含的类或者接口来指定要扫描的包,你可以考虑专门在每个包中创建一个用来扫描的空标记接口从而解耦。

自动装配

相关注解

@Autowired

声明进行自动装配,假如有且只有一个bean匹配依赖需求的话,那么这个bean会被装配进来

如果没有匹配或有多个匹配bean,Spring将会跑出相应的异常

如将required属性设置设置为false,则在没有匹配的bean时,Spring会让这个bean处于未装配状态。

注:@inject注解功能与@Autowired相近,大多数场景下可互相替换

通过java代码装配Bean

创建配置类

即使用JavaConfig配置类

@Configuration

表明所在类是一个配置类,该类应该包含在Spring应用上下文如何创建bean的细节

在JavaConfig中声明简单的bean

@Bean

@Bean注解会告诉Spring该方法会返回一个对象,该方法要注册为Spring应用上下文中的bean,方法体中包含了最终产生bean实例的逻辑。

@bean
public CompactDisc sgtPeppers(){
return new SgtPeppers();
}

默认情况下bean的ID与带有@Bean注解的方法名是一样的。当然也可以通过name属性指定。

@Bean(name="lovelyClubBand")

依赖注入

同样使用@Bean创建方法,只需要通过参数声明要注入的依赖

@Bean
public CDPlayer cdPlayer(CompactDisc compactDisc){
return new CDPlayer(compactDisc);
}

这只是一种实现DI功能的代码,完全可以采用其他风格的代码实现,java语言是唯一的限制。

条件化的bean

@Conditional

可使用该注解应用到带有@Bean注解的方法上,如果给定的条件(参数类)满足返回true,就会创建这个bean,否则忽略这个bean。

//@Conditional注解的使用方法
@Bean
@Conditional(MagicExistsConidtion.class)
public MagicBean magicBean() {
return new MagicBean();
} //设置给@Conditional的类的创建,只需实现Condition接口的matches方法即可
public class MagicExistsCondition implements Condition {
//判断是否存在magic环境变量
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
Environment env = context.getEnvironment();
return env.containsProperty("magic");
}
}

处理自动装配的歧义性

标记首选bean

使用@Primary注解,可与@Component或@Bean结合使用,或在xml中的bean元素中配置primary="true"属性

@Component
@primary
public Dessert iceCream(){
return new IceCream();
}

但若配置两个@Primary,则仍然出现歧义性问题。

使用限定符

@Qualifier注解

可与@Autowired协同使用,指定想要注入的bean的限定符(如未自己指定限定符,默认限定符为bean ID)

@Autowired
@Qualifier("iceCream")
public void set Dessert(Dessert dessert){
this.dessewrt = dessert;
}
创建自定义限定符

将@Qualifier与@component联合使用,为类定义限定符

@Component
@Qualifier("cold")//为IceCream类定义限定符名称cold,则可以在依赖注入的时候使用@Qualifier("cold")来指定注入这个bean
public class IceCream implements Dessert{...}

自定义限定符注解

由于java不允许在同一个条目上同时出现相同类型的多个注解(如同时出现@Qualifier("cold")和@Qualifier("sweet")),所以我们可以通过自定义注解的方式定义一些不同的限定符注解,从而不断缩小可选bean的范围

//自定义@cold限定符注解
@Target({ElementType.CONSTRUCTOR,ElementType.FIELD,ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface Creamy{}

然后将@Creamy注解分别应用于要装配的bean和注入点(即分别与@Component和@Autowired一起使用)即可

bean的作用域

使用@Scope(param)注解

Spring定义的作用域包括

  • 单例(Singleton):在整个应用中,只创建bean的一个实例
  • 原型(Prototype):每次注入或者通过Spring应用上下文获取的时候,都会创建一个新的bean实例
  • 会话(Session):在web应用中,为每个会话创建一个bean实例
  • 请求(Request):在web应用中,为每个请求创建一个bean实例
@Component
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class Notepad {
// the details of this class are inconsequential to this example
}

若使用xml配置,则可以使用元素的scope属性(scope=“prototype”)来设置作用域。

关于会话和请求作用域的特别之处

需要设置@Scope的参数proxyMode

//设置bean的作用域为会话
@Component
@Scope(
value=WebApplicationContext.SCOPE_SESSION,
proxyMode=ScopedProxyMode.INTERFACES)
public ShoppingCart cart(){ ... }
//定义一个作用域为单例的bean,依赖我们刚才定义的作用域为会话的ShoppingCart bean
@Component
public class StoreService{
@Autowired
public void setShoppingCart(ShoppingCart shoppingCart){
this.shoppingCart = shoppingCart;
}
...
}

因为StoreService是一个单例bean,会在Spring应用上下文加载的时候创建,但 ShoppingCart bean是会话作用域的,要等到某个用户进入了系统创建了会话之后才会出现ShoppingCart实例。

此外系统中将会同时有多个ShoppingCart实例,我们肯定希望当StoreService处理购物车功能的时候所使用的恰好是当前会话所对应的那一个。

对于这种情况,Spring的处理方式是:

Spring注入到StoreService中的实际上是一个到ShoppingCart bean的代理,当StoreService调用ShoppingCart的方法时,代理会对其进行懒解析并将调用委托给会话作用域内真正的ShoppingCart bean。从而完成了会话作用域bean向单例作用域bean的注入。

请求作用域的bean也同样是以作用域代理的方式进行注入。

proxyMode参数的取值
proxyMode=ScopedProxyMode.INTERFACES

如果ShoppingCart是接口而不是类的话,则使用java动态代理创建基于接口的代理。

proxyMode=ScopedProxyMode.TARGET_CLASS

如果ShoppingCart是一个具体的类的话,则必须使用CGLib来生成基于类的代理。

运行时值的注入

使用@PropertySource注解

注入properties配置文件中的值,使用environment加载并加检索。

@Configuration
@PropertySource("classpath:/com/soundsystem/app.properties")
public class ExpressiveConfig{
@Autowired
Environment env; @Bean
public BlankDisc disc(){
return new BlankDisc(env.getProperty("disc.title"),
env.getProperty("disc.artist"));
}
}

从代码里的解释来看environment代表了profile和properties,profile还不知道是啥,profile就是配置文件,比如配置数据库权限链接字符串啥的,肯定见过。Environment的详细api见《Spring实战》P90-P92

《Spring In Action》阅读笔记之装配bean的更多相关文章

  1. spring源码阅读笔记10:bean生命周期

    前面的文章主要集中在分析Spring IOC容器部分的原理,这部分的核心逻辑是和bean创建及管理相关,对于单例bean的管理,从创建好到缓存起来再到销毁,其是有一个完整的生命周期,并且Spring也 ...

  2. spring源码阅读笔记06:bean加载之准备创建bean

    上文中我们学习了bean加载的整个过程,我们知道从spring容器中获取单例bean时会先从缓存尝试获取,如果缓存中不存在已经加载的单例bean就需要从头开始bean的创建,而bean的创建过程是非常 ...

  3. spring源码阅读笔记08:bean加载之创建bean

    上文从整体视角分析了bean创建的流程,分析了Spring在bean创建之前所做的一些准备工作,并且简单分析了一下bean创建的过程,接下来就要详细分析bean创建的各个流程了,这是一个比较复杂的过程 ...

  4. spring in action 学习笔记六:bean在不同情况下的默认id号或者将名字

    bean如果不知名id是什么它一般都有一个id或者讲名字. 第一种情况:组件扫描的情况:默认的id号或者bean的name是类名的首字母小写. 代码如下: package com.qls.beanli ...

  5. spring in action 学习笔记四:bean的生命周期

    bean 的生命周期分为:一个是ApplicationContext的容器的bean的生命周期,另一个是BeanFactory容器的生命周期. 首先介绍一下:ApplicationContext的容器 ...

  6. 1、Spring In Action 4th笔记(1)

    Spring In Action 4th笔记(1) 2016-12-28 1.Spring是一个框架,致力于减轻JEE的开发,它有4个特点: 1.1 基于POJO(Plain Ordinary Jav ...

  7. Spring入门(5)-自动装配Bean属性

    Spring入门(5)-自动装配Bean属性 本文介绍如何装配Bean属性. 0. 目录 ByName ByType constructor 默认自动装配 混合使用自动装配和显示装配 1. ByNam ...

  8. Spring第一课:基于XML装配bean(四),三种实例化方式:默认构造、静态工厂、实例工厂

    Spring中基于XML中的装配bean有三种方式: 1.默认构造 2.静态工厂 3.实例工厂 1.默认构造 在我们在Spring的xml文件中直接通过:     <bean id=" ...

  9. Spring源码阅读笔记

    前言 作为一个Java开发者,工作了几年后,越发觉力有点不从心了,技术的世界实在是太过于辽阔了,接触的东西越多,越感到前所未有的恐慌. 每天捣鼓这个捣鼓那个,结果回过头来,才发现这个也不通,那个也不精 ...

随机推荐

  1. linggle使用技巧

    Linggle 搜索引擎是一个可用于英语写作的语法.句子工具,可帮助学习者分析更准确的英文写作建议,能够根据词性来推测短句和句子,可精准的分享出完整英文句子如何撰写. Linggle 是台湾学术团队研 ...

  2. OpenCV-Python 立体图像的深度图 | 五十二

    目标 在本节中, 我们将学习根据立体图像创建深度图. 基础 在上一节中,我们看到了对极约束和其他相关术语等基本概念.我们还看到,如果我们有两个场景相同的图像,则可以通过直观的方式从中获取深度信息.下面 ...

  3. 推荐|近期热点机器学习git项目

    No1: InterpretML by Microsoft--Machine Learning Interpretability github地址:https://github.com/microso ...

  4. 17.用cmd创建maven web工程

    1.跳转到需要创建maven工程的目录,输入 mvn archetype:generate 2.找到webapp的那一项,输入它的序号(这里是10) 3.输入groupId,artifactId,ve ...

  5. [codevs2597]团伙<并查集>

    题目描述 Description 1920年的芝加哥,出现了一群强盗.如果两个强盗遇上了,那么他们要么是朋友,要么是敌人.而且有一点是肯定的,就是: 我朋友的朋友是我的朋友: 我敌人的敌人也是我的朋友 ...

  6. Linux - ubuntu下Vim安装失败,报The following packages have unmet dependencies: vim : Depends: vim-common

    错误命令行 root@ubuntu:/etc/apt# apt install vim Reading package lists... Done Building dependency tree R ...

  7. 浅谈Java构造器

    Java构造器 每个类都有构造方法.如果没有显式地为类定义构造方法,Java编译器将会为该类提供一个默认构造方法. 在创建一个对象的时候,至少要调用一个构造方法.构造方法的名称必须与类同名,一个类可以 ...

  8. vim效率操作

                                        vim效率操作 案例6:vim效率操作 6.1问题 本例要求掌握使用vim文本编辑器时能够提高操作效率的一些常用技巧和方法,完成 ...

  9. 【数据库】MySQL数据库(三)

    一.MySQL当中的索引: 数组当中我们见过索引:它的好处就是能够快速的通过下标.索引将一个信息查到:或者说 能够快速的定位到一个信息: 1.MySQL中的索引是什么? 它是将我们表中具有索引的那个字 ...

  10. mpvue微信小程序怎么写轮播图,和官方微信代码的差别

    目前用mpvue很多第三方的ui库是引入不了的,因为它不支持含有dom操作. 那我们要做轮播图的话一个是手写另外一个就是用小程序的swiper组件了: 官方代码: <swiper indicat ...