Spring framework的第一大部分就是core container 核心容器,用于管理对象,其中有个IoC容器。
我们先来了解一下什么是IoC:
代码现状是:在业务层实现类中,我们需要new出数据层的一个具体的实现类对象才能实现数据层对应的方法。但当我们需要更换成实现了同一个数据层接口的另一个实现类时,因为new出来实现类不一样了,所以后面的代码肯定也要改。就是下面这种情况。
解决办法:在使用对象的时候,在程序中不要主动用new创造对象,转换为由外部提供对象。
这就是IoC(Inversion of Control)控制反转:就是把对象的创建控制权由程序转移到了外部。目的是为了解耦。
Spring提供了一个容器,IoC容器来充当IoC思想中的“外部” 。IoC容器负责对象的创建,初始化等一系列工作,被创建或被管理的对象在IoC容器中统称为bean。
这时还有一个问题,上面我们仅仅是完成了在外部创建对象的工作,当我们运行service时,如果IoC容器只提供给我们service的对象是不能到达效果的,因为service层的运行是需要依靠dao层的,所以IoC容器应该把这俩个对象都传给我们,并建立依赖。
其实这个建立依赖的工作,IoC容器是可以帮我们做的。如果我们需要的多个对象,IoC容器中都有,IoC容器就是帮我们建立依赖并传给我们,这个就叫做依赖注入DI。
DI(Dependency Injection)依赖注入:在容器中建立起多个bean之间的依赖关系的过程。
下面让我们开始使用配置文件来运行Spring:
第一步,先导入spring对应的依赖包
org.springframework
spring-context
5.2.10.RELEASE
junit
junit
4.13.2
test
第二步,创建需要的配置文件,这个文件在导完上面的依赖包才会有。
给该配置文件起名叫applicationContext.xml
下面我们就可以创造我们需要的bean了:用bean标签创建
id属性给bean起名字 class属性给bean定义类型
一个bean的id属性只能有一个且不能重复,但name属性可以给该bean起多个别名,不能重复
name属性与id属性具有相同功能,都可以被用来获取该bean 。name中的多个别名之间可以用逗号,分号或者空格分隔。name属性不需要时可以省略。
到这我们完成了dao层和service层对象的创建,我们还需要对这俩个对象建立依赖:因为是service层依赖dao层,所以创建依赖的过程应写在service的bean中。
dao层代码:
public class bookDaoImpl implements bookDao {
public bookDaoImpl() {
System.out.println("bookDaoImpl被new");
}
@Override
public void save() {
System.out.println("bookDao....");
}
}
我们需要先在service层代码中声明对应的set方法。
public class bookServiceImpl implements bookService{
//5.删除业务层中使用new方式创建的对象
//bookDao bookDao=new bookDaoImpl();
bookDao bookDao;
@Override
public void save() {
bookDao.save();
System.out.println("bookService....");
}
public void setBookDao(bookDao bookDao) {
this.bookDao = bookDao;
}
}
然后在配置文件中添加下面的标签
property标签是配置当前bean的属性; name属性为bookService类中的bookDao属性,ref为为bookDaoImpl配置的bean的id值。
最后我们就可以在main方法中获取我们的bean并执行其中的save方法了
public class beanConstruction {
public static void main(String[] args) {
//3.获取IoC容器
ApplicationContext act=new ClassPathXmlApplicationContext("applicationContext.xml");
//4.获取bean
bookDao bookDao = (bookDao) act.getBean("bookDao");
bookService bookService = (bookService) act.getBean("bookService");
bookService.save();
}
获取IoC容器方法中的参数为我们前面写的Spring配置文件的名。
getBean()方法的参数为配置文件中bean标签的id属性值或者name属性值。另外因为该方法的返回值为Object类型,所以我们需要强转一下类型。
下面让我们来了解一下Spring是怎么创建对象的:Spring创建对象有3种方式
第一种(默认):调用该对象无参的构造方法。通过上面的例子,就可以反映出Spring是通过无参的构造方法创建对象的。
第二种:使用静态工厂实例化bean:
先创建一个静态工厂,通过一个静态方法返回我们需要的对象。
package org.example.factory;
import org.example.dao.bookDao;
import org.example.dao.impl.bookDaoImpl;
public class bookDaoFactory {
public static bookDao getBookDao(){
return new bookDaoImpl();
}
}
配置文件中的bean标签就应该这样写:
如果不写factory-method属性 该bean创建的是factory工厂的对象,但我们需要的是工厂中的方法所返回的对象,所以我们需要用factory-method指明运用工厂中的哪个方法来返回对象
第三种:使用实例化工厂:注意该类中返回所需对象的方法不是静态方法。
package org.example.factory;
import org.example.dao.bookDao;
import org.example.dao.impl.bookDaoImpl;
public class bookDaoFactory2 {
public bookDao getBookDao(){
return new bookDaoImpl();
}
}
因为该工厂不是静态工厂,所以要先创建该工厂的bean
factory-bean 属性是工厂实例bean 然后调用该工厂的factory-method方法。
因为这种方式我们需要创建工厂bean,且工厂bean仅仅是配合其他bean使用的,没别的作用了,所以后续对该方式进行了改良:
package org.example.factory;
import org.example.dao.bookDao;
import org.example.dao.impl.bookDaoImpl;
import org.springframework.beans.factory.FactoryBean;
public class bookDaoFactoryBean implements FactoryBean {
//代替原实例工厂中创建对象的方法
@Override
public bookDao getObject() throws Exception {
return new bookDaoImpl();
}
@Override
public Class> getObjectType() {
return bookDao.class;
}
//该方法用于改变由该实例工厂创建出来的对象是否为单例
//返回值为true时为单例,为false时不是单例
//该方法一般不用重写
@Override
public boolean isSingleton() {
return true;
}
}
其中的方法都是实现了FactoryBean接口后重写的方法。
配置文件中的写法: