自动装配
我们进行对象注入的时候有两种方式
- 1 set方法注入
<property name="uerDao" ref="userDao" />
- 2 构造方法注入
<constructor-arg>
<ref bean="userDao"/>
</constructor-arg>
现在来学习自动注入,就是不需要指定以上两种方式
Autowire : 自动装配,两种取值
- 1 byName
- 2 byType
byName
byName是根据setter方法名字进行匹配,如果找不到,就不赋值
如 setUserDao 方法 就会找userDao,如果 bean的ID为 UserDao 也一样找不到,区分大小写
设置方式
<bean name="userDao" class="com.tledu.zrz.dao.impl.UserDaoImpl">
</bean>
<bean id="userService" class="com.tledu.zrz.service.UserService"
autowire="byName">
</bean>
byType
byType是根据setter方法的参数列表中的数据类型进行匹配,如果beans.xml中出现了多个相同类型的对象,就会报错
如 setUserDao(UserDao userDao) 方法 就会找UserDao,如果是接口,就找对应的实现类对象
设置方式
<bean name="userDao" class="com.tledu.zrz.dao.impl.UserDaoImpl">
</bean>
<bean id="userService" class="com.tledu.zrz.service.UserService"
autowire="byType">
</bean>
注意 : 使用自动装配,需要有公共的无参构造,虽然这里就算是私有化构造方法也依然可以创建对象,但是还是提供一个公共的比较好,万一别的框架需要呢
生命周期和迟加载
生命周期
之前servlet的生命周期
构造方法 -- init -- service -- destroy
那么spring创建对象的生命周期呢?
Spring中是没有init、service和destroy的,但是我们可以指定某个方法在创建完对象之后执行,某个方法在最后销毁的时候执行.
public void init(){
System.out.println("init--------");
}
public void destroy(){
System.out.println("destroy----------");
}
public UserService() {
System.out.println("service构造方法");
}
<bean name="userDao" class="com.tledu.zrz.dao.impl.UserDaoImpl" >
</bean>
<!--
init-method : 用于设置初始化的方法
destory-method : 用于设置销毁资源的方法
-->
<bean id="userService" class="com.tledu.zrz.service.UserService"
autowire="byName" init-method="init" destroy-method="destroy" >
</bean>
Destroy之所以会执行,是因为我们默认创建对象的时候是单例模式
这个时候对象的生命周期会和Spring容器的生命周期绑定到一起,所以当我们销毁Spring容器的时候,会把所有的对象销毁,并自动调用destroy方法
但是如果我们把scope设置为prototype的时候,对象的生命周期就不会再和Spring容器绑定,销毁Spring容器的时候也就不会再执行该对象的destroy方法
比如
<bean name="userDao" class="com.tledu.zrz.dao.impl.UserDaoImpl" >
</bean>
<!--
init-method : 用于设置初始化的方法
destory-method : 用于设置销毁资源的方法
-->
<bean id="userService" class="com.tledu.zrz.service.UserService" scope="prototype"
autowire="byName" init-method="init" destroy-method="destroy" >
</bean>
注意:scope为prototype类型时,我们容器只负责实例的创建,创建之后的生命周期由调用者负责。
迟加载
Spring容器默认是在执行
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
进行解析的时候创建对象并调用init,
如果我们不想让某个类在解析的时候就创建对象,而是用到的时候在创建对象的话,就需要设置迟加载
比如想要对userService迟加载可以这样设置
1.相关类
public UserDaoImpl(){
System.out.println("Dao构造方法");
}
public UserService() {
System.out.println("service构造方法");
}
2.配置
<bean name="userDao" class="com.tledu.zrz.dao.impl.UserDaoImpl" >
<bean id="userService" class="com.tledu.zrz.service.UserService" scope="prototype"
autowire="byName" init-method="init" destroy-method="destroy" lazy-init="true" >
</bean>
3.测试
@Test
public void testAdd() {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext(
"beans.xml");
}
这时,不使用getBean方法就会报错,因为迟加载
通过结果可以看出,UserService的对象没有创建,那么什么时候创建呢?
UserService userService = (UserService) applicationContext.getBean("userService");
当调用getBean()的时候创建
或者是使用到这个对象的时候,比如我们获取userService对象,但是需要将userDao对象注入到userService中,那么这时候就算没有通过getBean(“userDao”) 而是通过getBean(“userService”) 也会创建userDao对象,因为在UserService中用到userDao了
为了使用方便,Spring还提出了default-lazy-init="true"
比如我们通过xml创建了10个对象,这10个对象都需要迟加载,那么每个bean标签中都设置lazr-init是比较麻烦的
于是我们可以在beans标签中添加default-lazy-init="true" 对所有的bean进行迟加载
default-lazy-init 和 lazy-init 可以同时存在,比如 10个对象中 只有一个不需要迟加载,那么可以使用 default-lazy-init = true 全部设置迟加载,然后再去指定的bean中添加 lazy-init=false 就可以
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd" default-lazy-init="true" >
IOC注解
XML和注解的区别
XML配置
优点有:
-
XML配置方式进一步降低了耦合,使得应用更加容易扩展,即使对配置文件进一步修改也不需要工程进行修改和重新编译。
-
在处理大的业务量的时候,用XML配置应该更加好一些。因为XML更加清晰的表明了各个对象之间的关系,各个业务类之间的调用。同时spring的相关配置也能一目了然。
缺点有:
配置文件读取和解析需要花费一定的时间,配置文件过多的时候难以管理,无法对配置的正确性进行校验,增加了测试难度。
annotation配置
优点有:
-
在class文件中,可以降低维护成本,annotation的配置机制很明显简单
-
不需要第三方的解析工具,利用java反射技术就可以完成任务
-
编辑期可以验证正确性,查错变得容易
-
提高开发效率
缺点有:
-
如果需要对于annotation进行修改,那么要重新编译整个工程
-
业务类之间的关系不如XML配置那样容易把握。
-
如果在程序中annotation比较多,直接影响代码质量,对于代码的简洁度有一定的影响