ASCII码 ASCII码

二、Spring程序开发

发布于:2022-06-29 20:37:45  栏目:技术文档

一、本次学习的软件版本介绍

  1. JDK 1.8+
  2. Maven 3.5+
  3. IDEA2018+
  4. SpringFramework 5.1.4

二、环境搭建

Spring的jar包

  1. 我们可以通过maven的中心仓库来获取对应版本的依赖(上网找-搜spring-看到springcontext)
  2. <dependency>
  3. <groupId>org.springframework</groupId>
  4. <artifactId>spring-context</artifactId>
  5. <version>5.1.4.RELEASE</version>
  6. </dependency>

Spring的配置文件

  1. 1. 配置文件的放置位置: 任意位置 没有硬性要求
  2. 2. 配置文件的命名:没有硬性要求,不过官方建议:applicationContext.xml
  3. 思考:你不告诉spring你的配置文件在哪,它怎么去拉配置呢?
  4. 所以我们后面要配置对应【配置文件】的路径
  5. 备注:我们可以通过下图所示创建对应的配置文件

三、Spring的核心API

ApplicationContext

  1. 作用:Spring提供的的这个ApplicationContext这个工厂,最重要的是为了对象的创建
  2. 好处: 解耦合

ApplicationContext接口类型

  1. >为什么是接口?
  2. 因为接口的目的是为了屏蔽实现的差异(谁实现我,谁就必须实现我所声明的方法)
  3. >那么Spring的接口实现类有哪些呢?
  4. 非WEB环境:ClassPathXmlApplicationContext (比如main junit等方法)
  5. WEB环境: XmlWebApplicationContext
  6. >如何证明上面说的是正确的呢?
  7. 首先为了保证有WEB环境的实现类,我们先导入下面这个依赖
  8. <dependency>
  9. <groupId>org.springframework</groupId>
  10. <artifactId>spring-webmvc</artifactId>
  11. <version>5.1.4.RELEASE</version>
  12. </dependency>
  13. 第二步:我们使用 CTRL+H 去查看该类的继承关系,那么我们就找到了如下图

Application的实现类都是重量级资源

  1. 》毕竟属于创建对象的重要方法,所以其一定占用了大量的内存
  2. 》不会频繁地创建对象:一个应用只会创建一个工厂对象
  3. 》在多线程并发访问的时候一定是线程安全的

开发你的第一个Spring程序吧!其实和第一节的通过工厂方式获取对象的方式一样,我们通过在配置文件取得唯一的类的全限定名来获取对象,下面为开发步骤

  1. 1》创建类:需要什么类,就配置什么类
  2. 2》配置applicationContext.xml文件
  3. <bean id="user" class="cn.paul.spring.demo.hellospring.entity.User"/>
  4. 这里的id一定是唯一的,class是类的权限定名,这就像我们开头所学习的配置文件的k-v对一样
  5. 3》通过工厂,获得对象
  6. ApplicationContext
  7. |- ClassPathXmlApplicationContext (Junit或main等非web的环境下使用)
  8. |- XmlWebApplicationContext(在web环境下使用)
  9. 4》demo展示
  10. public class TestSpring {
  11. @Test
  12. void test01(){
  13. //获取Spring工厂(传入对应的文件路径)
  14. ApplicationContext ctx = new ClassPathXmlApplicationContext("/applicationContext.xml");
  15. //通过Spring工厂创建对象
  16. User user = ctx.getBean("user", User.class);
  17. System.out.println("user:"+user);
  18. }
  19. }
  20. 备注:对于非WEB的环境,你需要告知Spring你的配置文件在哪里!!

第一个程序后,你应该要对下面这些细节有了解哦

  1. 第一点,通过上面的getBean方法传入的是配置文件的id和对应的类名称,那么很明显
  2. 通过这种方式,能很好地去让Spring确定你需要创建哪个Bean(在Spring中也叫component)
  3. 第二点,我们还有一种getBean(User.class),通过这种方式来创建对象,比较好的一点就是
  4. 开发者可以稍微懒一下,但是这是有限制的,如果你在配置文件中有声明到两个bean,而这
  5. 两个bean所对应的Class名称都一样,都为这个同一个类的全限定名,那么在运行的时候就会
  6. 报NoUniqueBeanDefinitionException 这个异常
  7. //通过这种方式获得对象,就不需要强制类型转换
  8. Person person = ctx.getBean("Person",Person.class);
  9. //当前Spring的配置文件中,只能有一个<bean class是Person类型
  10. Person person = ctx.getBean(Person.class);
  11. //获取的是Spring工厂配置文件中所有的bean标签的id值(看英文的复数便知)
  12. String[] beanDefinitionNames = ctx.getBeanDefinitionNames();
  13. //根据class的类型获得Spring配置文件中对应的id值
  14. String[] beanNamesForType = ctx.getBeanNamesFortype(Person.class);
  15. //下面两个方法都能用于判断是否存在指定id 的bean
  16. ctx.containsBeanDefinition("指定的id");
  17. ctx.containsBean("指定的id")

配置文件中需要注意的细节

  1. a)我们先来思考一个问题,如果我们只是配置了一个只含有class标签的bean,Spring会帮
  2. 我们创建吗?如下
  3. <bean class="cn.paul.spring.demo.hellospring.entity.User"/>
  4. 答案是:可以的,但是必须保证如果你想实际地使用上该对象,那么这个bean要保证唯一
  5. 第二问题:既然上面对bean的定义是可以,那么Spring是否有给它定义“id值”呢?
  6. 我们可以通过 ctx.getBeanDefinitionNames()来获取对应的id值以做出判断
  7. 我们会发现其实Spring其实会给这个只声明了class名称的bean对应的id值的,
  8. 其命名规则为:类的全限定名+ # + 下标
  9. 如:cn.paul.spring.demo.hellospring.entity.User#0
  10. 我们留意一下最后一个下标,为什么下标是数组0呢?莫非还有1,2,3.....?
  11. 其实我推测可能是这样的,我们可以在配置文件配置多个只带class名称的bean
  12. Spring也会给他们对应的默认id值(后面下标改变即可)
  13. b) 只定义class名称的bean的应用场景
  14. 1> 如果这个bean只需要使用一次,那么就可以省略id值
  15. 2> 如果这个bean会使用多次,或者被其他bean引用则需要设置id值
  16. c) name的属性
  17. 除了在bean标签内定义id和class属性外,还可以定义name属性
  18. 作用:用于在Spring的配置文件中,为bean对象设置别名(小名)
  19. 按照我们的生活经验,我们知道本名只能有一个(就像这里的id属性),但是我们可以有
  20. 很多个别名小名(就像这里的name属性,但是注意是指只针对一个bean对象)
  21. 问题:它和id属性有什么区别呢?
  22. 先说相同点:
  23. 1.ctx.getBean("id|name") --> Object (通过id或name,都可以创建对象)
  24. 但是注意:可以定义多个name,之间用逗号分割即可,但是不能在不同的bean使用同一个别名
  25. 2. <bean id="" class="" />
  26. 等效
  27. <bean name="" class="" />
  28. 3. 为什么要有name这个属性呢?
  29. 这是因为在早期Spring与Struts1整合的时候,对于bean的命名必须是以/开头的
  30. 但是早期的xml是不允许id以/开头的,所以导致说可用name来匹配这种特殊的命名
  31. 最后随着技术的发展,现在xml也允许id以/开头了,所以说name这个属性多多少少
  32. 带有一点历史的痕迹
  33. 4. 关于ctx工厂提供的方法
  34. ctx.containsBeanDefinition("字符串名称")只能判断是否存在指定id的bean
  35. 不能判断name值
  36. ctx.containsBean("字符串名称")既可以判断是否存在指定id值的bean,也可以
  37. 判断name值(所以以后尽量用这个吧,比较好记)

Spring工厂对上述的底层实现原理(简易版)

  1. 1.Spring框架通过ClassPathXmlApplicationContext工厂读取配置文件
  2. applicationContext.xml
  3. 2.获取到配置文件标签的相关信息,比如id的值=account,class的值=cn.paul.entity.User
  4. 3.通过反射去创建对象
  5. Class<?> clazz = Class.forName("class的值");
  6. User user = clazz.newInstance();
  7. 4.注意一个问题,通过反射可以创建以任何修饰符修饰的构造方法的类的对象(回顾爆破)
  8. 同时要知道反射的底层其实是调用了该类的构造方法,并且首先调用的是无参构造
  9. Class<?> clazz = Class.forName("class的值");
  10. User user = clazz.newInstance();
  11. 等效于
  12. User user = new User();

思考:在spring的开发中,是不是所有的对象,都会交由Spring工厂来创建呢

  1. 理论上来说,因为使用Spring工厂能解耦合的原因,确实是可以通过工厂来创建的
  2. 但是有特例,比如操作数据库的持久层DAO,或者叫entity是不会交给Spring创建的
  3. 而是交给持久层框架比如mybatis进行创建,毕竟entity生来是操作数据库的,和数据库做映射关系
相关推荐
阅读 +