1、Spring IOC的基本概念
IOC(Inverse of Control)反转控制的概念,就是将原本在程序中手动创建对象的控制权,交由Spring框架管理。当某个Java对象(调用者)需要调用另一个Java对象(被调用者)时,在传统编程模式下,调用者通常会采用“new 被调用者”的代码方式来创建对象。这种方式会增加调用者与被调用者之间的耦合性,不利于后期代码的升级与维护。
当Spring框架出现后,对象的实例不再由调用者来创建,而是由Spring容器来创建。Spring容器会负责控制程序之间的关系,而不是由调用者的程序代码直接控制。这样,控制权由调用者转移到Spring容器,控制权发生了反转,这就是Spring的控制反转。
2、Spring IOC容器
实现控制反转的是Spring IOC容器,Spring IOC容器的设计主要是基于Bean Factory和ApplicationContext两个接口。
2.1、BeanFactory接口
BeanFactory由org.springframework.beans.factory.BeanFactory接口定义,它提供了完整的IOC服务支持,是一个管理Bean的工厂,主要负责初始化各种Bean。
BeanFactory接口最常用的实现类是org.springframework.beans.factory.xml.XMLBeanFactory,该类会根据XML配置文件中的定义来装配Bean。
BeanFactory实例创建代码如下:
@Test
public void demo(){
FileSystemResource file = new FileSystemResource("C:\\demo\\applicationContext.xml");
BeanFactory beanFactory = new XmlBeanFactory(file);
TestDao testDao = (TestDao) beanFactory.getBean("testDao");
testDao.sayHello();
}
由于使用BeanFactory实例加载Spring配置文件在实际开发中并不多见,所以对于该接口仅了解即可。
2.2、ApplicationContext接口
ApplicationContext是BeanFactory的子接口,也称为应用上下文,由org.springframework.context.ApplicationContext接口定义。ApplicationContext接口除了包含BeanFactory的所有功能以外,还添加了对国际化、资源访问、事件传播等内容的支持。
创建ApplicationContext接口实例通常有以下3中方法:
(1)通过ClassPathXmlApplicationContext创建
使用ClassPathXmlApplicationContext将从类路径目录(src根目录)中寻找指定的XML配置文件,代码示例:
@Test
public void demo(){
//初始化Spring容器ApplicationContext,加载配置文件
ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
TestDao testDao= (TestDao) applicationContext.getBean("testDao");
testDao.sayHello();
}
(2)通过FileSystemXmlApplicationContext创建
使用FileSystemXmlApplicationContext将从指定文件的绝对路径中寻找XML配置文件,找到并装载完成ApplicationContext的实例化工作,代码示例:
@Test
public void demo(){
ApplicationContext application = new FileSystemXmlApplicationContext("C:\\demo\\applicationContext.xml");
TestDao testDao = (TestDao) application.getBean("testDao");
testDao.sayHello();
}
(3)通过Web服务器实例化ApplicationContext容器
通过Web服务器实例化ApplicationContext容器,一般使用org.springframework.web.context.ContextLoaderListener的实现方式,需要添加Spring-web依赖,pom.xml配置如下:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
在web.xml中配置代码如下:
<context-param>
<!--加载src目录下的applicationContext.xml文件-->
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<!--指定以ContextLoaderListener方式启动Spring容器-->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
通过web.xml配置,web容器会自动加载context-param中的配置文件初始化ApplicationContext实例,然后就可以在web应用中通过WebApplicationContextUtils.getWebApplicationContext方法获取ApplicationContext的引用,Servlet中的代码如下:
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws javax.servlet.ServletException, IOException {
ApplicationContext application = WebApplicationContextUtils.getWebApplicationContext(request.getServletContext());
TestDao testDao = (TestDao) application.getBean("testDao");
testDao.sayHello();
}
3.依赖注入(基于xml方式)
DI (Dependency Injection)依赖注入的概念,在Spring中实现IOC容器的方法是依赖注入,依赖注入的作用是在使用Spring框架创建对象时动态地将其所依赖的对象(属性值)注入Bean组件中。
Spring框架的依赖注入通常有以下几种实现方式:
(1)使用构造方法注入
(2)使用属性的setter方法注入
(3)使用使用P名称空间注入
(4)使用SpEL注入
3.1、使用构造方法注入
创建Student类
package com.kude.entity;
public class Student {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
在applicationContext.xml文件中配置student实例:
<bean id="student" class="com.kude.entity.Student">
<constructor-arg name="name" value="石先生"></constructor-arg>
<constructor-arg name="age" value="21"></constructor-arg>
</bean>
在测试方法中代码:
public void demotwo(){
ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
Student student= (Student) applicationContext.getBean("student");
System.out.println(student);
}
3.2、使用属性的setter方法注入
<bean id="stu" class="com.kude.entity.Student">
<property name="name" value="张三">
</property>
<property name="age" value="20">
</property>
</bean>
测试类
public void demoThree(){
ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
Student student= (Student) applicationContext.getBean("stu");
System.out.println(student);
}
3.3 为list,set,map,注入值
Student类
package com.kude.entity;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class Student {
private String name;
private int age;
private Set<String> set;
private String [] str;
private List<String> list;
private Map<String,String> map;
public Student(){
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Set<String> getSet() {
return set;
}
public void setSet(Set<String> set) {
this.set = set;
}
public String[] getStr() {
return str;
}
public void setStr(String[] str) {
this.str = str;
}
public List<String> getList() {
return list;
}
public void setList(List<String> list) {
this.list = list;
}
public Map<String, String> getMap() {
return map;
}
public void setMap(Map<String, String> map) {
this.map = map;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", set=" + set +
", str=" + Arrays.toString(str) +
", list=" + list +
", map=" + map +
'}';
}
public Student(String name, int age, Set<String> set, String[] str, List<String> list, Map<String, String> map) {
this.name = name;
this.age = age;
this.set = set;
this.str = str;
this.list = list;
this.map = map;
}
}
applicationContext.xml文件配置
<bean id="stu" class="com.kude.entity.Student">
<property name="name" value="张三"></property>
<property name="age" value="20"></property>
<property name="str">
<list>
<value>123</value>
<value>321</value>
<value>121</value>
<value>125</value>
</list>
</property>
<property name="list">
<list>
<value>list1</value>
<value>list2</value>
<value>list3</value>
</list>
</property>
<!--name得值为属性名。 -->
<property name="set">
<set>
<value>one</value>
<value>two</value>
<value>three</value>
</set>
</property>
</bean>
测试类:
public void demoThree(){
ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
Student student= (Student) applicationContext.getBean("stu");
String [] st=student.getStr();
for(String s:st){
System.out.println(s);
}
List<String> list=student.getList();
for(String s:list){
System.out.println(s);
}
Set<String> set=student.getSet();
for(String s:set){
System.out.println(s);
}
Set<String> key=student.getMap().keySet();
for(String s:key){
System.out.println("键=:"+s+" 值=:"+student.getMap().get(s));
}
}
输出结果:
123
321
121
125
list1
list2
list3
one
two
three
键=:1 值=:11
键=:2 值=:22