我报名参加金石计划1期挑战——瓜分10万奖池,这是我的第1篇文章,点击查看活动详情”
IOC与DI
IOC:反转控制(inversion of control)的思想完全颠覆了应用程序组件获取资源的传统方式;反转了资源的获取方向——改由容器主动的将资源推送给需要的组件,开发人员不需要知道容器是如何创建对象的,只需要提供接收资源的方式即可,极大的降低了学习成本,提高了开发的效率。这种行为也称为查找的被动形式
DI:dependency injection是ioc的另一种表述形式;即组件以一些预先定义好的方式(例如:setter方法)接收来自于容器的资源注入。相对于ioc而言,这种表述更直接
结论:IOC就是一种反转控制的思想,而DI是对IOC的一种具体实现
IOC容器
spring的ioc容器就是ioc思想的一个落地产品的实现。ioc容器中管理的组件叫做bean。在创建bean之前,首先需要创建ioc容器。spring提供了ioc容器的两种实现方式
BeanFactory:这是IOC容器的基本实现,是spring内部使用的接口。面向spring本身,不提供给开发人员使用 ApplicationContext:BeanFactory的子接口,提供了更多高级的特性。面向spring的使用者,几乎所有的场合都使用ApplicationContext,而不是底层的BeanFactory
基于Xml文件来管理bean
依赖
<!--设置打包方式-->
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.1</version>
</dependency>
<!--junit测试-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
helloworld对象
public class HelloWorld {
public void sayHello(){
System.out.println("Hello,Spring");
}
}
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">
<!--ioc容器配置文件-->
<!--id是bean的唯一标识,class是bean对象所对应的类型(将helloworld这个对象交给ioc容器来管理)-->
<bean id="helloworld" class="com.sentiment.pojo.HelloWorld"></bean>
</beans>
测试类
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class SpringTest {
@Test
public void HelloWorldTest(){
//通过配置文件获取ioc容器
ClassPathXmlApplicationContext ioc = new ClassPathXmlApplicationContext("applicationContext.xml");
//从ioc中获取bean对象
HelloWorld bean = (HelloWorld) ioc.getBean("helloworld");
bean.sayHello();
}
}
获取bean的三种方式
- 根据bean的id获取
Student studentOne = (Student) ioc.getBean("studentOne");
- 根据bean的类型获取
Student studentOne = ioc.getBean(Student.class);
注意:根据类型获取bean时,要求Ioc容器中有且只有一个类型匹配的bean
若没有任何一个类型匹配的bean,此时抛出异常:NoSuchBeanDefinitionException
若有多个类型匹配的bean,此时抛出异常:NouniqueBeanDefinitionException
- 根据bean的id和类型获取
Student studentOne = ioc.getBean("studentOne", Student.class);
根据类型来获取bean时,在满足bean唯一性的前提下其实只是看:『对象instanceof指定的类型』的返回结果只要返回的是true就可以认定为和类型匹配,能够获取到。即通过bean的类型、bean所继承的类的类型、bean所实现的接口的类型都可以获取bean
扩展
若组件类实现了接口,可以根据接口获取bean,但若这个接口有多个实现类则无法获取即:若Student实现或继承了Persion类,则可以通过person获取student的bean
Person person = ioc.getBean(Person.class);
三种方式及扩展
public void testIoc(){
ClassPathXmlApplicationContext ioc = new ClassPathXmlApplicationContext("spring-ioc.xml");
//Student studentOne = (Student) ioc.getBean("studentOne");
//Student studentOne = ioc.getBean(Student.class);
//Student studentOne = ioc.getBean("studentOne", Student.class);
Person person = ioc.getBean(Person.class);
System.out.println(person);
}
依赖注入
setter注入
配置
- property:通过成员变量的set方法进行赋值
- name :设置需要赋值的属性名(和set方法有关)
- value:设置为属性所赋的值
<bean id="studentTwo" class="com.sentiment.pojo.Student">
<property name="sid" value="1842"></property>
<property name="sname" value="Sentiment"></property>
<property name="age" value="20"></property>
<property name="gender" value="男"></property>
</bean>
测试
public void testSetter(){
ClassPathXmlApplicationContext ioc = new ClassPathXmlApplicationContext("spring-ioc.xml");
Student studentTwo = ioc.getBean("studentTwo", Student.class);
System.out.println(studentTwo);
}
结果
此时通过property标签,对各个属性进行了赋值
Student{sid=1842, sname='Sentiment', age='20', gender='男'}
构造器注入
配置
若只有一个有参控制器,直接赋值即可
<bean id="studentThree" class="com.sentiment.pojo.Student">
<constructor-arg value="1843"></constructor-arg>
<constructor-arg value="Tana"></constructor-arg>
<constructor-arg value="21"></constructor-arg>
<constructor-arg value="男"></constructor-arg>
</bean>
测试
public void testByConstructor(){
ClassPathXmlApplicationContext ioc = new ClassPathXmlApplicationContext("spring-ioc.xml");
Student studentThree = ioc.getBean("studentThree", Student.class);
System.out.println(studentThree);
}
结果
Student{sid=1843, sname='Tana', age='21', gender='男'}
此时若再加一个属性并定义他的有参控制器
public Student(Integer sid, String sname, Double score, String gender) {
this.sid = sid;
this.sname = sname;
this.score = score;
this.gender = gender;
}
在执行后结果:
Student{sid=1843, sname='Tana', age='null', gender='男', score=21.0}
可以看到21想赋给age但,赋值给了score,所以在配置文件后边可以再加上一个name属性,来定义赋值对象
<constructor-arg value="21" name="age"></constructor-arg>
此时结果就赋给了age
Student{sid=1843, sname='Tana', age='21', gender='男', score=null}
\