Spring入门01-IOCDI

目录 一、学习导图 二、Spring 框架概念 三、基本环境搭建 四、SpringIOC容器Bean对象的实例化的模拟实现 什么是IOC? (1)定义b

目录

一、学习导图

 二、Spring 框架概念

 三、基本环境搭建

四、SpringIOC容器Bean对象的实例化的模拟实现

什么是IOC?

(1)定义bean属性对象

(2)添加dom4j坐标依赖

(3)自定义spring.xml配置文件

(4)定义bean工厂接口

(5)测试

五、配置文件加载

六、IOC容器Bean对象实例化

Spring三种实例化Bean的方式比较

七、Spring IOC 注入

注入方式的选择

七、Spring IOC 自动装配(注入)

注解方式注入 Bean

@Resource注解

@Autowired注解

八、Spring IOC 扫描器

九、Bean的作用域与生命周期

1.Bean的作用域

(1)lazy-init属性(懒加载)

lazy-init属性为什么要设置为false?

(2)Scope属性:

1.singleton:单例作用域(默认)

什么对象适合作为单例对象?(什么对象适合交给IOC容器实例化?)

2.prototype:原型作用域

2.Bean的生命周期


一、学习导图

IOC/DI- 控制反转和依赖注入:将对象实例化的创建过程转交给外部容器(IOC 容器充当工厂角色)去负责;属性赋值的操作。

 二、Spring 框架概念

        Spring 是众多开源 java 项目中的一员,基于分层的 javaEE 应用一站 式轻量级开源框架,主要核心是 IOC (控制反转 / 依赖注入)与 AOP(面向切面)两大技术,实现项目在开发过程中的轻松解耦, 提高项目的开发效率。         在项目中引入 Spring 立即可以带来下面的好处 降低组件之间的耦合度, 实现软件各层之间的解耦。可以使用容器提供的众多服务,如:事务管理服务、消息服务等等。当我们使用容器管理事务时, 开发人员就不再需要手工控制事务。 也不需处理复杂的事务传播。 容器提供单例模式支持,开发人员不再需要自己编写实现代码。 容器提供了AOP 技术,利用它很容易实现如权限拦截、运行期监控等功能。

 三、基本环境搭建

1.新建Maven项目:模板quick-start

2.配置pom文件

4.0.0com.msbSpring011.0-SNAPSHOTjarSpring01http://maven.apache.orgUTF-81.81.8junitjunit4.12testorg.springframeworkspring-context5.2.4.RELEASE

3.编写Bean对象,如dao层、service层对象。

4.添加spring配置文件

在项目的src下创建resources并标记为Resources Root

5.测试类中加载配置文件



6.启动

public class Starter01 {public static void main(String[] args) {//得到spring的上下文环境ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");//通过id属性得到指定的bean对象UserService userService = (UserService) ac.getBean("userService");//调用实例化好的javabean对象的方法userService.test();//通过id属性得到指定的bean对象UserService02 userService02 = (UserService02) ac.getBean("userService02");//调用实例化好的javabean对象的方法userService02.test();}
}

四、SpringIOC容器Bean对象的实例化的模拟实现

什么是IOC?

解释1:创建对象的权利,或者是控制的位置,由JAVA代码转移到spring容器,由spring的容器控制对象的创建,就是控制反转。spring创建对象时,会读取配置文件中的信息,然后使用反射给我们创建好对象之后在容器中存储起来,当我们需要某个对象时,通过id获取对象即可,不需要我们自己去new。

一句话:创建对象交给容器

解释2:Spring框架管理这些Bean的创建工作,即由用户管理Bean转变为框架管理Bean,这个就叫 控制反转 - Inversion of Control (IoC)

部分引用自什么是控制反转(IOC)? - 知乎

思路:

  1. 定义Bean 工厂接口,提供获取bean方法
  2. 定义Bean工厂接口实现类,解析配置文件,实例化Bean对象
  3. 实现获取 Bean 方法

(1)定义bean属性对象

/*** Bean属性对象*  用来存放配置文件中bean标签对应的id和class属性值*/
public class MyBean {private String  id; //bean标签的id属性值private String clazz; //bean标签的class属性值public MyBean() {}public MyBean(String id, String clazz) {this.id = id;this.clazz = clazz;}public String getId() {return id;}public void setId(String id) {this.id = id;}public String getClazz() {return clazz;}public void setClazz(String clazz) {this.clazz = clazz;}
}

(2)添加dom4j坐标依赖

    dom4jdom4j1.6.1jaxenjaxen1.1.6

(3)自定义spring.xml配置文件



(4)定义bean工厂接口

public interface MyFactory {//通过id属性值获取对象public Object getBean(String id);
}

实现类:

/*** 模拟Spring的实现* 1. 通过带参构造器得到对应的配置文件* 2. 通过dom4j解析配置文件(xml文件),得到List集合(存放bean标签的id和class属性值)* 3. 通过反射得到对应的实例化对象,放置在Map对象  (遍历List集合,通过获取对应的class属性,利用Class.forName(class).newIntance())* 4. 通过id属性值获取指定的实例化对象*/
public class MyClassPathXmlApplicationContext implements MyFactory {private List beanList;  // 存放从配置文件中获取到的bean标签的信息(MyBean代表的就是每一个bean标签)private Map beanMap = new HashMap<>();  // 存放实例化好的对象,通过id获取对应的对象/* 通过带参构造器得到对应的配置文件 */public MyClassPathXmlApplicationContext(String fileName) {/* 通过dom4j解析配置文件(xml文件),得到List集合 */this.parseXml(fileName);/* 通过反射得到对应的实例化对象,放置在Map对象 */this.instanceBean();}/*** 通过dom4j解析配置文件(xml文件),得到List集合* 1. 获取解析器* 2. 获取配置文件的URL* 3. 通过解析器解析配置文件(xml文件)* 4. 通过xpath语法解析,获取beans标签下的所有bean标签* 5. 通过指定的解析语法解析文档对象,返回元素集合* 6. 判断元素集合是否为空* 7. 如果元素集合不为空,遍历集合* 8. 获取bean标签元素的属性 (id和class属性值)* 9. 获取MyBean对象,将id和class属性值设置到对象中,再将对象设置到MyBean的集合中** @param fileName*/private void parseXml(String fileName) {
//        1. 获取解析器SAXReader saxReader = new SAXReader();
//        2. 获取配置文件的URLURL url = this.getClass().getClassLoader().getResource(fileName);try {
//        3. 通过解析器解析配置文件(xml文件)Document document = saxReader.read(url);
//        4. 通过xpath语法解析,获取beans标签下的所有bean标签XPath xPath = document.createXPath("beans/bean");
//        5. 通过指定的解析语法解析文档对象,返回元素集合List elementList = xPath.selectNodes(document);
//        6. 判断元素集合是否为空if (elementList != null && elementList.size() > 0) {// 实例化beanListbeanList = new ArrayList<>();
//        7. 如果元素集合不为空,遍历集合for (Element el : elementList) {
//        8. 获取bean标签元素的属性 (id和class属性值)String id = el.attributeValue("id");//id属性值String clazz = el.attributeValue("class");//class属性值
// 9. 获取MyBean对象,将id和class属性值设置到对象中,再将对象设置到MyBean的集合中MyBean myBean = new MyBean(id, clazz);beanList.add(myBean);}}} catch (DocumentException e) {e.printStackTrace();}}/*** 通过反射得到对应的实例化对象,放置在Map对象* 1. 判断对象集合是否为空,如果不为空,则遍历集合,获取对象的id和calss属性* 2. 通过类的全路径名 反射 得到实例化对象  Class.forName(class).newInstance()* 3. 将对应的id和实例化好的bean对象设置到map对象中*/private void instanceBean() {
//        1. 判断对象集合是否为空,如果不为空,则遍历集合,获取对象的id和calss属性if (beanList != null && beanList.size() > 0) {for (MyBean bean : beanList) {String id = bean.getId();String clazz = bean.getClazz();try {
//        2. 通过类的全路径名 反射 得到实例化对象  Class.forName(class).newInstance()Object o = Class.forName(clazz).newInstance();
//        3. 将对应的id和实例化好的bean对象设置到map对象中beanMap.put(id, o);} catch (Exception e) {e.printStackTrace();}}}}/*** 通过id获取对应的map对象中的value(实例化好的bean对象)** @param id* @return*/@Overridepublic Object getBean(String id) {Object obj = beanMap.get(id);return obj;}
}

(5)测试

public class App {public static void main(String[] args) {//得到工厂的实现类MyFactory factory = new MyClassPathXmlApplicationContext("spring.xml");//得到对应的实例化对象UserDao userDao = (UserDao) factory.getBean("userDao");UserService userService = (UserService) factory.getBean("userService");userDao.test();userService.test();UserDao userDao02 = (UserDao) factory.getBean("userDao");System.out.println(userDao==userDao02);}
}

五、配置文件加载

  1. 根据相对路径加载资源(常规)
  2. 根据绝对路径加载资源(了解)
  3. 多配置文件加载,可变参数,传入多个文件名
  4. 多配置文件加载,总的配置文件import其他文件,只需要加载总文件即可


六、IOC容器Bean对象实例化

  1. 构造器实例化
  2. 静态工厂实例化(了解)
  3. 实例化工厂实例化(了解)

配置:



工厂:
public class StaticFactory {    //静态/*** 定义对应的静态方法* @return*/public static TypeService createService(){// 实例化前可以做事return new TypeService();}
}public class InstanceFactory {    //实例化public TypeController createTypeController(){return new TypeController();}
}
测试:
public static void main(String[] args) {/*** 返回的全是单例*/BeanFactory factory = new ClassPathXmlApplicationContext("spring02.xml");//构造器实例化TypeDao typeDao = (TypeDao) factory.getBean("typeDao");typeDao.test();System.out.println(typeDao);System.out.println(factory.getBean("typeDao"));//静态工厂实例化TypeService typeService = (TypeService) factory.getBean("typeService");typeService.test();// 实例化工厂实例化TypeController typeController = (TypeController)factory.getBean("typeController");typeController.test();}

注意:当我们指定Spring使用静态工厂方法来创建Bean实例时,Spring将先解析配置文件,并根据配置文件指定的信息,通过反射调用静态工厂类的静态工厂方法,并将该静态工厂方法的返回值作为Bean实例,在这个过程中,Spring不再负责创建Bean实例,Bean实例是由用户提供的静态工厂方法提供的。

Spring三种实例化Bean的方式比较

方式一: 通过 bean 的缺省构造函数创建 ,当各个 bean 的业务逻 辑相互比较独立的时候或者和外界关联较少的时候可以使用。 方式二:利用静态 factory 方法创建,可以统一管理各个 bean 的 创建,如各个bean 在创建之前需要相同的初始化处理,则可用这个factory 方法先进行统一的处理等等。 方式三:利用实例化 factory 方法创建,即将 factory 方法也作为了业务bean 来控制, 1 可用于集成其他框架的 bean 创建管理方法,2 能够使 bean factory 的角色互换。 开发中项目一般使用一种方式实例化 bean ,项目开发基本采用第 一种方式,交给 Spring 托管,使用时直接拿来使用即可。另外两种 了解。

七、Spring IOC 注入

Spring 支持的注入方式共有四种: set 注入、构造器注入、静态工厂注入、实例化工厂注入。 set 方法注入: 属性字段需要提供 set 方法 四种方式,推荐使用 set 方法注入
北京上海深圳西藏新疆云南许嵩玫瑰花的葬礼林俊杰江南山东河北河南

注入方式的选择

重点掌握 set 注入和构造器注入,工厂方式了解即可。实际开发 中基本使用 set 方式注入 bean p 名称空间的使用: spring2.5 以后,为了简化 setter 方法属性注入,引用 p 名称空间的 概念,可以将子元素,简化为元素属性配置。

七、Spring IOC 自动装配(注入)

注解方式注入 Bean

对于 bean 的注入,除了使用 xml 配置以外,可以使用注解配置。 注解的配置,可以简化配置文件,提高开发的速度,使程序看上去更简洁。对于注解的解释,Spring 对于注解有专门的解释器,对定义的注解进行解析,实现对应bean 对象的注入。通过 反射技术实现。

参考:<context:annotation-config/>的作用_tiny-dong的博客-CSDN博客

@Resource注解

@Resource注解实现自动注入 (反射)
1. 注解默认通过属性字段名称查找对应的bean对象(属性字段名称与bean标签的id属性值一致)
2. 如果属性字段名称不一样,则会通过类型(Class)类型
3. 属性字段可以提供set方法 也可以不提供
4. 注解可以声明在属性字段上 或 set方法级别
5. 可以设置注解的name属性,name属性值要与bean标签的id属性值一致(如果设置了name属性,则会按照name属性查询bean对象)
6. 当注入接口时,如果接口只有一个实现类,则正常实例化;如果接口有多个实现类,则需要使用name属性指定需要被实例化的bean对象

@Autowired注解

@Autowired注解实现自动化注入
1. 注解默认使用类型(Class类型)查找bean对象,与属性字段名称没有关系
2. 属性字段可以提供set方法 也可以不提供
3. 注解可以声明在属性级别 或 set方法级别
4. 如果想要通过指定名称查找bean对象,需要结合@Qualifier使用(通过设置value属性值查找,value属性值要bean标签的id属性值保持一致)

八、Spring IOC 扫描器

实际的开发中, bean 的数量非常多,采用手动配置 bean 的方式已无法满足生产需要,Spring 这时候同样提供了扫描的方式,对扫描到的bean 对象统一进行管理,简化开发配置,提高开发效率。

九、Bean的作用域与生命周期

1.Bean的作用域

(1)lazy-init属性(懒加载)

如果设置为true,表示懒加载,容器在启动时,不会实例化bean对象,在程序调用时才会实例化;

如果设置false(默认),表示不懒加载,容器启动则实例化bean对象。

lazy-init属性为什么要设置为false?

  1. 可以提前发现潜在的配置问题
  2. Bean对象在启动时就设置在单例缓存池中,使用时不需要再去实例化bean对象,提高程序运行效率

(2)Scope属性:

1.singleton:单例作用域(默认)

默认情况下,我们从 Spring 容器中拿到的对象均是 单例 的,对于 bean的作用域类型如下:

注意:

  1. 默认懒加载是false即Spring容器启动时实例化。如果等于true作用是指Spring容器启动的时候不会去实例化这个bean, 而是在程序调用时才去实例化。
  2. 默认单例:被管理的Bean只会在IOC容器中存在一个实例,对于所有获取该Bean的操作,Spring容器将只返回同一个Bean。
  3. 容器在启动的情况下就实例化所有singleton bean对象,并缓存与容器中。

 总结:Spring IOC容器在启动时,会将所有在singleton作用域中的bean对象实例化,并设置到单例缓存池中。

配置如下:

什么对象适合作为单例对象?(什么对象适合交给IOC容器实例化?)

无状态的对象(不存在改变当前对象状态的成员变量)比如:controller层、service层、dao层。

什么是无状态或状态不可改变的对象? 实际上对象状态的变化往往均是由于属性值得变化而引起的,比如user类姓名属性会有变化,属性姓名的变化一般会引起 user 对象状态的变化。对于我们的程序来说,无状态对象没有实例变量的存 在,保证了线程的安全性, service 层业务对象即是无状态对象,线程安全的。

2.prototype:原型作用域

 通过scope="prototype" 设置bean的类型 ,每次向Spring容器请求获取Bean都返回一个全新的Bean,相对于"singleton"来说就是不缓存Bean,每次都是一个根据Bean定义创建的全新Bean。

总结:Spring IOC容器在启动时,不会将bean对象实例化设置到单例缓存池中,每次实例化对象都会创建一个新的实例。

2.Bean的生命周期

在Spring中,Bean的生命周期包括Bean的定义、初始化、使用和销毁4个阶段。

Bean的定义
在配置文件中定义bean,通过bean标签定义对应bean对象。

Bean的初始化
IOC容器启动时,自动实例化Bean对象
        1. 在配置文档中通过指定 init-method 属性来完成。
        2. 实现 org.springframework.beans.factory.InitializingBean 接口。




Bean的使用
        1. 使用 BeanFactory对象
        2. 使用 ApplicationContext对象

Bean的销毁
         步骤一:通过 AbstractApplicationContext 对象,调用其close方法实现bean的销毁过程

// 通过 AbstractApplicationContext 对象,调用其close方法实现bean的销毁过程
AbstractApplicationContext ac = new ClassPathXmlApplicationContext("spring03.xml");
System.out.println("销毁前");
ac.close();
System.out.println("销毁后");


         步骤二:在配置文件中指定对应销毁的方法 destroy-method