Spring框架的官方下载地址: 点击进入
IoC理论
IoC理论
1、前言
文章主要讲的是Spring框架的控制反转以及它的实现方法依赖注入
2、IOC理论推导
2.1、
原先代码的顺序
(1)UserDao
package com.lin.dao;
public interface UserDao {
void getUser();
}
(2.1)UserDaoImpl
package com.lin.dao;
public class UserDaoImpl implements UserDao{
@Override
public void getUser() {
System.out.println("获取数据库数据");
}
}
(2.2)UserDaoMySqlImpl
package com.lin.dao;
public class UserDaoMySqlImpl implements UserDao{
@Override
public void getUser() {
System.out.println("Mysql get user data");
}
}
(3)UserService
package com.lin.service;
public interface UserService {
void getUser();
}
(4)UserServiceImp
package com.lin.service;
import com.lin.dao.UserDao;
import com.lin.dao.UserDaoImpl;
import org.junit.Test;
public class UserServiceImpl implements UserService{
// UserDao userDao=new UserDaoImpl(); //一般情况下
UserDao userDao;
//对于到层中的多个接口实现类,用set方法 使得代码不需要做太多改动
//利用set进行动态实现值的注入
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
@Override
public void getUser() {
userDao.getUser();
}
}
(5)Test
import com.lin.dao.UserDaoImpl;
import com.lin.dao.UserDaoMySqlImpl;
import com.lin.service.UserService;
import com.lin.service.UserServiceImpl;
public class MyTest {
public static void main(String[] args) {
//用户实际使用业务层 dao层不需要接触
UserService userService=new UserServiceImpl();
((UserServiceImpl)userService).setUserDao(new UserDaoImpl());
userService.getUser();
((UserServiceImpl)userService).setUserDao(new UserDaoMySqlImpl());
userService.getUser();
}
}
-
之前,程序是主动创建对象!控制权在我们自己的手上!
-
使用了set注入后,程序不再具有主动性,而是变成了被动的接受对象!
这种思想,从本质上解决了问题,我们程序猿不用再去管理对象的创建了。系统的耦合性大大降低~,可以更加专注的在业务的实现上!这是IOC的原型
2.2、IOC的本质
控制反转IoC(Inversion of Control),是一种设计思想,DI(依赖注入)是实现IoC的一种方法,也有人认为DI只是IoC的另一种说法。没有IoC的程序中 , 我们使用面向对象编程 , 对象的创建与对象间的依赖关系完全硬编码在程序中,对象的创建由程序自己控制,控制反转后将对象的创建转移给第三方,个人认为所谓控制反转就是:获得依赖对象的方式反转了。
IoC是Spring框架的核心内容,使用多种方式完美的实现了IoC,可以使用XML配置,也可以使用注解,新版本的Spring也可以零配置实现IoC。
Spring容器在初始化时先读取配置文件,根据配置文件或元数据创建与组织对象存入容器中,程序使用时再从Ioc容器中取出需要的对象。
采用XML方式配置Bean的时候,Bean的定义信息是和实现分离的,而采用注解的方式可以把两者合为一体,Bean的定义信息直接以注解的形式定义在实现类中,从而达到了零配置的目的。
控制反转是一种通过描述(XML或注解)并通过第三方去生产或获取特定对象的方式。在Spring中实现控制反转的是IoC容器,其实现方法是依赖注入(Dependency Injection,DI)。
3、IOC创建对象的方式
1.使用无参构造创建对象,默认
<!--Creating objects using parameterless construction-->
<bean id="user" class="com.lin.pojo.User">
<property name="name" value="lin"></property>
</bean>
2.使用有参构造创建对象,构造器注入
下标
<!-- 1.Constructor argument index-->
<bean id="user1" class="com.lin.pojo.User">
<constructor-arg index="0" value="lili"></constructor-arg>
</bean>
参数类型的匹配
<!-- 2.Constructor argument type matching-->
<!-- Not recommended-->
<bean id="user2" class="com.lin.pojo.User">
<constructor-arg type="java.lang.String" value="linlin"></constructor-arg>
</bean>
名字
<!-- 3.Constructor argument name-->
<bean id="user3" class="com.lin.pojo.User">
<constructor-arg name="name" value="lingling"></constructor-arg>
</bean>
总结:在配置文件加载的时候,容器中管理的对象就已经初始化了
4、DI 依赖注入
4.1、构造器注入
4.2、setter方式注入
- 依赖注入:set注入
- 依赖:bean对象的创建依赖于容器
- 注入:bean对象中的使用属性,由容器来注入
【环境搭建】
1.复杂类型
package com.lin.pojo;
public class Address {
private String address;
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
2.真实测试对象
public class Student {
private String name;
private Address address;
private String[] books;
private List<String> hobbys;
private Map<String,String> card;
private Set<String> games;
private String nullpoint;
private Properties info;
//此处省略getter、setter方法
}
3.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">
<bean id="student" class="com.lin.pojo.Student">
<!-- 1.Common value injection value=-->
<property name="name" value="lin"></property>
<!-- 2.2.Reference type injection ref=-->
<property name="address" ref="address"></property>
<!-- 3.Array injection-->
<property name="books">
<array>
<value>Journey to the West</value>
<value>The Dream of Red Mansion</value>
<value>Romance of the Three Kingdoms</value>
<value>Water Margin</value>
</array>
</property>
<!-- 4.List-->
<property name="hobbys">
<list>
<value>150</value>
<value>18</value>
<value type="int">15</value>
</list>
</property>
<!-- 5.Map-->
<property name="card">
<map>
<entry key="name" value="linlin"></entry>
<entry key="age" value="18"></entry>
</map>
</property>
<!-- 6.Set-->
<property name="games">
<set>
<value>QQ</value>
<value>WeChar</value>
</set>
</property>
<!-- 7.(1).nullpoint-->
<!-- <property name="nullpoint">-->
<!-- <null></null>-->
<!-- </property>-->
<!-- 7.(2).nullpoint-->
<property name="nullpoint" value=""></property>
<!-- 8.Properties-->
<property name="info">
<props>
<prop key="driver">com.mysql.cj.jdbc.Driver</prop>
<prop key="url">jdbc:mysql://localhost:3306</prop>
<prop key="username">admin</prop>
<prop key="password">123456</prop>
</props>
</property>
</bean>
<!-- -->
<!-- 2.1.Reference type injection-->
<bean id="address" class="com.lin.pojo.Address">
<property name="address" value="beijin"></property>
</bean>
</beans>
4.测试类
import com.lin.pojo.Student;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
Student student = (Student) context.getBean("student");
System.out.println(student.toString());
/*
Student{
name='lin',
address=Address{address='beijin'},
books=[Journey to the West, The Dream of Red Mansion, Romance of the Three Kingdoms, Water Margin],
hobbys=[150, 18, 15],
card={name=linlin, age=18},
games=[QQ, WeChar],
nullpoint='',
info={
password=123456, driver=com.mysql.cj.jdbc.Driver, url=jdbc:mysql://localhost:3306, username=admin}
}
*/
}
}
4.3、拓展方式注入
p命名空间
xmlns:p="http://www.springframework.org/schema/p"
c命名空间
xmlns:c="http://www.springframework.org/schema/c"
使用
<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"
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:P namespace injection properties-->
<bean id="user" class="com.lin.pojo.User" p:name="lin" p:age="18"></bean>
<!-- c:C namespace injection construct-args-->
<bean id="user2" class="com.lin.pojo.User" c:age="17" c:name="ling"></bean>
</beans>
测试
@Test
public void test(){
ApplicationContext context = new ClassPathXmlApplicationContext("userbean.xml");
User user = context.getBean("user",User.class);
System.out.println(user);
L
L
4.4、bean的作用域
1.单例模式(Spring默认机制):每次getBean都使用同一个对象
<bean id="user" class="com.lin.pojo.User" scope="singleton" ></bean>
User user2 = context.getBean("user2", User.class);
System.out.println(user2);
User user3 = context.getBean("user2", User.class);
System.out.println(user3==user2); //结果为true
2.原型模式:每次getBean都会产生新对象
<bean id="user" class="com.lin.pojo.User" scope="prototype" ></bean>
User user2 = context.getBean("user2", User.class);
System.out.println(user2);
User user3 = context.getBean("user2", User.class);
System.out.println(user3==user2); //结果为false
3.其余的request、session、application、在web开发中使用
5.Spring配置
5.1、别名(id)
<!-- 3.Constructor argument name-->
<bean id="user3" class="com.lin.pojo.User">
<constructor-arg name="name" value="lingling"></constructor-arg>
</bean>
<alias name="user3" alias="2233"></alias>
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
User user3 = (User) context.getBean("2233");
user3.show();
5.2、Bean的配置
5.3、import
用于团队开发,它可以将多个配置文件,导入合并为一个
<import resource="beans.xml"></import>
6、Bean的自动装配
- 自动装配:Spring满足bean依赖的一种方式
- Spring会在上下文中自动寻找,并自动给bean装配属性
在Spring中有三种装配的方式
1.在xml中显式的配置
2.在java中显式配置
3.隐式的自动装配bean
6.1、测试
6.2、ByName自动装配
名字唯一
<bean id="cat" class="com.lin.pojo.Cat"></bean>
<bean id="dog" class="com.lin.pojo.Dog"></bean>
<!-- <bean id="person" class="com.lin.pojo.Person">-->
<!-- <property name="cat" ref="cat"></property>-->
<!-- <property name="dog" ref="dog"></property>-->
<!-- </bean>-->
<!--Automatically find parameter name of set method in container-->
<bean id="person" class="com.lin.pojo.Person" autowire="byName"></bean>
6.3、ByType自动装配
类型唯一
<bean id="cat" class="com.lin.pojo.Cat"></bean>
<bean id="dog" class="com.lin.pojo.Dog"></bean>
<!--Automatically find the beanid with the same object property type in the container-->
<bean id="person" class="com.lin.pojo.Person" autowire="byType"></bean>
小结:
- byName:需要保证所有bean的id唯一,并且这个bean需要和自动注入的属性的set方法的值一致
- byType:需要保证所有bean的class唯一,并且这个bean需要和自动注入的属性的类型一致
6.4、使用注解自动装配
jdk1.5,Spring2.5 支持
注意:
1.导入context约束
2.配置注解的支持context:annotation-config/
<?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可以忽略setter方法,前提是自动装配的属性在IOC(Spring)容器中存在,且符合byName
@Autowired(required=false):对象取空不会报错
@Nullable:参数加上该注解即可取空值
代码测试
package com.lin.pojo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.lang.Nullable;
public class Person {
//都被注入而且名字相同就可以用@Autowired
@Autowired
private Cat cat;
@Autowired
private Dog dog;
public Cat getCat() {
return cat;
}
//@Nullable Cat cat
public void setCat(@Nullable Cat cat) {
this.cat = cat;
}
public Dog getDog() {
return dog;
}
@Override
public String toString() {
return "Person{" +
"cat=" + cat +
", dog=" + dog +
'}';
}
public void setDog(Dog dog1) {
this.dog = dog1;
}
}
如果@Autowired自动装配的环境比较复杂,无法通过一个注解【@Autowired】完成自动装配的时候,我们可以通过@Qualifier(value =“xxx”)去配合@Autowired去使用,它将去指定一个唯一的bean对象的注入
@Autowired
@Qualifier(value ="dog11")
private Dog dog;
@Resource
//找名字或者找类型都行
@Resource
@Resource和@Autowired的区别:
- 都是用来自动装配的,都可以放在属性字段上
- @Autowired 通过byType的方式实现,而且这个对象必须存在,如果byType不能判断,则使用byName实现
- @Resource默认通过byName 的方式实现,如果byName不能判断,则使用byType 实现,两个都找不到就报错
总结
这里对文章进行总结:本文简单的介绍了IoC容器的基本内容,如有错误,请在评论区指出,谢谢。