01从BeanFactory入门Spring框架
传统的开发模式中,我们在业务代码中,需要使用一个类的实例对象时,主要通过new关键字来创建这个类的实例。当业务系统中,需要在不同的业务代码中多次使用同一个类的对象时。我们就要在这些不同的业务代码中多次去创建(new)这个类的实例对象。这种做法的缺点有:代码耦合度高、重复编写相同的代码,导致代码冗余度高。
而Spring框架,就帮助我们解决了这个问题。Spring内部实现了实例工厂(BeanFactory),我们将需要多次复用的类,通过配置文件告诉Spring框架。Spring框架会在内部通过实例工厂,将我们在配置文件中定义的类进行实例化。后期,我们再在业务代码中需要使用这个类的实例对象时,直接通过Spring框架来获取即可。例如,下图所示的流程:

其中,我们将创建实例对象的能力,由自己创建(new),转换为交给Spring来创建。将类的创建权由我们本身,转换为交给Spring框架的过程,就是控制反转(IOC)思想的体现。
Spring中使用BeanFactory获取类的实例对象
- 导入Spring的jar包或Maven坐标
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.7</version>
</dependency>
依赖了 spring-context之后,我们可以看到它里面包含了 core,beans,expression。这些正是 spring 框架架构中基础容器所包含的内容。

- 编写需要交给Spring管理的测试类
public interface UserService {
void show();
}
public class UserServiceImpl implements UserService {
@Override
public void show() {
System.out.println("UserServiceImpl.show()");
}
}
- 创建配置文件,将测试实体类的信息配置到配置文件中
在resouce目录下创建一个xml文件,用于存放配置项。我取名为applicationContext.xml,如果你的pom文件中,已经成功依赖了spring-cotext。那么在IDEA中可以直接创建,供Spring使用的配置文件!

<?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">
<!--
id:类在spring中的唯一标志
class:类的全限定包名,spring的实例工厂就是根据这个全限定名,通过反射生成类的实例对象
-->
<bean id="userService" class="cn.zlprime.service.impl.UserServiceImpl"></bean>
</beans>
- 编写测试类,测试通过Spring的BeanFactory获取类的实例对象
public class BeanFactoryTest {
public static void main(String[] args) {
// 1. 创建Spring的BeanFactory
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
// 2. 创建一个XmlBeanDefinitionReader,将刚才创建的工厂类作为参数传递给读取器读
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
// 3. 取配置文件并加载到BeanFactory中,从类路径下加载配置文件
reader.loadBeanDefinitions("classpath:applicationContext.xml");
// 4. 从BeanFactory中获取Bean
UserService userService = (UserService) factory.getBean("userService");
// 5. 调用Bean的方法
userService.show();
}
}
通过以上四步,我们就实现了从spring的BeanFactory中获取实例对象。
在常见的MVC三层架构中,service层通常需要调用dao层中的方法进行持久化。例如,我们就可以在UserService对象中调用UserDao对象的save方法,进行保存操作。既然,我们可以将UserService交给spring进行管理,那么同样也可以将UserDao交给spring进行管理。但是,UserService又要依赖UserDao的某些方法,来完成业务。之前,我们会在UserService的业务代码中创建一个UserDao的对象,然后调用这个对象的方法。
现在,既然将UserDao和UserService都交给了spring进行管理。那么,我们就不需要再在UserService中手动创建UserDao的对象了。我们可以将多个类之间的依赖关系交给spring来管理,这就是依赖注入(DI)的思想
- 首先创建UserDao进行测试
public interface UserDao {
void show();
}
public class UserDaoImpl implements UserDao {
@Override
public void show() {
System.out.println("UserDaoImpl.show()");
}
}
- 修改UserService
在UserServie中,添加一个UserDao类型的引用成员变量,并提供setter方法(这很重要)
public class UserServiceImpl implements UserService {
//1. 声明一个UserDao类型的属性
private UserDao userDao;
@Override
public void show() {
System.out.println("UserServiceImpl.show()");
//调用UserDao的show方法
userDao.show();
}
//2. UserDao的set方法
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
}
- 在配置文件中,添加UserDao的配置文件,将UserDao交给Spring管理。并配置UserService和UserDao的依赖关系
<?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">
<!--
id:类在spring中的唯一标志
class:类的全限定包名,spring的实例工厂就是根据这个全限定名,通过反射生成类的实例对象
-->
<bean id="userService" class="cn.zlprime.service.impl.UserServiceImpl">
<!--配置依赖注入-->
<property name="userDao" ref="userDao"></property>
</bean>
<!--配置userDao-->
<bean id="userDao" class="cn.zlprime.dao.impl.UserDaoImpl"></bean>
</beans>
通过上面的配置文件,我们就将UserDao的实例对象注入到了UserService中。 标签的两个属性,name和ref,它们的属性值虽然都是userDao,但是含义完全不同。spring完成UserDao的依赖注入,需要调用UserService提供的set方法。而name属性,配置的就是调用哪个set方法。只是去掉了set前缀(setUserDao),并将首字母进行了小写。如果UserService中成员变量UserDao的set方法,方法名为setDao,那么name的属性值就应该是dao。而ref属性,则用于声明注入的是哪个类,如果这个类本身就是spring管理的,那么我们只要填写这个类在spring中的id即可。例如:userDao
- 编写测试代码,查看依赖注入是否成功
public class BeanFactoryTest {
public static void main(String[] args) {
// 1. 创建Spring的BeanFactory
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
// 2. 创建一个XmlBeanDefinitionReader,读取配置文件并加载到BeanFactory中
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
// 3. 从类路径下加载配置文件
reader.loadBeanDefinitions("classpath:applicationContext.xml");
// 4. 从BeanFactory中获取Bean
UserService userService = (UserService) factory.getBean("userService");
// 5. 调用Bean的方法
userService.show();
}
}
//输出结果:
//UserServiceImpl.show()
//UserDaoImpl.show()
可以看到,即执行了userService的show方法,同时也调用userDao的show方法。说明依赖注入成功
控制反转(IOC)
IOC 是 Inversion of Control 英文的简称,翻译过来就是 控制反转 。它所强调的是,将 bean 对象的创建权和控制权由业务代码本身反转给第三方。这样在业务中调用其它的对象,从第三方获取就行。实现了调用者和被调用者的解耦。IOC的核心思想是将 bean 的控制权交给第三方:使用工厂设计模式,BeanFactory 来充当第三方,并通过配置文件配置 Bean 的基本信息,BeanFactory 根据配置文件来生产 Bean 实例
依赖注入(DI)
在传统的 MVC 架构开发中,Servic 层的 UserServiceImpl 运行需要使用 Dao 层的 UserDao。在控制反转思想中,我们已经将对象的创建交给了第三方。 第三方同时管理了 UserSericeImpl 和 UserDao。因此,我们也可以在第三方中将 UserDao 设置给 UserServiceImpl。其中,将 UserDao 对象设置给 UserServiceImpl 的过程就称为“注入”。由于 UserServiceImpl 需要使用 UserDao 才能正常运行,即前者的正常运行依赖于后者。所以,第三方将 UserDao 设置给 UserServiceImpl 的功能,我们称为依赖注入(即 Dpendency Injection)。这里注入的不一定是对象,也可以是普通参数。