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对应的依赖包
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.2.10.RELEASE</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.13.2</version> <scope>test</scope> </dependency>
第二步,创建需要的配置文件,这个文件在导完上面的依赖包才会有。
给该配置文件起名叫applicationContext.xml
下面我们就可以创造我们需要的bean了:用bean标签创建
<?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="bookDao" name="dao bookDao2" class="org.example.dao.impl.bookDaoImpl" scope="prototype"/> <bean id="bookService" class="org.example.service.impl.bookServiceImpl"/> </beans>
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; } }
然后在配置文件中添加下面的标签
<bean id="bookService" class="org.example.service.impl.bookServiceImpl"> <property name="bookDao" ref="bookDao"/> </bean>
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标签就应该这样写:
<bean id="bookMapper" class="org.example.factory.bookDaoFactory" factory-method="getBookDao"/>
如果不写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
<bean id="bookFactory" class="org.example.factory.bookDaoFactory2"/> <bean id="bookDao3" factory-method="getBookDao" factory-bean="bookFactory"/>
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<bookDao> { //代替原实例工厂中创建对象的方法 @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接口后重写的方法。
配置文件中的写法:
<bean id="bookDao4" class="org.example.factory.bookDaoFactoryBean"/>