IOC(控制反转)
控制反转(Inversion of Control,英文缩写为IoC)
把对象的创建、初始化、销毁等工作交给spring容器来做,由spring容器控制对象的生命周期。
比如我们依赖的service实例,直接获取注入过来的对象就可以使用该对象的变量方法等,而不需要先自己创建对象
spring创建对象方式
构造函数(用的最多)
在配置文件中进入如下的配置:
使用无参的构造函数创建对象
在客户端
HelloWorld类本身:
在控制台打印出了”create object”
可以看出:spring内部默认是调用了HelloWorld这个类的默认的构造函数创建对象
静态工厂
利用工厂类的静态方法获得对象。
说明:给工厂类创建了一个对象helloWorldFactory,再利用工厂对象调用工厂方法。
对象的创建时机
执行步骤为1,3,2
以上两种情况是默认值,当spring容器启动的时候创建对象
懒加载
在bean有这样一个属性
Default 相当于false 在spring容器启动的时候,创建对象
True 在context.getBean时创建对象
False 在spring容器启动的时候创建对象
注意:(lazy-init 设置只对scop属性为singleton的bean起作用;scope=“pototype“时,不管lazy-init值都是在调用的时候实例化)
不进行懒加载的bean1,引用了一个延迟加载的bean2,bean1在容器启动时被实例化,而bean2由于被bean1引用,所以也被实例化,这种情况也符合延迟加载的bean在第一次调用时才被实例化的规则。
如果多个bean都不想在IOC容器启动的时候就加载,可以
< beans default-lazy-init ="true" > < /beans>在里面配
意义:
如果把lazy-init设置为true,则当spring容器启动的时候,检测不到任何错误,这样会存在很大的安全性隐患,所以一般情况下应该设置lazy-init为default/false。但是如果一个bean中有一个属性,该属性含有大量的数据,这个时候不希望该bean过早的停留在内存中。
这个时候需要用到lazy-init为true。
单例多例
默认情况(scope=singleton)
在默认情况下放入到spring中的bean是单例的
将来service层和dao层所有的类将放入到spring容器中,所以默认情况下这两个层的类的实例都是单例的,所以不能把数据声明到属性中。如果声明在属性中,将会成为共享的。
Scope为prototype
这时为不同的对象。说明指定prototype就变成了多例了。
创建时机和scope的结合
Scope为prototype,lazy-init为true:在context.getBean时创建对象,
Scopse为prototype,lazy-init为false:
在context.getBean时创建对象,lazy-init为false失效
当scpose为prototype时,始终在context.getBean时创建对象,实例在用的时候才实例化。
说明多例的对象要在对象使用时创建。
Scopse为singleton(spring中默认为单例):
是默认情况,在spring容器启动的时候创建实例
对象的Init和destroy方法
说明:
- init方法是由spring内部执行的
- 只有当spring容器关闭以后才能执行destroy方法,spring容器一般情况下是不会关闭的。只有当web容器销毁掉的时候才可能关闭掉,所以只要一个对象在spring容器中,在spring容器关闭之前,会一直保留。
- 如果一个bean的配置是scope为”prototype”,则spring容器不负责销毁。
Spring容器做的事情
类扫描的注解
步骤
导入context的命名空间
xmlns:context="http://www.springframework.org/schema/context"
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd">
这里去掉Controller的扫描是要把Controller层交给springmvc容器负责
<context:component-scan base-package="com.xgss"> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller" /> </context:component-scan> |
springmvc的配置文件会有
<!-- 自动扫描且只扫描@Controller --> <context:component-scan base-package="com.xgss.ssm.controller" /> |
bean标签及内容就不用写了
说明:在指定的包及子包中扫描
@Service用于标注业务层组件、
@Controller用于标注控制层组件(如struts中的action)、
@Repository用于标注数据访问组件,即DAO组件。
而@Component泛指组件,当组件不好归类的时候,我们可以使用这个注解进行标注。
这些注解都是定义的,定义到spring容器中。
流程分析
- 启动spring容器
- Spring容器解析类扫描的注解解析器,在base-package指定的包及子包中查找所有的类
- 查看哪些类上面是否含有@Component注解
- 如果该注解的value的属性的值为空,则把类名的第一个字母变成小写,作为id值,放入到spring容器中
- 如果该注解的value的属性的值不为空,则用value的属性的值作为id值,放入到spring容器中
- 再次查找在spring容器中的类的所有的属性,按照@Resource的规则给属性赋值
说明
使用了类扫描机制的做法,配置文件中的配置很简单了,但是效率越来越低。