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. [leetcode] 位操作题解

    子集 题目[78]:给定一组不含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集). 示例: 输入: nums = [1,2,3] 输出: [ [3],   [1],   [2],   [ ...

  2. PyTorch专栏(八):微调基于torchvision 0.3的目标检测模型

    专栏目录: 第一章:PyTorch之简介与下载 PyTorch简介 PyTorch环境搭建 第二章:PyTorch之60分钟入门 PyTorch入门 PyTorch自动微分 PyTorch神经网络 P ...

  3. Homebrew中国镜像安装与配置

    1.删除旧Homebrew ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/u ...

  4. 面试刷题29:mysql事务隔离实现原理?

    mysql的事务是innodb存储引擎独有的,myisam存储引擎不支持事务. 事务最经典的例子就是转账了,事务要保证的是一组数据库的操作要么全部成功,要么全部失败.是为了保证高并发场景下数据的正确性 ...

  5. [React]Hook初探

    Hook是什么 Hook是React从16.8开始支持的特性,使用Hook可以在不使用class时使用state Hook支持在不需要修改组件状态的情况下复用逻辑状态,从而解决使用render pro ...

  6. 常用的python标准库

    os  :   操作系统接口 sys:    命令行操作 re : 正则模块 math :   数学模块 time,timedate: 日期模块 random: 随机数模块 threading: 线程 ...

  7. Django之auth用户认证

    auth模块 from django.contrib import auth django.contrib.auth中提供了许多方法,这里主要介绍其中的三个: authenticate()    提供 ...

  8. iOS开发 - 循环滚动的ScrollView

    源码在这里,请多多指教. 由于开发需要,要用到循环自动滚动的scrollView,借鉴了前人的思路,重新设计了一个AutoSlideScrollView.先自吹自擂一翻吧: 借鉴UITableView ...

  9. 001_Three.js中的跨域问题

    001_Three.js中的跨域问题 [情景描述]: 在初始化模型,引入字体和纹理皮肤图片的时候,由于跨域问题,出现了以下提示: Access to image at 'file:///F:/User ...

  10. C#通用类库整理--序列化类

    程序员在编写应用程序的时候往往要将程序的某些数据存储在内存中,然后将其写入某个文件或是将它传输到网络中的另一台计算机上 以实现通讯.这个将程序数据转化成能被存储并传输的格式的过程被称为"序列 ...