Spring之IOC底层实现原理
一、Spring框架概述Spring框架是轻量级的开源的JavaEE框架Spring框架可以解决企业应用开发的复杂性Spring框架有两个核心部分:IOC和AOPSpring框架特点:方便解耦,简化开发;AOP编程支持;方便程序测试;方便和其它框架进行整合;方便事务事务操作;降低API开发难度IOC概念和原理1、什么是IOC?控制反转,把对象创建和对象之间的调用过程交给Spring框架进行管理使用
一、Spring框架概述
- Spring框架是轻量级的开源的JavaEE框架
- Spring框架可以解决企业应用开发的复杂性
- Spring框架有两个核心部分:IOC和AOP
- Spring框架特点:方便解耦,简化开发;AOP编程支持;方便程序测试;方便和其它框架进行整合;方便事务事务操作;降低API开发难度
IOC概念和原理
1、什么是IOC?
- 控制反转,把对象创建和对象之间的调用过程交给Spring框架进行管理
- 使用IOC的目的:为了耦合度降低
- 做入门案例就是IOC实现
2、IOC底层原理
xml解析——XML有三种解析方式:DOM SAX STAX
存储和传输数据经常一起使用,XML数据通常由程序生成的,用程序解析XML(XML一般不加约束)
配置文件单独使用(通常会加约束)
工厂模式——把对类的创建初始化全都交给一个工厂来执行,而用户不需要去关心创建的过程是什么样的
反射 ——反射可以在运行时根据指定的类名获得类的信息
3、IOC底层原理的图形解析
第一种图解方式:
第二种图解方式(为了避免第一种创建过程中存在耦合度比较高的情况,使用IOC进行创建):
4、IOC接口
- IOC思想是基于IOC容器完成,IOC容器底层就是对象工厂
- Spring框架中对IOC容器实现提供了两种方式(即两种接口)
2.1 第一种接口(BeanFactory接口):此接口是IOC容器的基本实现,也是Spring框架内部使用的接口,不提供给开发人员进行使用
注:此接口是在加载配置文件时不会创建对象,而是在获取对象或使用时才去创建对象
2.2 第二个接口(ApplicationContext):此接口是BeanFactory接口的子接口,提供了更强大的功能,一般由开发人员进行
注:此接口在加载配置文件时就会创建配置文件中所配置的对象
5、ApplicationContext接口的所有实现类
6、IOC操作Bean管理(基于xml配置文件方式实现Spring框架中创建对象和注入属性)
6.1 Spring框架中对象的创建
第一步:基于xml方式创建对象
<!--创建对象-->
<bean id="stu" class="com.spring.collection.Stu"><bean/>
- 在Spring框架配置文件中,使用bean标签,标签里面添加对应属性,就可以实现对象的创建
- 在bean标签中有很多属性,常用的属性介绍:id属性——唯一标识 class属性——类全路径
- 创建对象时默认执行无参构造方法完成对象的创建
6.2 Spring框架中对一个对象中的属性进行注入
介绍注入属性之前,先介绍一下DI——就是依赖注入,也是属性注入
第一种注入的方式使用set方法进行注入
第一步:创建类,定义属性和对应的set方法
/**
* 演示使用set方法进行注入属性
*/
public class Book {
//创建属性
private String bname;
private String bauthor;
//创建属性对应的set方法
public void setBname(String bname) {
this.bname = bname;
}
public void setBauthor(String bauthor) {
this.bauthor = bauthor;
}
}
第二步:在Spring配置文件中创建对象,然后配置属性注入
<!--2 set方法注入属性-->
<bean id="book" class="com.spring5.Book">
<!--使用property完成属性注入 name:类里面属性名称 value:向属性注入的值 -->
<property name="bname" value="易筋经"></property>
<property name="bauthor" value="达摩老祖"></property>
</bean>
第二种属性注入方式:使用有参构造进行注入
第一步:创建类,定义属性,创建属性对应的有参构造方法
/**
* 使用有参数构造注入
*/
public class Orders {
//属性
private String oname;
private String address;
//有参数构造
public Orders(String oname,String address) {
this.oname = oname;
this.address = address;
}
}
第二步在Spring配置文件中进行配置
<!--3 有参数构造注入属性-->
<bean id="orders" class="com.spring5.Orders">
<constructor-arg name="oname" value="电脑"></constructor-arg>
<constructor-arg name="address" value="China"></constructor-arg>
</bean>
第三种注入方式是引入p名称空间进行属性的注入
第一步:在配置文件中添加p名称空间
第二步进行属性注入
<!--2 set方法注入属性-->
<bean id="book" class="com.atguigu.spring5.Book" p:bname="九阳神功" p:bauthor="无名氏"></bean>
第四种是其它类型属性的注入
第一种是null值的注入
<!--null值-->
<property name="address">
<null/>
</property>
第二种是属性值包含特殊符号
<!--属性值包含特殊符号
1 把<>进行转义 < >
2 把带特殊符号内容写到CDATA
-->
<property name="address">
<value><![CDATA[<<南京>>]]></value>
</property>
第三种是对象的注入(外部bean)
public class UserService {
//创建UserDao类型属性,生成set方法 private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public void add() {
System.out.println("service add...............");
userDao.update();
}
}
<!--1 service和dao对象创建-->
<bean id="userService" class="com.spring5.service.UserService">
<!--注入userDao对象 name属性:类里面属性名称 ref属性:创建userDao对象bean标签id值 -->
<property name="userDao" ref="userDaoImpl"></property>
</bean>
<bean id="userDaoImpl" class="com.atguigu.spring5.dao.UserDaoImpl"></bean>
第四种对象的注入(内部)
//部门类
public class Dept {
private String dname;
public void setDname(String dname) {
this.dname = dname;
}
}
//员工类
class Emp {
private String ename;
private String gender;
//员工属于某一个部门,使用对象形式表示
private Dept dept;
public void setDept(Dept dept) {
this.dept = dept;
}
public void setEname(String ename) {
this.ename = ename;
}
public void setGender(String gender) {
this.gender = gender;
}
}
<!--内部bean-->
<bean id="emp" class="com.atguigu.spring5.bean.Emp">
<!--设置两个普通属性-->
<property name="ename" value="lucy"></property>
<property name="gender" value="女"></property>
<!--设置对象类型属性-->
<property name="dept">
<bean id="dept" class="com.atguigu.spring5.bean.Dept">
<property name="dname" value="安保部"></property>
</bean>
</property>
</bean>
第五种集合的注入
public class Stu {
//1 数组类型属性
private String[] courses;
//2 list集合类型属性
private List<String> list;
//3 map集合类型属性
private Map<String,String> maps;
//4 set集合类型属性
private Set<String> sets;
public void setSets(Set<String> sets) {
this.sets = sets;
}
public void setCourses(String[] courses) {
this.courses = courses;
}
public void setList(List<String> list) {
this.list = list;
}
public void setMaps(Map<String, String> maps) {
this.maps = maps;
}
}
<bean id="stu" class="com.spring.collection.Stu">
<property name="courses">
<array>
<value>java课程01</value>
<value>java课程02</value>
</array>
</property>
<property name="list">
<list>
<value>张三</value>
<value>李四</value>
</list>
</property>
<property name="map">
<map>
<entry key="JAVA" value="java"></entry>
<entry key="PHP" value="php"></entry>
</map>
</property>
<property name="sets">
<set>
<value>MySql</value>
<value>Web</value>
</set>
</property>
<!-- 注入一个集合类型中存放的是对象-->
<property name="courseList">
<list>
<ref bean="course_01"></ref>
<ref bean="course_02"></ref>
</list>
</property>
</bean>
<!-- 创建多个course对象-->
<bean id="course_01" class="com.spring.collection.Course">
<property name="cName" value="MyBatis"></property>
</bean>
<bean id="course_02" class="com.spring.collection.Course">
<property name="cName" value="Spring"></property>
</bean>
6.3 bean的作用域
- 在Spring里面,设置创建bean实例是单实例还是多实例
- 在Spring里面,默认情况下,bean是单实例
@Test
public void test01(){
ApplicationContext context = new ClassPathXmlApplicationContext(
"bean_01.xml");
Stu stu1 = context.getBean("stu", Stu.class);
Stu stu2 = context.getBean("stu", Stu.class);
System.out.println(stu1);
System.out.println(stu2);
}
如何设置多实例?
- 在Spring配置文件bean标签中有属性scope用于设置单实例还是多实例
- 默认值——singleton(单实例) prototype(多实例)
单实例和多实例的区别?
- 单实例是在加载Spring配置文件时候就会创建单实例对象
- 多实例不是在加载配置文件时创建对象,而是在调用getBean方法时创建对象
6.4 bean的生命周期
- 生命周期——指对象从创建到销毁的过程
- bean的生命周期
- 通过构造器创建bean实例(无参构造)
- 为bean的属性设置值和对其他bean引用(使用set方式注入)
- 调用bean的初始化方法(需要配置)
- 获取bean对象
- 当容器关闭时,销毁(需要配置)
public class Orders {
//无参数构造
public Orders() {
System.out.println("第一步 执行无参数构造创建bean实例");
}
private String oname;
public void setOname(String oname) {
this.oname = oname;
System.out.println("第二步 调用set方法设置属性值");
}
//创建执行的初始化的方法
public void initMethod() {
System.out.println("第三步 执行初始化的方法");
}
//创建执行的销毁的方法
public void destroyMethod() {
System.out.println("第五步 执行销毁的方法");
}
}
<bean id="orders" class="com.atguigu.spring5.bean.Orders" init-method="initMethod" destroy-method="destroyMethod">
<property name="oname" value="手机"></property>
</bean>
@Test
public void testBean3() {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean4.xml"); Orders orders = context.getBean("orders", Orders.class);
System.out.println("第四步 获取创建bean实例对象");
System.out.println(orders);
//手动让bean实例销毁
context.close();
}
7、基于注解实现IOC操作Bean管理
7.1 什么是注解?
- 注解是代码的特殊标记,格式形如(属性名称=属性值....)
- 使用注解,注解可作用在类上面,方法上面,属性上面
7.2 Spring针对bean管理中创建对象提供的注解
- @Commponent
- @Service——一般使用在Service层
- @Controller——一般使用在Web层
- Repository——一般使用在Dao层
第一步:引入依赖
第二步:开启组件扫描
<!--开启组件扫描 1 如果扫描多个包,多个包使用逗号隔开 2 扫描包上层目录 -->
<context:component-scan base-package="com.atguigu"></context:component-scan>
第三步:创建类,在类上面添加创建对象注解
//在注解里面value属性值可以省略不写,
//默认值是类名称,首字母小写
//UserService -- userService
@Component(value = "userService") //<bean id="userService" class=".."/>
public class UserService {
public void add() {
System.out.println("service add.......");
}
}
7.3 使用注解方式实现属性的注入
@Autowired:根据属性类型进行自动装配
@Service
public class UserService {
//定义dao类型属性
//不需要添加set方法
//添加注入属性注解
@Autowired
private UserDao userDao;
public void add() {
System.out.println("service add.......");
userDao.add();
}
}
@Qualifier:根据名称进行注入
这个@Qualifier注解的使用,和上面@Autowired一起使用
//定义dao类型属性
//不需要添加set方法
//添加注入属性注解
@Autowired
//根据类型进行注入 因为userDao接口的实现类可以有很多个
@Qualifier(value = "userDaoImpl1")
//根据名称进行注入
private UserDao userDao;
@Resource:可以根据类型注入,可以根据名称注入
//@Resource //根据类型进行注入
@Resource(name = "userDaoImpl1")
//根据名称进行注入
private UserDao userDao;
@Value:注入普通类型属性
@Value(value = "abc")
private String name;
更多推荐
所有评论(0)