IOC/DI概述
依赖对象与被依赖对象
如:
class A{
}
class B{
A a = new A();
}
- 这里,B中有一个A对象,当类A被删除,B就不能正常运行,所以A,B之间具有依赖关系(即B依赖于A),可以说:当一个类B中引用了另一个类A的对象,则B依赖于A
- 在这个例子中,B称为被依赖对象,A称为依赖对象
IOC
Inverse of Controll(控制反转):
- 控制即控制了类的实例化及属性的赋值(IOC容器控制了对象的创建),
- 所谓反转,就是将类的实例化及属性的赋值交由第三方容器(如spring、guice)(通过new关键字主动创建依赖对象为正转,反转则是由ioc容器找到依赖对象并将它注入到被依赖对象中,被依赖对象是被动的接受依赖对象)
DI
Dependence Inject(依赖注入):实现IOC的手段
IOC和DI虽然本质上都是为了解耦,但IOC和DI不完全相同,IOC是一种面向对象的编程思想,目的是解耦;而DI是实现IOC的一种手段,还有其他手段如依赖查找
父子容器(SpringMVC的配置原理)
子容器的Bean可以引用父容器中的Bean,父容器的Bean不能引用子容器中的Bean,理解起来有点类似类的继承,子类对象可以调用父类中的方法,但父类对象不能调用子类重写的方法
代码演示
类一:
public class One {
private Two two;
public Two getTwo() {
return two;
}
public void setTwo(Two two) {
this.two = two;
}
}
类二:
public class Two(){}
One依赖于Two
容器一:
<?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">
<bean id="one" class="com.container.One">
<property name="two" ref="two"/>
</bean>
</beans>
容器二:
<?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">
<bean id="two" class="com.container.Two"/>
</beans>
测试:
@Test
public void test1(){
GenericXmlApplicationContext context2 = new GenericXmlApplicationContext();
context2.load("two.xml");
context2.refresh();
GenericXmlApplicationContext context1 = new GenericXmlApplicationContext();
context1.load("one.xml");
context1.setParent(context2);//将context2设为context1的父容器
context1.refresh();
One one = context1.getBean("one",One.class);
System.out.println(one.getTwo());
}
context1中的bean引用了context2中的bean,这里将context2设为context1的父容器,context1可以访问到context2中
Test
public void test2(){
GenericXmlApplicationContext context1 = new GenericXmlApplicationContext();
context1.load("one.xml");
context1.refresh();
GenericXmlApplicationContext context2 = new GenericXmlApplicationContext();
context2.load("two.xml");
context2.setParent(context1);
context2.refresh();
One one = context1.getBean("one",One.class);
System.out.println(one.getTwo());
}
这里将context1设置为context2的父容器,运行时会报错:one.xml中不存在bean:two
创建实例
实例名称
- id:id为bean的唯一标识
- name+class:可以使用逗号取多个名字(一个名字只能对应一个bean,但一个bean可以有多个名字)
- 匿名:默认的名字为—类全名#0,原型bean末尾数字递增;使用注解未指定名称时默认名称是类首字母小写后的类名
作用域
scope属性具有两个值:singleton和prototype
- singleton:单例对象,每一个bean只对应一个实例对象,在配置文件加载时实例化
- prototype:原型对象,每一个bean对应多个实例对象,在getBean被调用时实例化
depends-on、lazy-init
- depands-on:容器中的bean本是互不相干的,他们的创建没有先后顺序,但当某一个bean依赖于另一个bean时,需要控制他们实例化的顺序,就需要用到depends-on
- lazy-init:也是用来控制实例化时间,将lazy-init设为true则该bean将延迟加载,即当getBean的时候才会实例化,有“懒加载”的意味
init-method/destory-method
在bean初始化和销毁的时候的回调方法,应用场景少
destory-method一个常用场景是对于数据源的bean销毁时关闭连接
parent、abstract
在多个bean具有相同的内容时可以使用一个公共bean,并将abstract设为true,其他标签的parent指向该公共bean即可,可以简化开发 ,提高可维护性
注解
- @Component:一般组件,用于修饰普通类
- @Service:用于修饰业务逻辑层
- @Respository:用于修饰dao层
- @Controller:用于修饰控制器
- @Scope:同xml中的scope属性
注入属性
xml写法一
xml写法二(命名空间)
- p:用于为bean的属性赋值
<bean id="demo2" class="com.propertyInject.Demo2"/>
<bean id="demo1" class="com.propertyInject.Demo1" p:id="1" p:name="张三" p:demo2-ref="demo2"/>
id,name,demo2为Demo1的属性
<bean id="demo2" class="com.propertyInject.Demo2" p:names="1,2,3"/>
对于数组,直接用逗号隔开即可
- c:用于为bean的构造方法传参数
<bean id="demo11" class="com.propertyInject.Demo1" c:id="1" c:name="张三" c:demo2-ref="demo2"/>
- util:用于单独定义集合,映射,属性
<bean id="demo22" class="com.propertyInject.Demo2" p:names="1,2,3" p:ages-ref="ages" p:codes-ref=""></bean>
<util:list id="ages">
<value>10</value>
<value>20</value>
<value>30</value>
</util:list>
<util:map id="codes">
<entry key="code1" value="1"/>
</util:map>
注解写法
- @Value:注入简单类型,直接赋值;并不适合直接写死赋值,而是引用外部属性文件来获取值
xml配置方法:使用
<context:property-placeholder location="<!--properties文件路径-->"
配置属性文件,然后通过${}的方式在注解中获取值
注解配置方法:使用@PropertySource注解指定属性文件路径,然后在类中使用@Autowired private Enviroment env;使用env.getProperty(“name”)来获取属性文件的值
- @Autowired:先找类型,如果在容器中该类型只有一个bean,则将该bean注入;如果在容器中该类型有多个bean,则根据该属性的名称来找到相同名称的bean,没有则报错
- @Resource:无视类型,通过属性名在容器中找到相同名称的bean然后注入,属性不匹配或找不到则报错
- @Qualifier:配合@Autowired使用,当同类型有多个bean时,可以不修改属性名,而是通过该注释来指定需要注入的bean