spring在IoC容器中装配Bean详解
1、Spring配置概述
1.1、概述
Spring容器从xml配置、java注解、spring注解中读取bean配置信息,形成bean定义注册表;
根据bean定义注册表实例化bean;
将bean实例放入bean缓存池;
应用程序使用bean。
1.2、基于xml的配置
(1)xml文件概述
xmlns------默认命名空间
xmlns:xsi-------标准命名空间,用于指定自定义命名空间的schema文件
xmlns:xxx=“aaaaa”-------自定义命名空间,xxx是别名,后面的值aaaa是全名
xsi:schemaLocation----------为每个命名空间指定具体的schema文件,格式:命名空间全名文件地址。。。用空格隔开
2、Bean基本配置
2.1、Bean的命名
(1)id和name都可以指定多个名字,名字之间用逗号,分号或空格进行分隔
1
|
< beanname = "#car,123,$car" class = "xxxxxxxxx" > |
用户可以使用getBean("#car"),getBean("123"),getBean("$car")获取bean。
(2)如果没有指定id和name属性,则spring自动将类的全限定名作为bean的名称
(3)如果存在多个匿名bean,即没有指定id和name的<bean/>,假设类的全限定名为xxx,
则获取第一个bean使用getBean("xxx"),获取第二个bean使用getBean("xxx#1"),获取第三个bean使用getBean("xxx#2")。
3、依赖注入
3.1、属性注入
(1)属性注入要求Bean提供一个默认的构造函数,并为需要注入的属性提供Setter方法。spring先调用默认构造函数实例化bean对象,然后通过反射的方式调用Setter方法注入属性值。
(2)spring只会检查bean中是否有对应的Setter方法,至于bean中是否有对应的属性变量则不做要求。
(3)javabean关于属性命名的特殊规范:变量的前2个字母要么全部大写,要么全部小写。
3.2、构造函数注入
(1)构造函数参数的配置顺序不会对配置结果产生影响,spring的配置文件采用和元素标签顺序无关的策略,这种策略可以在一定程度上保证配置信息的确定性。
(2)按索引匹配入参
如果构造函数的入参类型相同,则需要指定参数的顺序索引,否则无法确定对应关系。如:
1
2
|
< constructor-argindex = "0" value = "xxxxxx" > < constructor-argindex = "1" value = "xxxxxx" > |
索引从0开始。
(3)循环依赖问题
如果有2个bean的构造函数配置都依赖对方,则会出现类似线程死锁的问题,
解决的办法就是将构造函数注入改为属性注入。
3.3、工厂方法注入
(1)非静态工厂方法
由于工厂方法不是静态的,所以得先创建一个工厂类的实例bean,并使用factory-bean来引用
1
2
|
< beanid = "carFactory" class = "工厂类" /> < beanid = "car5" factory-bean = "carFactory" factory-method = "createCar" /> |
(2)静态工厂方法
1
|
< beanid = "car5" class = "工厂类" factory-method = "createCar" /> |
3.4、注入参数详解
(1)xml中的5个特殊字符
特殊符号 | 转义序列 | 特殊符号 | 转义序列 |
< | < | "" | " |
> | > | ' | ' |
& | & |
(2)<![CDATA[]]>
<![CDATA[]]>的作用是让XML解析器将标签中的字符串当作普通文本对待。
(3)使用<null/>标签注入null值
(4)级联属性
1
2
3
|
< beanid = "parent" class = "xxxxxxx" > < propertyname = "child.xxx" value = "依赖对象的属性值" /> </ bean > |
spring3.0之前,必须先实例化依赖对象child,否则会抛出异常,spring3.0之后,则不需要在显示实例化,spring容器会自动实例化依赖对象。
(5)集合合并
1
|
< setmerge = "true" /> |
常见于子类合并父类的集合元素
(6)通过util命名空间配置集合类型的bean
如果希望配置一个集合类型的Bean,而不是一个集合类型的属性,则可以通过util命名空间进行配置。
3.5、自动装配
(1)<bean/>元素提供了一个指定自动装配类型的属性autowire
3.6、方法注入
如果我们往单例模式的bean中注入prototype的bean,并希望每次调用时都能够返回一个新的bean,使用传统的注入方式将无法实现,因为单例的bean注入关联bean的动作仅发生一次。
(1)一种可选的解决方法就是让宿主bean实现BeanFactoryAware接口,让宿主bean能够访问容器的引用,这样就可以修改get方法,使用容器的
factory.getBean("被依赖bean")方法,每次都能获得最新的bean。
(2)上面那种方式使我们的代码和spring耦合,实为下策,我们可以通过方法注入的方式解耦。
我们只需定义一个接口,接口中定义一个获取依赖bean的抽象方法,spring配置如下:
1
2
3
4
|
< beanid = "car" class = "被依赖bean" /> < beanid = "host" class = "接口bean" > < lookup-methodname = "getCar" bean = "car" /> </ bean > |
通过lookup-method元素标签为接口bean的getCar()提供动态实现,方法注入的实现主要依赖Cglib包的动态操作字节码技术。
3.7、方法替换
使用bean2替换bean1的getCar方法,前提是bean2得实现MethodReplacer接口,配置如下:
1
2
3
4
|
< beanid = "bean1" class = "aaaaaaaaaa" > < replaced-methodname = "getCar" replacer = "bean2" /> </ bean > < beanid = "bean2" class = "bbbbbbbbb" /> |
4、<bean>之间的关系
4.1、继承
父bean的配置可以被子类继承,避免重复定义,配置如下:
1
2
|
< beanid = "父bean" class = "aaaaaaa" abstract = "true" /> < beanid = "子bean" class = "bbbbbb" > |
子类可以覆盖父类的配置,如果不指定父类的abstract="true",则父bean会被实例化。
4.2、依赖
有些bean的实例化依赖其他bean,其他bean必须先实例化好后才能实例化宿主bean,spring提供了depends-on的属性,指定依赖bean先实例化,如:
1
2
|
< beanid = "host" class = "aaaaaaa" depends-on = "b1" /> < beanid = "b1" class = "bbbbbbb" /> |
如果有多个前置依赖bean,则可以通过逗号,空格或分号的方式创建bean的名称。
4.3、Bean作用域
(1)spring容器在启动时就会实例化所有的bean,如果不想提前实例化,<bean/>的lazy-init="true"属性可以控制延迟实例化,但是如果该bean被其他需要提前实例化的bean引用,则spring也将忽略延迟实例化的设置。
(2)web应用相关的作用域
如果用户使用request,session,globalSession作用域,首先必须在web容器中进行额外的配置:
在低版本的web容器(Servlet2.3之前),可以使用http请求过滤器配置:
1
2
3
4
5
6
7
8
|
< filter > < filter-name >requestContextFilter</ filter-name > < filter-class >org.springframework.web.filter.RequestContextFilter</ filter-class > </ filter > < filter-mapping > < filter-name >requestContextFilter</ filter-name > < url-pattern >/*</ url-pattern > </ filter-mapping > |
在高版本的web容器中,可以使用http请求监听器进行配置:
1
2
3
|
< listener > < listener-class >org.springframework.web.context.request.RequestContextListener</ listener-class > </ listener > |
(3)作用域依赖问题
当将web作用域的bean注入到singleton或prototype的bean中时,要借助于aop,例如:
1
2
3
4
5
6
|
< bean id = "web1" class = "aaaaaa" scope = "request" > < aop:scoped-proxy /> </ bean > < bean id = "singleton1" class = "bbbbbb" > < property name = "z1" ref = "web1" /> </ bean > |
4.4、FactoryBean
一般情况下,spring通过反射机制利用<bean/>的class属性指定实现类实例化bean就可以了。但在某些情况下,实例化bean的过程比较复杂,如果按照传统的方式,则需要在<bean>中提供大量的配置信息。配置方式的灵活性是受限的,这时采用编码的方式可能会得到一个简单的方案。
Spring为此提供了一个org.springframework.beans.factory.FactoryBean工厂类接口,用户可以通过实现该接口,定制实例化bean的逻辑。
当<bean/>的class属性配置的实现类是FactoryBean及其子类时,通过getBean()方法返回的不是FactoryBean及其子类本身,而是返回FactoryBean的getObject()方法返回的对象。
如果希望获取FactoryBean及其子类本身的对象,则在getBean(beanName)方法时显式地在beanName前加上“&”前缀,如getBean("&car5")。
5、基于注解的配置
5.1、注解类型
@Component------原生注解
衍型注解:
@Repository:标注DAO
@Service:标注service
@Controller:标注控制器
5.2、使用注解配置信息启动spring容器
(1)spring2.5以后引入了context命名空间,它提供了通过扫描类包以应用注解定义bean:
1
|
< context:component-scan base-package = "xxxxxxxxxx" resource-pattern = "xxxx/*.class" > |
resource-pattern属性用于指定在基包中需要扫描的特定包下的类
(2)还有更加强大过滤子标签
1
2
3
4
|
< context:component-scan base-package = "xxxxxxxxxx" > < context:include-filter type = "xxxx" expression = "xxxxxxxxxxxxxxxx" /> < context:exclude-filter type = "xxxx" expression = "xxxxxxxxxxxxxxxx" /> </ context:component-scan > |
在所有的类型中,aspectj的过滤能力是最强大的。
5.3、自动装配Bean
(1)@Autowired
@Autowired默认按类型匹配的方式,如果容器中没有一个匹配的bean,spring容器启动时将抛出异常,那么可以使用@Autowired(required=false)进行标注,则不会抛出异常。
使用@Autowired还可以对方法入参直接标注,如果一个方法有多个入参,在默认情况下,spring自动选择匹配入参类型的bean进行注入。
使用@Autowired标注集合变量,可以将所有匹配该集合元素类型的bean都注入进来,很强大。
使用@Autowired装配属性,可以没有setter方法。
(2)@Qualifiler
如果容器中有一个以上匹配的bean,则可以通过@Qualifiler注解限定bean的名称。
(3)对标注注解的支持
spring还支持JSR-250定义的@Resource和JSR-330定义的@Inject注解
@Resource要求提供一个bean的名称属性,如果属性为空,则自动采用变量名或者方法名作为bean的名称。
(4)要点:
如果仅仅使用@Autowired,我们仍然需要显式地在xml中定义<bean/>节点,spring容器默认禁用注解装配,启用的方式是在xml中配置<context:annotation-config/>元素。
但是spring还提供了另一种技巧,使用<context:component-scan/>元素,spring容器就会自动检测bean,而不需要显式的定义<bean/>节点。
spring通过@Component、@Repository、@Service、@Controller注解标注类,让<context:component-scan/>知道哪些类需要注册为SpringBean。
如果使用了第三方的jar包,且希望自动注入第三方jar包中的类,即使第三方jar包的类中没有使用注解标注它们,过滤器元素<context:include-filter>可以替换掉基于注解的组件扫描策略,让<context:component-scan/>自动注册符合expression表达式的类。
5.4、Bean作用范围及生命过程方法
(1)@Scope("xxxx")
通过注解配置的Bean和通过xml配置的Bean一样,默认的作用范围都是singleton。
spring提供了@Scope注解,作用于类上,注解的参数就和xml中<bean/>的scope属性的值一样。
(2)生命过程方法对比
<bean> | 注解 |
init-method | @PostConstruct |
destory-method | @PreDestroy |
区别:注解在类中可以定义多个方法,且方法按顺序执行
6、基于java类的配置
6.1、使用java类提供Bean定义信息
(1)普通的POJO只要标注@Configuration注解,就可以为spring容器提供bean定义的信息,每个标注了@Bean的方法都相当于提供一个Bean的定义信息。
(2)@Bean
Bean的类型由@Bean标注的方法的返回值类型决定
Bean的名称默认和方法名相同,也可以通过@Bean(name="xxx")来显式指定
可以在@Bean处使用@Scope,标注Bean的使用范围
(3)@Configuration
由于@Configuration注解类本身已经标注了@Component注解,所以任何标注了@Configurstion的类,都可以使用@Autowired被自动装配到其他类中。
6.2、使用基于java类的配置信息启动spring容器
(1)spring提供了一个AnnotationConfigApplicationContect类,它能够直接通过标注@Configuration注解的类启动Spring容器。
(2)当有多个配置类时
可以通过AnnotationConfigApplicationContect的register方法一个个注册,然后再调用refresh方法刷新容器以应用这些注册的配置类。
也可以通过@Import(xxx.class)注解,将其他配置类全部引入到一个配置类中,这样仅需要注册一个配置类即可
(3)通过xml配置类引用@Configuration的配置
1
|
< context:component-scanbase-package = "......" resource-pattern = "配置类名" > |
(4)在配置类中引用xml配置信息
在@Configuration处使用@ImportResource("classpath:................")来引入xml配置文件
6.3、3种配置方式的比较
XML | 注解 | java类 |
|
Bean的实现类是当前项目开发 | 通过代码方式控制Bean初始化整体逻辑,适用于实例化Bean比较复杂的场景 |
总结
以上就是本文关于spring在IoC容器中装配Bean详解的全部内容,欢迎补充评论。
spring在IoC容器中装配Bean详解的更多相关文章
- (转)java之Spring(IOC)注解装配Bean详解
java之Spring(IOC)注解装配Bean详解 在这里我们要详细说明一下利用Annotation-注解来装配Bean. 因为如果你学会了注解,你就再也不愿意去手动配置xml文件了,下面就看看 ...
- java之Spring(IOC)注解装配Bean详解
在这里我们要详细说明一下利用Annotation-注解来装配Bean. 因为如果你学会了注解,你就再也不愿意去手动配置xml文件了,下面就看看Annotation的魅力所在吧. 先来看看之前的bean ...
- Spring重点—— IOC 容器中 Bean 的生命周期
一.理解 Bean 的生命周期,对学习 Spring 的整个运行流程有极大的帮助. 二.在 IOC 容器中,Bean 的生命周期由 Spring IOC 容器进行管理. 三.在没有添加后置处理器的情况 ...
- spring学习笔记三:Component注解(把POJO类实例化到spring的IOC容器中)
Component注解:把普通的POJO 类实例化到spring的IOC容器中,就是定义成<bean id="" class=""> 项目目录树: ...
- 【spring源码学习】spring的IOC容器之自定义xml配置标签扩展namspaceHandler向IOC容器中注册bean
[spring以及第三方jar的案例]在spring中的aop相关配置的标签,线程池相关配置的标签,都是基于该种方式实现的.包括dubbo的配置标签都是基于该方式实现的.[一]原理 ===>sp ...
- Spring学习-- IOC 容器中 bean 的生命周期
Spring IOC 容器可以管理 bean 的生命周期 , Spring 允许在 bean 声明周期的特定点执行定制的任务. Spring IOC 容器对 bean 的生命周期进行管理的过程: 通过 ...
- Spring扩展:替换IOC容器中的Bean组件 -- @Replace注解
1.背景: 工作中是否有这样的场景?一个软件系统会同时有多个不同版本部署,比如我现在做的IM系统,同时又作为公司的技术输出给其他银行,不同的银行有自己的业务实现(比如登陆验证.用户信息查询等) ...
- Spring:获取容器中的Bean
某些情况下我们要获取 IOC 容器中指定注解.类型.名字的 Bean 要获取 IOC 容器中指定条件的 Bean 可以通过 ApplicationContext 相应的方法 @Autowired pr ...
- Spring学习--实现 FactoryBean 接口在 Spring IOC 容器中配置 Bean
Spring 中有两种类型的 bean , 一种是普通的 bean , 另一种是工厂 bean , 即 FactroyBean. 工厂 bean 跟普通 bean 不同 , 其返回的对象不是指定类的一 ...
随机推荐
- Java 截取字符串中指定数据及之后数据
String resCallBackJson="12556{1{{{456858585{"; resCallBackJson = resCallBackJson.su ...
- 睡梦中被拉起来执行Spring事务
梦中惊醒 在Tomcat的线程池里,有这样一个线程,自打出生后,从来不去干活儿,有好多次走出线程池“这座大山”去看世界的机会,都被他拱手让给了弟兄们. 弟兄们给他取了个名字叫二师兄.没错,好吃懒做,饱 ...
- [C++] 重载运算符与类型转换(1)
1.形式:返回值 operator符号(参数列表){} 2.不能被重载的运算符::: 作用域运算符 .* . 成员访问运算符 ?: 条件运算符:某些运算符(逗号,,取地址&, ...
- Java基础系列-深入理解==和equals的区别(一)
一.前言 说到==和equals的问题,面试的时候可能经常被问题到,有时候如果你真的没有搞清楚里边的原因,被面试官一顿绕就懵了,所以今天我们也来彻底了解一下这个知识点. 二.==和equals的作用 ...
- 第八届蓝桥杯java b组第九题
标题: 分巧克力 儿童节那天有K位小朋友到小明家做客.小明拿出了珍藏的巧克力招待小朋友们. 小明一共有N块巧克力,其中第i块是Hi x Wi的方格组成的长方形. 为了公平起见,小明需要从这 N ...
- mybatis 插件的原理-责任链和动态代理的体现
目录 1 拦截哪些方法 2 如何代理 3 代理对象 4 责任链设计模式 @ 如果没有自定义过拦截器, 可以看我前面的文章.如果不知道 JDK 动态代理怎么使用的, 可以看我这文章. 责任链设计模式理解 ...
- flask+layui+echarts实现前端动态图展示数据
效果图: 该效果主要实现一个table展示数据,并在下方生成一个折线图. 实现方式: 1.首先需要对表格进行一个数据加载,这里用到了layui的table.render,具体用法可以参考 https: ...
- ORM组件LogORM使用指北
LogORM是一个对数据库进行对象关系映射的ORM组件.当对数据库进行增删改操作时,组件会自动进行日志记录. 该组件支持.Net平台和.NetCore平台,支持SQL Server.Oracle.My ...
- Angular 自定义管道
管道的作用就是将原始值进行转化处理,转换为所需要的值: 1. 新建sex-reform.pipe.ts文件 ng g pipe sex-reform 2. 编辑sex-reform.pipe.ts文件 ...
- RabbitMQ原理介绍
RabbitMQ历史 RabbitMQ消息系统是一个由erlang开发的AMQP(Advanced Message Queue )的开源实现.在同步消息通讯的世界里有很多公开标准(如COBAR的IIO ...