1.IoC的概念
- IoC控制反转(IoC,Inversion of Control),
是一个概念,是一种思想。控制反转就是对对象控制权的转移,从程序代码本身反转到了外部容器。把对象的创建、初始化、销毁等工作交给spring容器来做。由spring容器控制对象的生命周期。 - DI依赖注入:Dependency Injection。
依赖注入 DI 是指程序运行过程中,若需要调用另一个对象协助时,无须在代码中创建被调用者,而是依赖于外部容器,由外部容器创建后传递给程序。依赖注入是目前最优秀的解耦方式。依赖注入让Spring的Bean之间以配置文件的方式组织在一起,而不是以硬编码的方式耦合在一起的。 - IoC与DI的关系
IoC是一个概念,是一种思想,其实现方式多种多样。当前比较流行的实现方式之一是DI。
SpringIoC 类似于 包子铺, 对象就是包子
IoC:控制反转,本质就是将对象new的过程交给了Spring容器去处理。
2.IoC基于XML配置的实现方式
2.1 基本实现步骤
演示第一个SpringIoC案例
2.1.1 创建一个普通的Java项目
2.1.2 导入相关的Spring依赖
将我们需要使用到的相关的jar拷贝到lib目录下,选中jar包点击右键,Build Path->Add to Build Path,将jar包添加到Referenced Libraries下面。
2.1.3 创建Spring配置文件
在src目录下创建一个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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
</beans>
2.1.4 添加对应的Java类型
Food.java
package com.zyz.spring;
public class Food {
public Food(String name) {
super();
this.name = name;
}
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Food [name=" + name + "]";
}
}
Person.java
package com.zyz.spring;
public class Person {
private String name;
private int age;
private Food food;
public Person(String name, int age, Food food) {
super();
this.name = name;
this.age = age;
this.food = food;
}
public Food getFood() {
return food;
}
public void setFood(Food food) {
this.food = food;
}
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;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + ", food=" + food + "]";
}
}
2.1.5 配置文件中注册Bean
将Person在配置文件中通过bean标签注册
引入外部文件
<import resource="application-service.xml"/>
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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<import resource="applicationContext-*.xml"/>
//通过构造器进行注入属性的值
<bean id="person" class="com.zyz.spring.Person">
<constructor-arg name="name" value="maxiaosan"></constructor-arg>
<constructor-arg name="age" value="18"></constructor-arg>
<constructor-arg name="food" ref="food"></constructor-arg>
</bean>
</beans>
applicationContext-service.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
//通过构造器进行注入属性的值
<bean id="food" class="com.zyz.spring.Food">
<constructor-arg name="name" value="jiaozi"></constructor-arg>
</bean>
</beans>
2.1.6 Java代码实现
package com.zyz.spring;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestGetBean {
public static void main(String[] args) {
// IoC的初始化操作
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
// 从容器中获取person对象
Person person = (Person)ctx.getBean("person");
System.out.println(person.toString());
System.out.println(person.getFood().toString());
System.out.println("========"+ToStringBuilder.reflectionToString(person,ToStringStyle.MULTI_LINE_STYLE));;
System.out.println("====------===="+ToStringBuilder.reflectionToString(ctx,ToStringStyle.MULTI_LINE_STYLE));;
}
}
输出
Person [name=zhangwuji, age=18, food=Food [name=jiaozi]]
========com.zyz.spring.Person@35d176f7[
name=zhangwuji
age=18
food=Food [name=jiaozi]
]
====------====org.springframework.context.support.ClassPathXmlApplicationContext@c4437c4[
configResources=<null>
validating=true
configLocations={applicationContext.xml}
setIdCalled=false
allowBeanDefinitionOverriding=<null>
allowCircularReferences=<null>
beanFactory=org.springframework.beans.factory.support.DefaultListableBeanFactory@3567135c: defining beans [food,person]; root of factory hierarchy
beanFactoryMonitor=java.lang.Object@a7e666
logger=org.apache.commons.logging.impl.Jdk14Logger@68bbe345
id=org.springframework.context.support.ClassPathXmlApplicationContext@c4437c4
displayName=org.springframework.context.support.ClassPathXmlApplicationContext@c4437c4
parent=<null>
environment=StandardEnvironment {activeProfiles=[], defaultProfiles=[default], propertySources=[MapPropertySource {name='systemProperties'}, SystemEnvironmentPropertySource {name='systemEnvironment'}]}
beanFactoryPostProcessors=[]
startupDate=1661869012782
active=true
closed=false
startupShutdownMonitor=java.lang.Object@7c29daf3
shutdownHook=<null>
resourcePatternResolver=org.springframework.core.io.support.PathMatchingResourcePatternResolver@9660f4e
lifecycleProcessor=org.springframework.context.support.DefaultLifecycleProcessor@5a8806ef
messageSource=Empty MessageSource
applicationEventMulticaster=org.springframework.context.event.SimpleApplicationEventMulticaster@5e853265
applicationListeners=[]
earlyApplicationListeners=[]
earlyApplicationEvents=<null>
classLoader=sun.misc.Launcher$AppClassLoader@73d16e93
protocolResolvers=[]
resourceCaches={}
]
getBean方法
我们从IoC容器中获取对应的对象是通过getBean方法实现的,默认是调用的无参构造方法。
上面使用的是构造函数的形式,下面使用属性注入的方式来给属性初始化赋值
<import resource="applicationContext-*.xml"/>
<!-- 对象属性 Spring 会调起 对象的 set方法 来 DI -->
<bean id="person" name="human,star" class="com.mashibing.spring.Person">
<property name="name"><value>马小六</value></property>
<property name="age" value="18" />
<property name="food" ref="food" />
</bean>
<!-- 如果配置文件有一个class多个bean,代码通过bean的class属性获取就会报错 -->
<bean id="p1" class="com.zyz.spring.Person"></bean>
<bean id="food" class="com.zyz.spring.Food"></bean>
<alias name="person" alias="person2"/>
getBean获取对象实例的方法:id;name;class;id+class混合
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
Person person1 = (Person)ctx.getBean("star");//通过name获取
Person person2 = (Person)ctx.getBean("person");//通过id获取
//Person person3 = (Person)ctx.getBean(Person.class);//通过class类获取
//通过class类获取 <bean id="p1" class="com.mashibing.spring.Person"></bean> 属性没有初始化 所以基本类型是默认值 引用类型是null
Person person4 = (Person)ctx.getBean("p1",Person.class);
System.out.println(ToStringBuilder.reflectionToString(person4));
组合的方式查找
Person person4 = (Person)ctx.getBean(“p1”,Person.class);
通过属性赋值,如果实体类没有set方法,会报错
Caused by: org.springframework.beans.NotWritablePropertyException: Invalid property 'name' of bean class [com.zyz.spring.Person]: Bean property 'name' is not writable or has an invalid setter method. Does the parameter type of the setter match the return type of the getter?
IoC对象工厂注入
静态工厂注入
通过工厂类的静态方法获取对应的实例对象
在配置文件中bean标签加工厂方法
<bean id="p1" class="com.zyz.spring.Person" factory-method="getInstance"></bean>
在实体类添加静态方法
public static Person getInstance() {
Person p = new Person("sun", 19, new Food("niurou"));
return p;
}
通过getBean方法生成的实体类对象就是上面静态方法new出的对象
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
Person person4 = (Person)ctx.getBean("p1");
Person person5 = (Person)ctx.getBean("p1");
System.out.println(person4.toString());
System.out.println(person4==person4);
生成的两个对象是同一个对象
动态工厂注入
通过工厂类的普通方法获取实例对象
配置文件
<!-- 注册动态工厂Bean -->
<bean class="com.zyz.spring.userDynamicFactory" id="userDynamicFactory" />
<!-- 从工厂对象获取User对象 -->
<bean id="user" factory-bean="userDynamicFactory" factory-method="getInstance"></bean>
userDynamicFactory.java
public class userDynamicFactory {
public Person getInstance(){Person p = new Person("sun2", 19, new Food("niurou"));
return p;}
}
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
Person person6= (Person)ctx.getBean("user");
System.out.println(person6.toString());