前言:
控制反转IOC(Inversion of Control),是一种设计思想,DI(依赖注入)是实现IOC的一种方法,有很多人都说DI就是IOC,其实看你怎么理解了。
如下我们看到ApplicationContext有这么多的实现类,每一种都相当于一个DI,实现了IOC的思想。
1、什么是IOC和DI
以前用对象是自己是通过new 来获取,现在 通过spring容器来进行创建并通过注入的方式来获取。这个创建对象的控制权由调用者自己变成了spring容器
依赖注入(DI)一般由三种方式进行注入(构造方法、set、注解)
2、bean的一些元素
由IOC容器管理的称为bean,Spring容器启动的时候就加载了bean对象。
2.1、scope
总共有六个,分别是:
- singleton:单个对象实例,spring默认创建的对象的方式就是单例的
- prototype:原型,任意数量的对象实例
- request
- session
- application
- websocket
2.2、自动注入bean(bean对象中注入引入的bean)
2.2.1、xml方式
前提:有两个类一个是Address,一个是User,其中User中有一个成员变量Address
public class User {
private String userName;
private Address address;
public User(){
System.out.println("user无参构造");
}
public Address getAddress() {
return address;
}
public User setAddress(Address address) {
this.address = address;
return this;
}
public String getUserName() {
return userName;
}
public User setUserName(String userName) {
this.userName = userName;
return this;
}
方式一:
<bean id="user" class="com.guang.spring.ioc.Model.User" autowire="byName">
<property name="userName" value="liguang"></property>
</bean>
<bean id="address" class="com.guang.spring.ioc.Model.Address">
<property name="address" value="北京"></property>
</bean>
方式二:
<bean id="user" class="com.guang.spring.ioc.Model.User">
<property name="userName" value="liguang"></property>
<property name="address" ref="address"></property>
</bean>
方式一的结果和方式二相同,只不过是autowire=“byName” 代替了 <property name="address" ref="address"></property>
,通过set方法的名字自己注入。
2.2.2、注解@Autowired
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/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<bean id="user" class="com.guang.spring.ioc.Model.User"></bean>
<bean id="address" class="com.guang.spring.ioc.Model.Address"></bean>
<!--开启注解-->
<context:annotation-config/>
</beans>
User类中
@Autowired
private Address address;
以上同样能实现自动注入
2.2.3、@Resource和Autowired区别
- 都是用来自动装配的,都可以放在属性字段上
- @Autowired通过byType的方式实现,如果@Autowired不能唯一自动装配上属性,则需要通过@Qualifier(value=“xxx”)
- @Resource默认通过byname的方式实现,如果查找不到名字,则通过byType实现,如果两个都找不到就报错
- @Autowired是Spring自己的注解,但是@Resource是jdk的注解,只不过Spring都支持
上面所说的byname其实就是根据bean下的id值找到对应java中的set名
3、Spring常用的依赖注入方式(DI)(bean注入到Spring容器中)
介绍之前建议快速过一下官网 https://docs.spring.io/spring-framework/docs/5.2.13.RELEASE/spring-framework-reference/core.html#beans-basics
3.1 构造方法注入
maven项目 pom:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.3</version>
</dependency>
User类:
package com.guang.spring.ioc.Model;
public class User {
private String userName;
public User(String userName){
this.userName=userName;
}
public String getUserName() {
return userName;
}
public void show(){
System.out.println("name="+userName);
}
}
beans.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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!--使用Spring来创建对象,在Spring中这些都称为bean
User user=new User();
id=变量名
class=new 对象;
-->
<bean id="user" class="com.guang.spring.ioc.Model.User">
<constructor-arg name="userName" value="guangge"></constructor-arg>
</bean>
</beans>
测试类:
public class MyTest {
public static void main(String[] args) {
//配置文件的地址,并且可以传多个,获取Spring上下文对象
// context 就相当于Spring容器
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
//我们的对象现在都在Spring中管理了,我们要使用,直接去里面取出来
User user = context.getBean("user",User.class);
user.show();
}
}
结果:
3.2 set注入(重要 )
User
package com.guang.spring.ioc.Model;
public class User {
private String userName;
public User(){
System.out.println("user无参构造");
}
public String getUserName() {
return userName;
}
public User setUserName(String userName) {
this.userName = userName;
return this;
}
public void show(){
System.out.println("name="+userName);
}
}
beans.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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!--使用Spring来创建对象,在Spring中这些都称为bean
User user=new User();
id=变量名
class=new 对象;
-->
<bean id="user" class="com.guang.spring.ioc.Model.User">
<property name="userName" value="liguang"></property>
</bean>
</beans>
结果:
注意:
(1)name属性值与类中的成员变量名以及set方法的参数名都无关,只与对应的set方法名有关 如上name为userName 那么对应的set也要为setUserName
(2)如果通过set方法注入属性,那么spring会通过默认的空参构造方法来实例化对象,所以如果在类中写了一个带有参数的构造方法,一定要把空参数的构造方法写上,否则spring没有办法实例化对象,导致报错。
3.3 Spring IOC容器
(1)BeanFactory 容器
提供了配置框架的基本功能
(2)ApplicationContext
它实现了BeanFactory ,增加了新的功能,我们上面用到的ClassPathXmlApplicationContext和ClassPathXmlApplicationContext都是ApplicationContext
后记
上述方式注册bean,我们在开发中不会这么用,一般就用@controller @service等注解都解决了,这里只是剖析原理