IOC概念:
控制反转:将对象创建和对象之间的调用从程序员手上交给Spring IOC容器进行管理
目的是为了降低程序的耦合度。
何谓耦合度?
按我自己的理解,耦合度高的结果是:维护成本高
例如一个场景中,耦合度高的代码在进行代码修改的时候,我需要在所有使用到这个类的地方全部修改。表现出,一处修改,全部修改。这显然是一个灾难
那耦合度是可以为0吗?
答案是否定的。如果一个程序完全没有耦合度,那他们之间就没有合作关系了。也就是说:类之间失去了协调工作的能力
但是我们可以把他降低到最低限度,这个降低的过程称为:解耦
所以我们的目标是:高内聚,低耦合
高内聚是指:在符合设计模式的单一责任原则的基础上,模块只完成自己的任务,不干预其他的模块。
(这里会引出很多分支概念,如单一责任原则和设计模式,这里就不展开了)
IOC容器可以存放多个Bean,而Bean的注入又有两种实现方法
实现:
- XML
- 注解
应用场景
当一个在一个类中的一个方法,需要调用到另外一个对象中的方法。传统的方法是在方法内部new 一个对象出来,然后通过这个对象调用目的方法。而这种耦合度过于高。所以才需要IOC来降低程序的耦合度。
如代码段
class Book{
public getBook(){
...
}
}
class BookStore{
public void add(){
Book book= new Book();
book.getBook();
...
}
}
工厂模式
目的:为了降低传统模式的耦合度
加入一个工厂类
class BookFactory{
public static Book getBook(){
return new Book();
}
}
class BookStore{
public void add(){
Book book= new Book();
BookFactory.getBook();
...
}
}
//反射创建对象
class BookFactory{
public static Book getBook() throws ClassNotFoundException, IllegalAccessException, InstantiationException {
String className="Day6.Bean.Book";
Class myClass=Class.forName(className);
Book o = (Book)myClass.newInstance();
return o;
}
}
降低了Book与BookStore之间的耦合度。但是耦合度就转移到工厂上了。
Spring实现IOC容器的方式:
1. ApplicationContext
2. BeanFactory(不常用)
两个都能实现加载配置文件。
但是BeanFactory一般是用在Spring内部,开发人员一般使用ApplicationContext。
ApplicationContext是BeanFactory的一个子接口,拥有更多的功能
BeanFactory在执行
BeanFactory context=new ClassPathXmlApplicationContext("applicationContext.xml");
的时候不会创建对象,而是在getBean的时候才会获取对象(懒加载)
ApplicationContext则会在
ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");
的时候创建对象(饿汉式)
Bean管理操作
Bean管理操作指的是两个,一个是Spring创建对象,一个是Spring注入属性
而实现Bean管理操作的方式有两种,一个是基于XML配置文件方式实现,一个是基于注解方式实现
**
本文先说基于XML配置文件下的Bean管理操作:
在中有很多属性,例如class,id
这两个属性是bean中很重要的属性。
本文先只说这两个属性
这里提一下:name属性
name属性的用法与id属性基本相同。
但是name能加特殊符号,id则不能
name属性的创立是为了struts1框架,现在几乎不用了
创建对象:
<bean id="book" class="Day6.Bean.Book">
<property name="name" value="congcongcong"/>
</bean>
其中,class表示指向这个创建对象的类路径,id表示这个类的id,以方便后续getBean的时候拿到对象就是根据ID去拿到的。注意:这里默认使用无参构造,所以如果类中没有无参构造,没有用constructor,会报错。这里是一个易错点
主函数:
public class Main {
public static void main(String[] args) {
ApplicationContext context=new ClassPathXmlApplicationContext("Note.xml");
Book book = context.getBean("book", Book.class);
System.out.println(book);
book.add();
}
}
运行截图
同
通过这个例子可以知道,我们通过加载配置文件去创建对象,把创建对象的控制权反转了,不再是通过修改源代码来控制创建对象,而是通过修改配置文件去创建对象。
示例中并没有出现new
DI(依赖注入(dependency injection)):
set方法注入属性:
通过上述的例子也可知道,通过
<property name="name" value="congcongcong"/>
就能注入名字为name的属性,值为
而这个操作的前提是:
- 在对应路径"Day6.Bean.Book"类中必须要有一个setName方法。
- 在对应路径的8"Day6.Bean.Book"类中必须要有无参构造的方法。
原因
- 因为setProperty在set后的属性名才可被识别为一个Bean的属性
- 因为Spring底层默认使用无参构造方法创建对象,所以只有创建对象之后才能用对其注入,但是也不一定,后续有能够使Springg使用有参构造方法创建对象的方法。
否则注入失败。
有参构造方法注入:
<bean id="book" class="Day6.Bean.Book">
<constructor-arg name="name" value="congcongcong"/>
</bean>
总结:
- 使用set方法注入值使用property
- 使用有参构造函数注入使用constructor-arg
- 有参构造和set注入不能同时使用