四、Spring IoC
4、1什么是IoC
在传统的 Java 应用中,一个类想要调用另一个类中的属性或方法,通常会先在其代码中通过 new 的方式将后者的对象创建出来,然后才能实现属性或方法的调用。但在 Spring 应用中,Java 对象创建的控制权是掌握在 IoC 容器手里,开发者通过XML或注解的配置将Java对象的管理权交给IoC容器,对象的创建由Spring完成。当开发者需要用到对象时,可以直接从Spring中获取对象,不需要再自行创建。
IoC 带来的最大改变不是代码层面的,而是从思想层面上发生了“主从换位”的改变。原本开发者是主动的一方,它想要使用什么资源就会自己创建。但在 Spring 应用中,IoC 容器掌握着主动权,开发者则变成了被动的一方,等待 IoC 容器创建对象后使用。
在应用开发中,并不是所有对象都交给Spring创建,开发者经常将功能类的对象交给Spring去创建,这些类的对象创建后只需要调用功能,实现功能即可,但实体对象,因为每次创建存储的数据或代表的内容都不尽相同,所以实体类的对象还是使用常规方式(new)来实现对象创建。
4、2Spring加载Bean
DAO层
public interface IDemoDAO {public void show();
}public class DemoDAO implements IDemoDAO {@Overridepublic void show() {System.out.println("我是DAO方法");}
}
Service层
public interface IDemoService {public void show();
}public class DemoService implements IDemoService {private IDemoDAO demoDAO=new DemoDAO();@Overridepublic void show() {demoDAO.show();}
}
在applicationContext.xml中添加Bean配置
<!--bean标签声明要创建的类,id为唯一标识,class为类的全路径-->
<bean id="demoDAO" class="com.demo.DAO.Impl.DemoDAO"></bean>
<bean id="demoService" class="com.demo.service.Impl.DemoService"></bean>
获取IoC创建的对象
//创建ApplicationContext,通过实例化ClassPathXmlApplicationContext获取配置文件
ApplicationContext applicationContext= new ClassPathXmlApplicationContext("applicationContext.xml");
//getBeanDefinitionNames获取配置文件中所有加载的Bean
String[] str=applicationContext.getBeanDefinitionNames();
for (String s : str) {System.out.println(s);
}
//getBean通过Bean的id属性获取对象
IDemoService demoService1= (IDemoService) applicationContext.getBean("demoService");
demoService1.show();
4、3Spring注入对象
通过案例可以看到Spring通过配置,为我们创建了对象,但是目前我们遇到了问题,问题就是,我们在实现过程中,Service要引用DAO的对象进行功能实现,我们的DAO虽然交给了Spring去创建,但我们依旧需要手动创建,也就是说我们要想实现功能,在Service中就要依赖于DAO的对象实现功能,这样的形式,我们也可以交给Spring帮我们解决,这就是SpringIoC中重要的功能—依赖注入(DI)
在applicationContext.xml中进行修改
<bean id="demoDAO" class="com.demo.DAO.Impl.DemoDAO"></bean>
<bean id="demoService" class="com.demo.service.Impl.DemoService"><!--property标签实现依赖注入,name属性为调用类对象属性的set方法,ref属性为指向配置中的对象--><property name="demoDAO" ref="demoDAO"/>
</bean>
Service类修改
public class DemoService implements IDemoService {private IDemoDAO demoDAO;public void setDemoDAO(IDemoDAO demoDAO) {this.demoDAO = demoDAO;}@Overridepublic void show() {demoDAO.show();}
}
4、4使用注解实现IoC
通过配置文件实现SpringIoC,可以很好的分离代码和配置,有较高的解耦性,但操作较为繁杂,所以Spring又提供了以注解形式对IoC进行配置的方式,虽然解耦性降低,但代码实现较为轻便。
IoC核心注解:
- @Component 组件,通用的注解方式
- @Service 在业务逻辑层使用(service层)
- @Repository 在数据访问层使用(DAO层)
- @Controller 在控制层使用,控制器的声明(Controller)
- @Autowired:用来实现依赖注入,Autowired会通过对象类型进行注入,如在一个类中出现相同数据类型对象需要注入时,需要配合@Qualifier(对象名)进行组合注解进行注入
- @Resource:用来实现依赖注入,Resource会先根据名称查找要注入的对象,在根据对象类型查找注入对象,根据名称查找时,可以通过Resource的name属性查找
applicationContext.xml文件配置
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd"><!--使用context:component-scan标签对包进行扫描,base-package属性为要扫描的包,扫描时会讲包下面的所有注解进行扫描--><context:component-scan base-package="com.demo"/>
</beans>
DAO层
@Repository
public class DemoDAO implements IDemoDAO {@Overridepublic void show() {System.out.println("我是DAO方法");}
}
Service层
@Service
public class DemoService implements IDemoService {//@Autowired//@Qualifier("demoDAO")@Resourceprivate IDemoDAO demoDAO;/*public void setDemoDAO(IDemoDAO demoDAO) {this.demoDAO = demoDAO;}*/@Overridepublic void show() {demoDAO.show();}
}
获取IoC对象
//创建ApplicationContext,通过实例化ClassPathXmlApplicationContext获取配置文件
ApplicationContext applicationContext= new ClassPathXmlApplicationContext("applicationContext.xml");
//getBeanDefinitionNames获取配置文件中所有加载的Bean
String[] str=applicationContext.getBeanDefinitionNames();
for (String s : str) {System.out.println(s);
}
//getBean通过Bean的id属性获取对象
IDemoService demoService1= (IDemoService) applicationContext.getBean("demoService");
demoService1.show();
4、5Resource注解和Autowired注解的区别
@Autowired 和 @Resource 都是用来实现依赖注入的注解(在 Spring/Spring Boot 项目中),但二者却有着不同:
- 来源不同:@Autowired 来自 Spring 框架,而 @Resource 来自于Java
- 依赖查找的顺序不同:@Autowired 先根据类型再根据名称查询,而 @Resource 先根据名称再根据类型查询
- 支持的参数不同:@Autowired 只支持设置 1 个参数,而 @Resource 支持设置 7 个参数
- 依赖注入的用法支持不同:@Autowired 既支持构造方法注入,又支持属性注入和 Setter 注入,而 @Resource 只支持属性注入和 Setter 注入