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. 3D画廊

    3D画廊 之前我都是写的学习的内容,我在写这些教程时遇到有趣的炫酷的小例子也会专门拿出来写一篇文章,今天就写一个酷炫的小例子,叫3D画廊,它是属于ViewPage的进阶版. 此项目下载地点:https ...

  2. C 实战练习题目1

    题目:有1.2.3.4个数字,能组成多少个互不相同且无重复数字的三位数?都是多少? 程序分析:可填在百位.十位.个位的数字都是1.2.3.4.组成所有的排列后再去 掉不满足条件的排列. 实例: #in ...

  3. 一份精简的Numpy使用指引(附python演练)

    欢迎大家关注我们的网站和系列教程:http://www.tensorflownews.com/,学习更多的机器学习.深度学习的知识! Numpy 的主要用途是以数组的形式进行数据操作. 机器学习中大多 ...

  4. 学霸双胞胎开源斯坦福CS 221人工智能备忘录,图文并茂看懂反射、状态、变量、逻辑...

    一份斯坦福CS 221人工智能备忘录最近登上了GitHub Trending. 这份备忘录解释了课程中的许多名词.公式和原理,动图.文字.表格并茂,作者之一还是官方助教,堪称CS 221最佳学习笔记. ...

  5. 对于一个由0..n的所有数按升序组成的序列,我们要进行一些筛选,每次我们取当前所有数字中从小到大的第奇数位个的数,并将其丢弃。重复这一过程直到最后剩下一个数。请求出最后剩下的数字。

    输入描述: 每组数据一行一个数字,为题目中的n(n小于等于1000). 输出描述: 一行输出最后剩下的数字.我的思路是用两个链表,一个用于存储原数据,一个用于存储要丢掉的数据,再循环从元数据中剔除掉即 ...

  6. 一个js函数算出任意位数的水仙花数

    一个算出任意位数的水仙花数的函数如下: var arr =[]; /*更改num确定取值范围*/ for(var num = 100; num <= 9999;num++){ /*多位数版本*/ ...

  7. spring5之容器始末源码赏析 (一)总览

    首先,本系列并不是以介绍spring5 的新特性为主,之所以以spring5为标题,是因为即将赏析的源码来自最新的spring版本.虽说是spring最新版本,但是容器的整个生命周期与之前版本相比,并 ...

  8. captcha-killer burp验证码识别插件体验

    0x01 使用背景 在渗透测试和src挖洞碰到验证码不可绕过时,就会需要对存在验证码的登录表单进行爆破,以前一直使用PKav HTTP Fuzzer和伏羲验证码识别来爆破,但是两者都有缺点PKav H ...

  9. Educational Codeforces Round 84 (Rated for Div. 2)

    A. Sum of Odd Integers(思维) 思路 这一题看完ans之后觉得是真简单,不过有一些地方还是要理解的. 这一题输出YES,有两个条件 kk%2 == n%2k,这个条件的意思是 k ...

  10. Boxes Packing

    Boxes Packing Mishka has got n empty boxes. For every i (1 ≤ i ≤ n), i-th box is a cube with side le ...