Spring
Ioc控制反转
DI(依赖注入)是实现Ioc的一种方法
Ioc就是将得到对象的方式反转,不是由我们自身主动创建(new)对象,而是将创建对象的过程交给spring容器完成,我们只负责从容器中得到(get)对象。
Ioc是Spring的核心。可以使用xml,注解的方式实现Ioc,也可以零配置实现。
Spring容器在初始化时会先读取配置文件,根据配置文件或元数据创建与组织对象存入容器中,程序使用时再从Ioc容器中取出需要的对象。
用XML方式配置Bean时,Bean的定义信息是和实现分离的,而采用注解的方式可以把两者合为一体,Bean的定义信息直接以注解的形式定义在实现类中,从而达到了零配置的目的。
控制反转是一种通过描述(XML或注解)并通过第三方去生产或获取特定对象的方式。在Spring中实现控制反转的是IoC容器,其实现方法是依赖注入(Dependency Injection,DI)。
配置文件Bean.xml
认识
bean.xml:
1 |
|
Hello.java:
1 | public class Hello { |
测试:
1 | public void test(){ |
用法
在配置文件加载时,bean中管理的对象就已经初始化了。
-
当没有定义任何构造方法时会默认调用无参构造方法
-
有参构造方法最常用:
1
2
3
4
5<!-- 根据参数名字设置 -->
<bean id="hello" class="com.kuang.pojo.Hello">
<!-- name指参数名 -->
<constructor-arg name="name" value="cz"/>
</bean>
id是bean的唯一标识符,如果bean中没有设置id值,那么name默认为标识符,如果设置了id,name就是别名,别名可设置多个。
1 | <!--bean就是java对象,由Spring创建和管理--> |
<import resource="{path}/beans.xml"/>
多人import导入其他配置文件可以合并。
DI依赖注入
Bean注入
1. 注意点:这里的值是一个引用,ref
1 | <bean id="addr" class="com.kuang.pojo.Address"> |
2. 数组注入
1 | <bean id="student" class="com.kuang.pojo.Student"> |
3. List注入
1 | <property name="hobbys"> |
4. Map
1 | <property name="card"> |
5. set
1 | <property name="games"> |
6. Null
1 | <property name="wife"><null/></property> |
7. Properties
1 | <property name="info"> |
拓展
User.java : 【注意:这里没有有参构造器!】
1 | public class User { |
- P注入(set方法注入) : 需要在头文件中加入约束文件
1 | 导入约束 : xmlns:p="http://www.springframework.org/schema/p" |
- c 注入(构造器注入) : 需要在头文件中加入约束文件
1 | 导入约束 : xmlns:c="http://www.springframework.org/schema/c" |
1 |
|
Bean作用域
Bean自动装配
隐式的bean发现机制和自动装配
- 组件扫描
- 自动装配
自动装配xml配置(不推荐)
1 |
|
user类拥有猫和狗两个宠物属性,猫狗都有一个sout方法。
byName:
按名称自动装配
1 | <bean id="user" class="com.kuang.pojo.User autowire="byName"></bean> |
当一个bean节点带有 autowire byName的属性时。
- 将查找其类中所有的set方法名,例如setCat,获得将set去掉并且首字母小写的字符串,即cat。
- 去spring容器中寻找是否有此字符串名称id的对象。
- 如果有,就取出注入;如果没有,就报空指针异常。
缺点:当id名与setXXX不同时就会出现空指针报错。
byType:
按类型自动装配
使用autowire byType首先需要保证:同一类型的对象,在spring容器中唯一。如果不唯一,会报不唯一的异常。
1 | <bean class="com.kuang.pojo.Dog"/> |
上面这个就会报错,因为有猫类在上面定义了两个,所以会报错 ``NoUniqueBeanDefinitionException`
去掉id也可以。
小结:
- byname的时候,需要保证所有bean的id唯一,并且这个bean需要和自动注入的属性set方法的值一致。
- bytype的时候,需要保证所有bean的class唯一,并且这个bean需要和自动注入的属性的类型一致。
使用注解自动装配(推荐)
用注解的方式注入属性
- 在spring配置文件中引入context文件头
1 | xmlns:context="http://www.springframework.org/schema/context" |
-
开始属性注解支持
1
<context:annotation-config/>
@Autowired
需要导入spring-aop包
@Autowired
是按bytype类型自动转配的,不支持id匹配,如果要id匹配可以配合@Qualifier(value="<id>")
来匹配id。例子:
将User类中的set方法去掉,使用@Autowired注解
1 | public class User { |
配置文件:
1 | <context:annotation-config/> |
补充:@Autowired(required=false),注解默认为返回true,说明:false是对象允许为null,true是对象不能为空。
还有一个java本身的 @Resource
- @Resource如有指定的name属性,先按该属性进行byName方式查找装配;
- 其次再进行默认的byName方式进行装配;
- 如果以上都不成功,则按byType的方式自动装配。
- 都不成功,则报异常。
@Autowired与@Resource异同:
@Autowired
与@Resource
都可以用来装配bean。都可以写在字段上,或写在setter方法上。@Autowired
默认按类型装配(属于spring规范),默认情况下必须要求依赖对象必须存在,如果要允许null 值,可以设置它的required属性为false,如:@Autowired(required=false) ,如果我们想使用名称装配可以结合@Qualifier注解进行使用@Resource
(属于J2EE复返),默认按照名称进行装配,名称可以通过name属性进行指定。如果没有指定name属性,当注解写在字段上时,默认取字段名进行按照名称查找,如果注解写在setter方法上默认取属性名进行装配。 当找不到与名称匹配的bean时才按照类型进行装配。但是需要注意的是,如果name属性一旦指定,就只会按照名称进行装配。
它们的作用相同都是用注解方式注入对象,但执行顺序不同。@Autowired
先byType,@Resource先byName
。