Spring框架 IOC/DI
1、IOC (inversion of Control) 控制反转
1.什么是控制反转呢?
IOC:控制反转,以前对象需要自己new进行创建,现在把对象创建的操作交给了spring框架,用的时候直接找框架要即可,spring负责所有的对象的创建和管理,称之为IOC容器。
2.IOC容器的作用以及内部存放的是什么?
- IOC容器负责对象的创建、初始化等一系列工作,其中包含了数据层和业务层的类对象
- 被创建或被管理的对象在IOC容器中统称为==Bean==
- IOC容器中放的就是一个个的Bean对象
3.当IOC容器中创建好service和dao对象后,程序能正确执行么?
- 不行,因为service运行需要依赖dao对象
- IOC容器中虽然有service和dao对象
- 但是service对象和dao对象没有任何关系
- 需要把dao对象交给service也就是说要绑定service和dao对象之间的关系
像这种在容器中建立对象与对象之间的绑定关系就要用到DI。
2、DI(DependencyInjection)依赖注入
(1)什么是依赖注入呢?
在容器中建立bean与bean之间的依赖关系的整个过程,称为依赖注入。业务层要用数据层的类对象,以前是自己new的
现在自己不new了,靠别人[外部其实指的就是IOC容器]来给注入进来
这种思想就是依赖注入
(2)IOC容器中哪些bean之间要建立依赖关系呢?
- 这个需要程序员根据业务需求提前建立好关系,如业务层需要依赖数据层,service就要和dao建立依赖关系介绍完Spring的IOC和DI的概念后,我们会发现这两个概念的最终目标就是:==充分解耦==,具体实现靠:
- 使用IOC容器管理bean(IOC)
- 在IOC容器内将有依赖关系的bean进行关系绑定(DI)
- 最终结果为:使用对象时不仅可以直接从OC容器中获取,并目获取到的bean已经绑定了所有的依赖关系
一个重要特征是反射,它允许程序在运行的时候动态的生成对象、执行对象的方法、改变对象的属性,spring就是通过反射来实现注入
- 注入方式: 1.set方式注入 2.构造方法注入 3.字段注入
- 注入类型: 1.值类型注入 2.引用类型注入
接口区别
- BeanFactory,Spring内部使用接口,不提供给开发人员,加载配置xml解析不会创建,只有创建对象才会getBean
- ApplicationContext是BeanFactory子接口,功能强大,开发人员可使用,加载配置就会创建对象
ApplicationContext有一些特别的实现类
- ClassPathXmlApplicationContext,在src目录下可以写文件名
- FileSystemXmlApplicationContext,在src目录下,必须写绝对路径
具体实现:
所有Spring框架底层都用到了反射。
先导入jar包
dao层
BookDao接口
package com.chen.dao;
public interface BookDao {
void add();
}
BookDaoImpl实现类
package com.chen.dao.impl;
import com.chen.dao.BookDao;
public class BookDaoImpl implements BookDao {
@Override
public void add() {
System.out.println("BookDaoImpl...add");
}
}
service层
BookService接口
package com.chen.service;
public interface BookService {
void save();
}
BookServiceImpl实现类
package com.chen.service.impl;
import com.chen.dao.BookDao;
import com.chen.service.BookService;
public class BookServiceImpl implements BookService {
//BookServiceImpl 依赖 BookDao的对象
private BookDao bookDao;
public String name;
private int age;
set方法
在BookServiceImpl中添加BookDao方法
public void setBookDao(BookDao bookDao) {
this.bookDao = bookDao;
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
使用Spring的API获得Bean实例
@Override
public void save() {
System.out.println("BookServiceImpl...save");
bookDao.add();
}
}
BookServiceVip实现类
package com.chen.service.impl;
import com.chen.service.BookService;
public class package com.chen.service.impl;
import com.chen.service.BookService;
public class BookServiceVip implements BookService {
@Override
public void save() {
System.out.println("BookServiceVip...save");
}
}
implements BookService {
@Override
public void save() {
System.out.println("BookServiceVip...save");
}
}
测试类:
package com.chen.test;
import com.chen.service.BookService;
import com.sun.org.apache.bcel.internal.util.ClassPath;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test01 {
BookService bookService;
@Test
public void tset01(){
//对家的创建由spring框架创建,此处只需要直接闻IOC空器要
//1.通过CLassPathXmLApplicationContext加载sprinq.xml获得获得IOC容器
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
//2.从IOC容器中根据名字获得对象
bookService = (BookService) context.getBean("bookService");
bookService.save();
}
}
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=" Index of /schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
</beans>
Bean标签基本配置
用于配置对象交由Spring 来创建。
默认情况下它调用的是类中的无参构造函数,如果没有无参构造函数则不能创建成功。
基本属性:
- id:Bean实例在Spring容器中的唯一标识
- class:Bean的全限定名称
注入方式
==基本类型
set方式注入
值类型用value注入
引用类型用ref注入
<?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">
<!--告诉spring框架,创建管理哪些对象
id:给创建出来的对象起个名字
class:要创建对象对应类的全类名
-->
<bean id="bookDao" class="com.chen.dao.impl.BookDaoImpl"/>
<bean id="bookService" class="com.chen.service.impl.BookServiceImpl">
<property name="bookDao" ref="bookDao"/>
</bean>
</beans>
3、常用注解及作用
1.@Component
类注解,设置该类为spring管理的bean,属性可以定义bean的id,添加在类定义的上方,@Component注解不可以添加在接口上,因为接口无法创建对象。
步骤1:删除原XML配置
<bean id="bookDao" class="com.chen.dao.impl.BookDaoImpl"/>
步骤2:在Dao上添加@Component注解
步骤3:配置Spring的注解包扫描
为了让Spring框架能够扫描到写在类上的注解,要在配置文件中进行包扫描。
XML与注解配置的对应关系
2.@ComponentScan
用于设定扫描路径,此注解只能添加一次,多个数据用数组格式,可以替换掉配置文件中的扫描
3.@Scope
类注解,设置在类的上方,设置该类创建对象的作用范围,可以用来设置创建出来的bean是否为单例对象,属性定义bean的作用范围,默认为singleto(单例),可填prototype(非单例)
6.@Autowired
属性注解,方法注解,方法形参注解,分别可以写在属性定义上方,标准set方法上方,类set方法上方或方法形参前,为引用类型属性设置值
@Autowired可以写在属性上,也可也写在setter方法上,最简单的处理方式是写在属性上并将 setter方法删除掉
为什么setter方法可以删除呢?
1.自动装配基于反射设计创建对象并通过暴力反射为私有属性进行设值
2.普通反射只能获取public修饰的内容
3.暴力反射除了获取public修饰的内容还可以获取private修改的内容
所以此处无需提供setter方法
7.@Qualifier
属性注解或方法注解。写在属性定义的上方,或标准set方法上方或类set方法上方。当根据类型在容器中找到多个bean,注入参数的属性名又和容器中bean的名称不一致,这个时候就需要使用到@Qualifier来指定注入哪个名称的bean对象。@Qualifier注解的属性值就是需要注入的bean的名称。@Qualifier不能独立使用,必须和@Autowired一起使用。