IOC的原型
程序员不再管理对象的创建,更专注于业务的实现(会大大降低系统的耦合性)
一个好的程序秉承着高内聚低耦合的思想
IOC的本质(对象由Spring来创建、管理、装配)
IOC是一种设计思想,DI(依赖注入)只是实现IOC的一种方法
IOC是一种编程思想,由主动编程变为被动接收
IOC的实现方法
IOC是Spring框架的核心内容,有多种方式来实现:
- 使用xml配置
- 使用注解
- 新版本的Spring也可以零配置实现IOC
Spring容器在初始化时现读取配置文件,根据配置文件或元数据创建于组织对象存入容器中,程序使用时再从IOC容器中取出需要的对象
控制反转
控制(由Spring来创建)反转(程序本身不再创建对象,而是被动的接受对象)是一种描述(XML或注解)并通过第三方去生产或获取特定对象的方式。在Spring中实现控制反转的是IOC容器,其实现方法是依赖注入(DI)(依赖注入:利用set来实现注入)
Spring官网
https://docs.spring.io/spring-framework/reference/core/beans/basics.html
代码理解
User.java
package com.dao;
public class Users {
private String str;
public String getStr() {
return str;
}
public void setStr(String str) {
this.str = str;
}
@Override
public String toString() {
return "Users{" +
"str='" + str + '\'' +
'}';
}
}
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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!--使用Spring来创建对象,在Spring中这些都称为bean-->
<bean id="users" class="com.dao.Users">
<property name="str" value="Spring"/>
</bean>
</beans>
test.java
import com.dao.Users;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.util.HashMap;
public class MyText {
@Test
public void mytext() {
// 获取Spring的上下文对象
ApplicationContext context = new ClassPathXmlApplicationContext ("applicationContext.xml");
Users users = (Users) context.getBean ("users");
System.out.println (users.toString ());
}
}
运行结果
IOC创建对象的方式
- 使用无参构造创建对象。默认
- 使用有参构造创建对象
2.1下标赋值
<bean id="users" class="com.dao.Users">
<!--<property name="str" value="Spring"/>-->
<constructor-arg index="0" value="我是有参构造注入的下标赋值"/>
</bean>
2.2类型赋值
<!--使用Spring来创建对象,在Spring中这些都称为bean-->
<bean id="users" class="com.dao.Users">
<constructor-arg type="java.lang.String" value="我是类型注入"/>
</bean>
2.3直接通过参数名
<!--使用Spring来创建对象,在Spring中这些都称为bean-->
<bean id="users" class="com.dao.Users">
<constructor-arg name="str" value="直接通过参数名"/>
</bean>
Spring配置
别名(alias,可以通过别名获取到该对象)
<alias name="users" alias="users2"/>
<!--id:Bean的唯一标识符,也就是相当于我们学的对象名 ,class:Bean对象所对应的全限定名:包名+类名 name:别名-->
<bean id="users" class="com.dao.Users" name="users3">
<constructor-arg name="str" value="直接通过参数名"/>
</bean>
import
一般用于团队使用,将多个配置文件导入合并为一个
DI依赖注入
Set注入(重点)
- 依赖注入:Set注入
- 依赖:Bean对象的创建依赖于容器
- 注入:Bean对象中的所有属性,由容器来注入
复杂类型
public class Address {
private String address;
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
实际对象
public class Student {
private String name;
private Address address;
private String[] books;
private List<String> hobby;
private Map<String, String> card;
private String wife;
private Properties info;
}
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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="address" class="com.pojo.Address">
<property name="address" value="我是地址"/>
</bean>
<bean id="student" class="com.pojo.Student">
<!--第一种,普通值(value)注入-->
<property name="name" value="测试"/>
<!--第二种,Bean注入-->
<property name="address" ref="address"/>
<!--数组注入-->
<property name="books">
<array>
<value>我是数组1</value>
<value>我是数组2</value>
<value>我是数组3</value>
</array>
</property>
<!--list注入-->
<property name="hobby">
<list>
<value>我是list注入1</value>
<value>我是list注入2</value>
<value>我是list注入3</value>
</list>
</property>
<!--map注入-->
<property name="card">
<map>
<entry key="我是map1的key" value="我是map1"/>
<entry key="我是map2的key" value="我是map2"/>
<entry key="我是map3的key" value="我是map3"/>
</map>
</property>
<!--空值注入-->
<property name="wife">
<null/>
</property>
<!--Properties注入-->
<property name="info">
<props>
<prop key="我是Properties1的key">我是Properties1</prop>
<prop key="我是Properties2的key">我是Properties2</prop>
<prop key="我是Properties3的key">我是Properties3</prop>
</props>
</property>
</bean>
</beans>
MyTest.java(测试类)
import com.pojo.Student;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest {
@Test
public void cs() {
ApplicationContext context = new ClassPathXmlApplicationContext ("beans.xml");
Student student = (Student) context.getBean ("student");
System.out.println (student.toString ());
}
}
官网参考
构造器注入
其他注入
p注入(快捷的set注入)
- 导入p命名空间
xmlns:p="http://www.springframework.org/schema/p"
- 实现
userBeans.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:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!--p命名空间注入,可以直接注入属性的值:相当于property-->
<bean id="user" class="com.pojo.User" p:name="我是p命名注入" p:age="20"/>
</beans>
测试
@Test
public void cs2() {
ApplicationContext context = new ClassPathXmlApplicationContext ("userBwans.xml");
User user = (User) context.getBean ("user");
System.out.println (user.toString ());
}
c注入(快捷的构造器注入)
导入c命名空间
xmlns:c="http://www.springframework.org/schema/c"
实现
userBeas.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:c="http://www.springframework.org/schema/c"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!--p命名空间注入,可以直接注入属性的值:相当于property-->
<bean id="user" class="com.pojo.User" c:name="我是c注入" c:age="20"/>
</beans>
cs.java
@Test
public void cs2() {
ApplicationContext context = new ClassPathXmlApplicationContext ("userBwans.xml");
User user = (User) context.getBean ("user");
System.out.println (user.toString ());
}
Bean scopes(Bean 作用域)
官方解释导航
重点掌握
- 单例模式(Spring模式机制)
`<bean id="user" class="com.pojo.User" c:name="我是c注入" c:age="20" scope="singleton"/>
- 原型模式(每次从容器中get时都会产生新的对象)
<bean id="user" class="com.pojo.User" c:name="我是c注入" c:age="20" scope="prototype"/>
- 其余的request、session、application,只能在Web开放中使用
Bean的自动装配
- 自动装配是Spring满足Bean依赖的一种方式
- Spring会在上下文中自动寻找,并自动给Bean装配属性
在Sprin中又三种自动装配的方式:
- 在xml中显示的配置
- 在Java中显示的配置
- 隐式的自动装配
测试代码搭建
Dog.java
package com.pojo;
public class Dog {
public void shut() {
System.out.println ("汪汪汪~");
}
}
Cat.java
package com.pojo;
public class Cat {
public void shut() {
System.out.println ("喵喵喵~");
}
}
People.java
package com.pojo;
public class People {
private String name;
private Dog dog;
private Cat cat;
public String getName() {
return name;
}
@Override
public String toString() {
return "People{" +
"name='" + name + '\'' +
", dog=" + dog +
", cat=" + cat +
'}';
}
public void setName(String name) {
this.name = name;
}
public Dog getDog() {
return dog;
}
public void setDog(Dog dog) {
this.dog = dog;
}
public Cat getCat() {
return cat;
}
public void setCat(Cat cat) {
this.cat = cat;
}
}
myTest.java
import com.pojo.People;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest {
@Test
public void test1() {
ApplicationContext context = new ClassPathXmlApplicationContext ("beans.xml");
People people = context.getBean ("people", People.class);
people.getCat ().shut ();
people.getDog ().shut ();
}
}
- byName自动装配
<?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">
<bean id="dog" class="com.pojo.Dog"/>
<bean id="cat" class="com.pojo.Cat"/>
<!--byName:会自动在容器上下文中查找,和自己对象set方法后面的值对应的beanid-->
<bean id="people" class="com.pojo.People" autowire="byName">
<property name="dog" ref="dog"/>
<property name="cat" ref="cat"/>
<property name="name" value="测试"/>
</bean>
</beans>
- byType自动装配
<?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">
<bean id="dog" class="com.pojo.Dog"/>
<bean id="cat" class="com.pojo.Cat"/>
<!--byType:会自动在容器上下文中查找,和自己对象属性类型相同的beanid-->
<bean id="people" class="com.pojo.People" autowire="byType">
<property name="dog" ref="dog"/>
<property name="cat" ref="cat"/>
<property name="name" value="测试"/>
</bean>
</beans>
小结:
byname的时候,需要保证所有的bean的id是唯一,并且这个bean需要和自动注入的属性的Set方法的值是一致的
bytype的时候,需要保证所有的bean的class是唯一的,并且这个bean需要和自动注入的属性的类型一致!
注解实现自动装配
使用注解的要求
- 导入约束
xmlns:context="http://www.springframework.org/schema/context"
- 配置注解支持
<?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">
<context:annotation-config/>
</beans>
@Autowired
直接在属性上使用即可,也可以在Set方式上使用!
使用Autowired我们可以不用编写Set方法了,前提自动装配的属性在IOC(Spring)容器中存在,且符合名字byname
科普:
@Nullable:字段标记了这个注解,说明这个字段可以为null
@Autowired (required=false):说明这个对象可以为空,否则则不允许为空
public @interface Autowired {
boolean required() default true;
}
测试代码:
public class People {
private String name;
@Autowired(required = false)
private Dog dog;
@Autowired
private Cat cat;
}
如果 @Autowired自动装配的环境比较复杂,自动装配无法通过一个注解【@Autowired】完成的时候,我们可以通过 @Qualifier(value = "XXX"取配置@Autowired的使用,指定一个唯一的bean对象注入
Resource注解(功能跟Autowired差不多)
@Resource(name = "cat")
private Cat cat;
小结:
@Resource和 @Autowired的区别
都是用来自动装配的,都可以放在属性字段上
@Autowired通过byType的方式实现,而且必须要求这个对象存在(常用)
@Resource默认通过byname的方式实现,如果找不到名字,则通过byType实现,如果两个都找不到的情况下,就报错(常用)
执行顺序不同:@Resource默认通过byname实现, @Autowired通过byType的方式实现。