装配SpringBean

1.依赖注入的三种方式

实际环境中实现 IoC 容器的方式主要分为两大类, 一类是依赖查找,依赖查找是通过资源定位,把对应的资源查找回来。另一类则是依赖注入,Spring主要使用的是依赖注入。依赖注入可分为3种方式:

  • 构造器注入
  • setter注入
  • 接口注入

构造器注入和 setter 注入是主要的方式,而接口注入是从别的地方注入的方式。
(1)构造器注入
构造器注入依赖于构造方法实现,构造方法可以是含参或无参数的。一般情况下,通过类的构造方法创建类对象,Spring可以采用反射,通过使用构造方法完成注入,这就是构造器注入的原理。为了让 Spring 完成对应的构造注入,我们有必要去描述具体的类、构造方法并设置对应的参数,这样 Spring 就会通过对应的信息用反射的形式创建对象。
构造器注入:
在这里插入图片描述
构造器配置:
在这里插入图片描述
constructor-arg元素用于定义类构造方法的参数,index用于定义参数的位置,value是设置值。
2.使用setter注入
setter注入是Spring中主流的注入方法,使用java Bean规范定义的setter方法完成注入,可读性高。消除使用构造器注入出现多个参数的可能性,首先可以把构造方法声明为无参数的,随后使用setter注入为其设置对应的值,也是通过java反射技术实现。
在这里插入图片描述
Spring通过反射调用没有参数的构造方法生成对象,同时通过反射对应的setter注入配置的值。
3.接口注入
有些时候资源并非来自于自身系统,而是来自于外界,比如数据库连接资源完全可以在Tomcat下配置,然后通过 JNDI 形式去获取它,这样数据库连接资源是属于开发外的资源,这个时候我们可以采用接口注入的形式来获取它。
例如:配置Tomcat后,打开服务器的context.xml配置Tomcat数据源,,在xml文件中的context加入一个资源:
在这里插入图片描述
如果已经配置了相应的数据库连接,那么 Eclipse 会把数据库的驱动包复制到对应的Tomcat lib 文件夹下,否则就需要自己手工将对应的驱动包复制到 Tomcat 工作目录下,位于Tomcat_Home lib,然后启动 Tomcat ,这个时候数据库资源也会在 Tomcat 启动的时候被其加载进来。
通过JNDI得到Tomcat启动的数据库连接池:
在这里插入图片描述
这样就可以再SpringIoC容器中得到数据库连接池。

2. 装配Bean概述

在Spring中提供3种方法进行配置:

  • XML中
  • java的接口和类中实现配置
  • 隐式Bean的发现机制和自动装配原则

三种配置方法的优先级:
(1)基于约定优于配置的原则,最优先的是通过隐式Bean的发现机制和自动装配的原则。好处是减少程序开发者的决定权。
(2)java接口和类中实现配置,好处是避免XML配置的泛滥,更容易。
(3)XML配置SpringIoC容器。
当配置的类是自身正在开发的工程,应该考虑java配置为主,java配置分为自动装配和Bean名称配置。优先使用自动装配,可以减少大量XML配置,当所需配置类非自身工程,使用XML。

3.通过XML配置装配Bean

使用XML装配Bean需要定义对应的XML,需要引入对应的xml模式文件,文件定义装配SpringBean的元素:
在这里插入图片描述
1.装配简易值
简易xml装配bean:
在这里插入图片描述

  • id属性是Spring找到的该Bean的编号,但是id不是一个必须的属性,当没有声明id,Spring使用“全限定名#{number}”方式生成编号。
  • class是一个类的全限定名
  • property元素是定义类的属性,其中 name 属性定义的是属性名称,而 value 是其值。
  • 当有注入一些自定义的类,例如之前的果汁制造器例子,需要原料信息和饮品店共同完成,因此可能要先定义原料信息,在制造器中引入原料:
    在这里插入图片描述
    这里先定义了 id source Bean ,然后在制造器中通过 ref 属性去引用对应的
    Bean ,而 source 正是之前定义的 Bean id ,这样就可以相互引用了。

2.装配集合
有些时候要做一些复杂的装配工作,比如 Set Map List Array Properties 等。首先定义一个Bean:
在这里插入图片描述
装配集合类:
在这里插入图片描述

在这里插入图片描述

  • List 属性为对应的<li st>元素进行装配,然后通过多个<valu >元素设值。

  • Map 属性为对应的<map>元素进行装配,然后通过多个<entry>元素设值,只是 包含 个键( key)和 个值( value )的设置。

  • Properties 属性,为对应的<properties>元素进行装配,通过多个<property>元素设置, 只是 property元素有个必填属性 key ,然后可以设置值。

  • Set 属性为对应的<set>元素进行装配,然后通过多个<value >元素设值。

  • 对于数组而言,可以使用<array>设置值,然后通过多个<value >元素设值。

有时候需要复杂的装载,如一个List可以是一个系列类的对象,如一个Map集合类,键可以是一个类对象,值要一个类对象。首先创建两个POJO:
在这里插入图片描述
在这里插入图片描述
装配用户和角色类:
在这里插入图片描述
配置用户角色:
在这里插入图片描述
在这里插入图片描述
3.命名空间装配
在使用命名空间时要先引入对应的命名空间和xml模式文件。使用xml命名空间注册角色:
在这里插入图片描述

  • 加粗的代码定义了xml的命名空间,这样才能使用p和c的前缀定义
  • id为role1的角色定义,c:_0代表构造方法的第一个参数,c:_1为第二个,c:_2为第三个。
  • id为role2定义,p代表引用属性,p:id=“2”以2为值,使用setId方法设置,

通过命名空间定义UserRoleAssembly类实例:
在这里插入图片描述
在这里插入图片描述
加粗的代码为命名空间和XSD文件,通过命名空间util定义Map、Set和List对象

4. 通过注解装配Bean

使用注解的方式减少xml配置,既能实现xml功能,也提供了自动装配的功能,采用自动装配后,有利于程序开发。
Spring中,有两种方式让SpringIoC容器发现Bean:

  • 组件扫描:通过定义资源的方式 让Spring IoC 容器扫描对应的包,从而把Bean装配进来。
  • 自动装配:通过注解定义,使得依赖关系可以通过注解完成。
    1.使用@Component装配Bean
    首先定义一个POJO:
    在这里插入图片描述
  • 注解@Component代表Spring IoC 会把这个类扫描生成 Bean 实例,而其中的 value属性代表这个类在Spring 中的id,这就相当于 XML 方式定义的 Bean的 id ,也可以简写成@Component(” role ”), 甚至直接写成@Component ,对于不写的, Spring IoC 容器就默认类名,但是以首字母小写的形式作为 id ,为其生成对象,配置到容器中。
  • 注解@Value 代表的是值的注入,这里只是简单注入一些值,其中id是一个long 型,注入的时候 Spring 会为其转化类型。

使用javaConifg告知SpringIoC在哪扫描对象:
在这里插入图片描述
javaConfig中的包名必须和POJO一致。
@ComponentScan代表进行扫描,默认为扫描当前包的路径,pojo的包名和它保持一致才能扫描,否则没有
通过Spring定义好的SpringIoC容器的实现类-AnnotationConfigApplicationContext生成IoC容器。
在这里插入图片描述使用了 AnnotationConfigApplicationContext 类去初始化Spring IoC容器,其配置项是PojoConfig类。这样SpringIoC根据注解的配置解析对应的资源,生成IoC容器。
对于@ComponentScan注解,只扫描所在包的java类,真正需要的是可以扫描所指定的类。
@ComponentScan 存在着两个配置项,一个是 basePackages,它是由base package两个单词组成的 ,而package还使用了复数,意味着它可以配置一个Java 包的数组, Spring会根据它的配置扫描对应的包和子包,将配置好的 Bean 装配进来;basePackageClasses,它由 base package class三个单词组成的,采用复数 意味着它可以配置多个类, Spring 会根据配置的类所在的包,为包和子包进行扫描装配对应配置的Bean。
为验证@ComponentScan的两个配置项,先定义一个接口RoleService:
在这里插入图片描述
实现上列接口:
在这里插入图片描述
@Component说明其是一个Spring需要的Bean,也实现了对应的RoleService接口定义的方法。
配置@ComponentScan制定包扫描:
在这里插入图片描述
加粗的代码是对扫描包的定义,使用任意一个@ComponentScan定义,取消代码中的注释。
当使用多个@ComponentScan定义对应的包,每定义一个@ComponentScan,Spring会为所定义的类生成一个新的对象,也就是所配置的Bean将会生成多个实例。
对于已定义了 basePackage、 basePackageClasses的@ComponentScan, Spring 会进行专门的区分,也就是说在同一个@ComponentScan 中即使重复定义相同的包或者存在其子包定义,也不会造成因同 Bean 多次扫描,而导致 次配置生成多个对象。
2.自动装配 ——@Autowired
学习SpringIoC容器,Spring首先完成Bean的定义和生成,然后寻找需要注入的资源。当Spring生成所有的Bean后,当发现这个注解,就会在Bean中查找,然后找到对应的类型,将其注入进来,这样就完成依赖注入。
自动装配是一种由Spring自身发现对应的Bean,自动完成装配工作的方法,会应用到注解@Autowired,这个时候Spring会根据类型去寻找定义的Bean然后将其注入。
对自动装配进行测试:
首先定义一个接口,对上面的RoleService接口进行改变:
在这里插入图片描述
对该接口进行实现:
在这里插入图片描述
@Autowired注解表示在SpringIoC定位所有的Bean后,这个字段需要按类型注入,这样IoC容器会寻找资源,然后将其注入。
IoC容器有时候会寻找失败,默认情况下寻找失败就会抛出异常。@Autowired 除可以配置在属性之外,还允许方法配置,常见的 Bean setter方法也可以使用它来完成注入。
在这里插入图片描述
在大部分的配置中笔者都推荐使用@Autowired 注解,这是 Spring IoC 自动装配完成的,使得配置大幅度减少,满足约定优于配置的原则,增强程序的健壮性。
3.自动装配的歧义性
@Autowired注解有时候不能使用,一切的根源来自按类型的方式来注入对象,按Spring的方法,大部分情况下会使用接口,但是定义一个接口不一定只有与之对应的一个实现类。一个接口可能会有多个实现类,这时SpringIoC容器出现问题,无法判断将哪个对象注入进去,于是会抛出异常,@Autowired注入失败。同样,抽象类也可以有多个实例化的类,这样会造成通过类型获取Bean的不唯一,导致SpringIoC类似按类型的方法无法获取唯一的实例类。
通过 RoleService.class 作为参数就无法判断使用哪个类实例进行返回,这便是自动装配的歧义性。使用@Primary和@Qualifier消除注解。
(1)注解@Primary
该注解代表优先的。当 Spring IoC 通过1个接口或者抽象类注入对象的时候,由于存在多个实现类或者具体类,就会犯糊涂,不知道采用哪个类注入为好。注解@Primary则是告诉 Spring IoC 容器,请优先使用该类注入。
在这里插入图片描述
这里的@Primary 注解告诉 Spring IoC 容器,如果存在多个 RoleService 类型,无法判断注入哪个的时候,优先将 RoleServicelmpl3 实例注入,这样就可以消除歧义性。@Prima 只能解决首要性的问题,而不能解决选择性的问题,简而言之,它不能选择使用接口具体的实现类去注入。
(2)注解@Quailfier
除了按照类型查找Bean,SpringIoC容器最底层的接口BeanFactory也是定义了按照名称查找的方法,如果采用名称查找的方法则会消除歧义性。例如:将RoleServiceImpl3定义了别名roleService3,:
在这里插入图片描述这个时候 IoC 容器就不会再按照类型的方式注入,而是按照名称的方式注入,这样既能注入成功,也不存在歧义性。IoC容器的底层接口BeanFactory所定义的方法:
在这里插入图片描述使用@Qualifier 注解后就可以使用这个方法通过名称从 IoC 容器中获取对象进行注入。
4.装载带有参数的构造方法类
一些带有参数的构造方法也允许我们通过注解进行注入:
在这里插入图片描述
在构造方法中使用@Autowired:
在这里插入图片描述
5. 使用@Bean装配Bean
@Component只能注解到类上,不能注解到方法。使用@Bean能够注解到方法上,将方法返回的对象作为Spring的Bean,存放在IoC容器。例如使用@Bean装配数据源Bean:
在这里插入图片描述
6.注解自定义Bean的初始化和销毁方法
对于Bean的初始化通过实现Spring所定义的一些关于生命周期的接口实现,这样BeanFactory或者其他高级容器ApplicationContext就可以调用这些接口所定义的方法。
如何在注解中实现自定义的初始化方法和销毁方法:主要是运用注解@Bean 的配置项,注解@Bean 不能使用在类的标注上,主要使用在方法上。@Bean配置项中包括如下:
name:一个字符串数组,允许配置多个BeanName
autowire:标志是否是一个引用的Bean的对象,默认值为Autowired,NO
initMethod:自定义初始化方法
destroyMethod:自定义销毁方法
自定义的初始化方法是配置initMethod,销毁是destroyMethod。使用一个方法创建一个POJO实例,指明初始化方法和销毁方法。
在这里插入图片描述
这样一个 Spring Bean 就可以注册到 Spring IoC 容器中了,也可以使用自动装配的方法将它装配到其它Bean。

5. 装配的混合使用

使用xml配置数据源:
在这里插入图片描述
Spring 同时支持这两种形式的装配,所以可以自由选择,只是无论采用 XML 还是注解方式的装配都是将 Bean 装配到 Spring IoC 容器中,这样就可以通过 Spring IoC 容器去管理各类资源了。
例如:对于数据池的配置,DBCP数据库连接池通过第三方定义,因为给第三方不能加入注解,但是可以选择通过XML给出,假设配置xml文件:spring-data.xml,通过引入其达到注解的体系,注解的体系需要完成对角色编号为1的查询功能。
首先使用注解@ImportResource,引入spring-data.xml所定义的内容:
在这里插入图片描述
@ImportResource 配置的内容是个数组,也就是可以配置多个 XML 配置文件,这样就可以引入多个 XML 定义的 Bean。随后使用@Autowired注入去实现对数据库连接池的注入。
例如;定义角色查询的接口:
在这里插入图片描述
实现类:
在这里插入图片描述
通过这样的形式就能够将XML所配置的 dataSourc 注入 RoleDat SourceServicelmpl中了。
有时候所有的配置都放在 ApplicationConfig 类里面会造成配置复杂,因此希望有多个类似于ApplicationConfig配置类,如ApplicationConfig2、ApplicationConfig3等,Spring使用注解@Import注入这些类:
在这里插入图片描述
有多个 XML 文件,而你希望通过其中一个XML文件去引入其他的 XML 文件,假
设目前有了Spring-bean.xml, 需要引入 spring -datasource.xml,那么可以在 Spring-bean .xml使用 import 元素来加载它。

<import resourse="spring-datasource.xml"> 

Spring可以支持通过xml的配置扫描注解的包,只需要通过<context:component-scan >定义扫描的包就可以:
在这里插入图片描述

6. 使用Profile

在软件开发的过程中 ,敏捷开发模式很常见,也就是每次都提交一个小阶段的测试,那么可能是开发人员使用一套环境,而测试人员使用另一套环境,而这两套系统的数据库是不一样的,毕竟测试人员也需要花费很多的时间去构建测试数据,可不想老是被开发人员修改那些测试数据,这样就有了在不同的环境中进行切换的需求了。 Spring 也会对这样的场景进行支持,Spring 中我们可以定义 Bean Profile。
1.使用注解@Profile配置
例如:配置两个数据库连接池,一个用于开发( dev ),一个用于测试( test ):
在这里插入图片描述
在这里插入图片描述
这里定义了两个 Bean 分别定义了@Profile,一个是 dev ,一个是 test ,同样,使用XML 可以进行定义。
2.使用xml定义Profile
xml配置Profile:
在这里插入图片描述
配置多个Profile:
在这里插入图片描述
在这里插入图片描述
3.启动Profile
当启动 Java配置或者 XML 配置,Profile 可以发现这两个 Bean 并不会被加载到 SpringIoC 容器中, 需要自行激活 Profile 。

  • 在使用 Spring MVC 情况下可配置 Web 上下文参数,或者 DispatchServlet参数。

  • 作为 JNDI 条目。

  • 配置环境变量。

  • 配 启动参数。

  • 在集成测试环境中 用@ActiveProfiles

加载带有@Profile(“dev”)的Bean:
在这里插入图片描述
加入@ActiveProfiles来指定加载哪个Profile,
有些时候要在一些服务器上运行,那么这个时候可以配置 Java 虚拟机的启动项,比如在 Tomcat 服务器上或者main 方法上,那么这个时候可以启用 Java 虚拟机的参数来实现它。

  • spring.profiles.active
  • spring.profiles.default

这个时候可以配置JVM的参数来启用对应的 Profile,例如:
JAVA OPTS=”-Dspring.profiles.active=test ”
使用web.xml配置Profile:
在这里插入图片描述

7. 加载属性文件properties

在开发的过程中,配置文件往往就是那些属性(prop rti es )文件,比如使用 properties文件配置数据库文件,又如 database-config. properrties:
在这里插入图片描述Spring中也可以通过注解或者 XML 的方式进行加载属性文件
1.使用注解方法加载属性文件
Spring提供了注解@PropertySource加载属性文件:

  • name: 字符串,配置这次属性配置的名称。
  • value:字符串数组,可以配置多个属性文件
  • ignoreResourceNotFound: boolea值,默认为 false ,其含义为如果找不到对应的属性文件是否进行忽略处理,由于默认值为 false ,所以在默认的情况下找不到对应的配置文件会抛出异常。
  • encoding:编码,默认为“”

如果只有@PropertySource 的加载, Spring 只会把对应文件加载进来。因此可以在Spring 环境中使用它们,比如先重新定义 Java 配置类:
在这里插入图片描述
@PropertySource 的配置,首先加载了 database-config. properties 文件,然后定义选项为ignoreResourceNotFound=true ,也就是找不到该文件就会忽略掉它。加载数据库属性文件:
在这里插入图片描述
使用注解@Value和占位符来引用属性文件的配置:
在这里插入图片描述
2.使用xml方法加载属性文件
只需要使用<context:property=placeholder >元素加载一些配置项:
在这里插入图片描述
ignore-resource-not-found属性代表着是否允许文件不存在,配置为 true ,则允许不存在。当默认值为 false 时, 不允许文件不存在,如果不存在 Spring 抛出异常。配置多个属性文件:
在这里插入图片描述

8. 条件化装配Bean

一些情况需要通过条件化判断,Spring提供注解@Conditional去配置,可以配置一个或多个类,只是这些类都需要实现接口Condition。
首先修改生成数据源的方法:
在这里插入图片描述
通过@Value往参数里注入对应属性文件的配置

9. Bean的作用域

默认SpringIoC容器只会对一个Bean创建一个实例:
在这里插入图片描述
默认情况下SpringIoC容器只会为配置的Bean生成一个实例。RoleService==RoleService2为true。
Spring有四种作用域:

  • 单例:在整个应用中Spring只为其生成一个Bean的实例
  • 原型(prototype):当每次注入,或者通过SpringIoC容器获取Bean时,Spring都会为其创建一个新的实例。
  • 会话(session):在web应用中,在会话过程中Spring只创建一个实例
  • 请求(request):在web应用中使用,一次请求中Spring创建一个实例,但是不同的请求会创建不同的实例

10. 使用Spring表达式(SpringEL)

SpringEL可以获得比使用Propertes文件更强大的装配功能。拥有很多功能:
使用Bean的id引用Bean
调用指定对象的方法和访问对象的属性
进行运算
集合配置
提供正则表达式匹配
1.SpringEL相关类
首先介绍ExpressionParser接口是一个表达式接口:
在这里插入图片描述
SpringEL的使用:
在这里插入图片描述
2.Bean的属性和方法
使用注解的方式需要用到注解@Value, 在属性文件的读取中使用的是“$,而在 Spring EL 中则使用“#”。
使用SpringEL初始化角色类:
在这里插入图片描述
通过SpringEL引用role的属性,调用其方法:
在这里插入图片描述
3.使用类的静态常量和方法
在这里插入图片描述
Math表示java.lang.*包下的Math类,如果在Spring中使用一个非该包的内容,则需要给出该类的全限定名:
在这里插入图片描述
这样就可以通过调用类的静态方法加载对应的数据。
4.SpringEL运算
SpringEL还可以进行运算,在ELbean中增加一个数字num,其值默认为要求是角色编号(id)+1:
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值