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. 通过带Flask的REST API在Python中部署PyTorch

    在本教程中,我们将使用Flask来部署PyTorch模型,并用讲解用于模型推断的 REST API.特别是,我们将部署一个预训练的DenseNet 121模 型来检测图像. 备注: 可在GitHub上 ...

  2. JAVA——桌球游戏(动画)

    跟着视频敲得 ,虽然不是自己的思路 ,不过对代码多了一点了解:涉及到继承类 主函数:创建一个BallGame对象,调用一个launchFrame函数 : launchFrame函数:严格来说是方法 , ...

  3. WeChat-SmallProgram:组件 scroll-view 横向和纵向 案例

    scroll-view为滚动视图,分为水平滚动和垂直滚动.注意滚动视图垂直滚动时一定要设置高度否则的话scroll-view不会生效. 滚动视图常用的地方一般都是Item项比较多的界面,比如我的模块 ...

  4. NSArray、NSDictionary

    一.NSDictionary 1.1 使用自定义对象 key Dictionaries manage pairs of keys and values. A key-value pair within ...

  5. 码云上开源JAVA项目收藏

    一. 个人学习项目 1. BootDo面向学习型的开源框架 (可以当做 管理台脚手架) BootDo是高效率,低封装,面向学习型,面向微服的开源Java EE开发框架. BootDo是在SpringB ...

  6. css指示箭头两种实现方法

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  7. 从养孩子谈谈 IO 模型(一)

    同步/异步.阻塞/非阻塞 说的是一回事儿吗? 同步/异步.阻塞/非阻塞 你能通俗易懂的讲清楚吗? Java 中的 BIO.NIO.AIO 你了解吗? Socket 编程你还会吗? Linux 操作系统 ...

  8. react axios 跨域访问一个或多个域名

    1.react + axios 跨域访问一个域名 配置非常简单,只需要在当前的 package.json 文件里面配置: "proxy":"http://iot-demo ...

  9. java仿win7计算器布局

    代码: package calculator; import javax.swing.*; import java.awt.*; import java.awt.event.*; public cla ...

  10. Hadoop (六):MapReduce基本使用

    MapReduce原理 背景 因为如果要对海量数据进行计算,计算机的内存可能会不够. 因此可以把海量数据切割成小块多次计算. 而分布式系统可以把小块分给多态机器并行计算. MapReduce概述 Ma ...