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. python之面向对象性封装,多态,以及鸭子类型

    默认类型 class A: class_name = 'python23期' def __init__(self, name, age): self.name = name self.age =age ...

  2. Transformers 词汇表 | 二

    作者|huggingface 编译|VK 来源|Github 词汇表每种模型都不同,但与其他模型相似.因此,大多数模型使用相同的输入,此处将在用法示例中进行详细说明. 输入ID 输入id通常是传递给模 ...

  3. 线段树(区间合并)HDU - 1540

    题意:输入n,m,给定n个相互连通的村庄,有m个操作,D x,表示破坏x村庄使其与相邻的两个村庄不相通,R 表示修复上一个被破坏的村庄,与相邻的两个村庄联通.Q x表示与x相连的村庄有多少个. 思路: ...

  4. MySql查询当天、本周、本月、本季度、本年的数据

    1.今天 SELECT * FROM 表名 WHERE TO_DAYS(时间字段名) = TO_DAYS(NOW()); 2.昨天 ; 3.本周 SELECT * FROM 表名 WHERE YEAR ...

  5. HTML 基础(五)

    一.列表 有序列表 无序列表 自定义列表 无序列表 无序列表是一个项目的列表,此列项目使用粗体圆点进行标记 无序列表使用 <ul> 标签 <ul> <li>Coff ...

  6. Python itchat库(1)

    一.实验环境 在cmd中输入以下命令,完成微信的API包itchat的安装. pip install itchat 注意这里有个问题,因为电脑里既有Python3.6,又有anaconda.所以一定要 ...

  7. Window.requestAnimationFrame()动画更新

    概述 Window.requestAnimationFrame()方法告诉浏览器你希望执行动画,并且再下一次重绘之前要求浏览器调用一个特定的函数去更新动画.该方法把一个回调函数作为参数,该回调函数会在 ...

  8. 解决MySQL workbench的resultgird不出现的问题

    23:01:37 2019-08-08 鸽了好久 终于开始看怎么使用MySQL workbench了 首先就是遇到了result gird不显示的问题 搜了 重启是一种办法(这方法...至少能用) 其 ...

  9. 《综合》MMM集群

    <综合>MMM集群 部署集群基础环境 MySQL-MMM架构部署 MySQL-MMM架构使用 1 部署集群基础环境 1.1 问题 本案例要求为MySQL集群准备基础环境,完成以下任务操作: ...

  10. 面试刷题37:微服务是什么?springcloud,springboot是什么?

    面试中被问到为什么要使用微服务架构?springcloud的核心组件有哪些? 拿我们国家的兵种来说,如何把战争这个单体架构微服务化,就是根据适用的场景,拆分出不同的兵种(微服务) 然后每个兵种之间通过 ...