Spring基础专题——第一章(第一个Spring程序)

前言:去年到现在一直没有很好的时间完成这个spring基础+源码的博客目标,去年一年比较懒吧,所以今年我希望我的知识可以分享给正在奋斗中的互联网开发人员,以及未来想往架构师上走的道友们我们一起进步,从一个互联网职场小白到一个沪漂湿人,一路让我知道分享是一件多么重要的事情,总之不对的地方,多多指出,我们一起徜徉代码的海洋!

 

我这里做每个章节去说的前提,不是一定很标准的套用一些官方名词,目的是为了让大家可以理解更加清楚,如果形容的不恰当,可以留言出来,万分感激

1、软件版本

  • jdk1.8+
  • maven3.5+
  • IDEA2019.2
  • Spring Framework 5.1.4(spring官网:http://spring.io)

2、环境搭建

pom.xml中设定spring的jar依赖

#设置pom 依赖
<!-- https://mvnrepository.com/artifact/org.springframework/springcontext -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.1.4.RELEASE</version>
</dependency>

此处新手会有疑问,我们为什么要导入这个context呢?

看下官网spring的核心组件有哪些(Core Container中有四个,Beans,Core,Context,SpEL)

我们为什么先选择用Context,因为对于Context来说,你可以理解为Spring既然是一种解决方案,一定是为了解耦而出现,所以它是作用在整个应用上下文,也就是官方文档中强烈建议我们xml设置为applicationContext.xml,我这边不严格对照官网的方式来,我们按照我们最熟悉spring的基础来走,所以我们先引用了Spring的Context包;

3、Spring的配置文件

  • 配置文件放置位置:任意位置,没有硬性要求
  • 配置文件命名:也没有硬性要求,但是官网强烈建议applicationContext.xml

4、Spring核心API

  • ApplicationContext
  1. 作用:Spring提供的ApplicationContext这个工厂,用于对象的创建
  2. 好处:解耦合
  3. 接口类型:屏蔽实现的差异

         非web环境:ClassPathApplicationContext(main unit)

         web环境:XmlWebApplicationContext(这个需要引入spring-web的才会有,因为这个实现是在web应用中)

找到ApplicationContext.java这个类,然后使用Ctrl+H就可以看到这个接口有那些实现类

注意:ApplicationContext这个工厂对象占用大量的内存,所以

  • 不会频繁的创建对象:一个应用只会创建一个工厂对象
  • 既然对象只有一个,那么一定会有涉及到共享资源多线程并发访问,那么也一定是线程安全的(后面解释)

5、程序开发

  • 创建类型,配置文件在resources下建立applicationContext.xml
  • 配置文件添加(前提是要创建一个Person类)
<bean id="person" class="com.doctchen.spring5.entity.Person">

</bean>
  • 测试类
/**
     * 测试ApplicationContext工厂怎么创建对象的
     */
    @Test
    public void test1(){
        ApplicationContext ctx = new ClassPathXmlApplicationContext("/applicationContext.xml");
        Person person = (Person) ctx.getBean("person");
        System.out.println("person = " + person);

    }

6、细节分析

  • 名词解释
    • Spring工厂创建的对象,叫做bean或者组件Component(实际上严格来说,不能称为对象,对象不等于bean,后面分析源码我再详解,这里先做为对象
  • Spring工厂相关的方法
    1. getBean家庭
    2. getBeanDefinitionNames
    3. getBeanNamesForType
    4. containsBeanDefinition
    5. containsBean

  • getBean(String, Class)
Person person = (Person) ctx.getBean("person");
System.out.println("person = " + person);

//通过这种⽅式获得对象,就不需要强制类型转换
Person person = ctx.getBean("person", Person.class);
System.out.println("person = " + person);
  • getBean(Class)
//当前Spring的配置⽂件中 只能有⼀个<bean class是Person类型
Person person = ctx.getBean(Person.class);
System.out.println("person = " + person);
<bean id="person" class="com.doctchen.spring5.entity.Person">
</bean>

<!--  对于getBean(Class),只能有一个class,id也唯一,这里多写一个Person1后,这个api会报错  -->
<bean id="person1" class="com.doctchen.spring5.entity.Person">
</bean>
//getBean(Class)报错
org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.doctchen.spring5.entity.Person' available: expected single matching bean but found 2: person,person1

	at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveNamedBean(DefaultListableBeanFactory.java:1137)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveBean(DefaultListableBeanFactory.java:407)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:341)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:335)
	at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1101)

很明显报错解释,要找一个确定的Person Bean,但是发现有两个Bean,所以Spring懵逼了!!!

  • getBeanDefinitionNames
 //获取的是Spring⼯⼚配置⽂件中所有bean标签的id值person person1 people
String[] beanDefinitionNames = ctx.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
     System.out.println("beanDefinitionName = " +
         beanDefinitionName);
}
<bean id="person" class="com.doctchen.spring5.entity.Person">
</bean>

<bean id="person1" class="com.doctchen.spring5.entity.Person">
</bean>

<bean id="people" class="com.doctchen.spring5.entity.People">
</bean>
  • getBeanNamesForType
//根据类型获得Spring配置⽂件中对应的id值
String[] beanNamesForType = ctx.getBeanNamesForType(Person.class);
for (String id : beanNamesForType) {
   System.out.println("id = " + id);
}
<bean id="person" class="com.doctchen.spring5.entity.Person">
</bean>

<bean id="person1" class="com.doctchen.spring5.entity.Person">
</bean>
  • containsBeanDefinition
//⽤于判断是否存在指定id值的bean,不能判断name的值
if (ctx.containsBeanDefinition("person")) {
    System.out.println("true = " + true);
} else {
    System.out.println("false = " + false);
}
<!--  判断是否存在指定id为person的bean,但是无法判断是否存在指定name为p的bean  -->
<bean id="person" name="p" class="com.doctchen.spring5.entity.Person">
</bean>
  • containsBean
<!--  判断是否存在指定id为person的bean,也可以判断是否存在指定name为p的bean  -->
<bean id="person" name="p" class="com.doctchen.spring5.entity.Person">
</bean>

这两个有细微的差别,就是id都可以判断,后者连name的值也可以判断,对于name和id的区别,我后面再说!


  • 配置文件中的细节注意
    • 只配置class属性
      <bean class="com.doctchen.spring5.entity.Person">

      当我们不写id的时候,spring会不会给我们一个id值?答案是肯定的,我们只需要用上面的api--getBeanDefinitionNames

//打印结果  beanDefinitionName = com.doctchen.spring5.entity.Person#0
String[] beanDefinitionNames = ctx.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
System.out.println("beanDefinitionName = " +
     beanDefinitionName);
}

所以这个名字是有的,如果没有命名的id对应的class有多个,并且我们id没有写,那么spring会默认以此类推1、2、...

<!--
    beanDefinitionName = com.doctchen.spring5.entity.Person#0
    beanDefinitionName = com.doctchen.spring5.entity.Person#1
-->

<bean class="com.doctchen.spring5.entity.Person">
</bean>

<bean class="com.doctchen.spring5.entity.Person">
</bean>

这个应用场景在:如果这个bean只需要使用一次,那么就可以省略id的值,如果这个bean被使用多次,或者被其他的bean引用则需要设置id的值

  • name属性
    • 作用在Spring配置文件中,为bean的对象定义别名(小名)
      相同:ctx.getBean("id|name")--->object
      配置上:<bean id="" class=""/> == <bean name="" class=""/>
    • 区别是
      1. 别名可以定义多个,但是id只有一个
      2. xml的id属性,命名要求,必须以字母,数字,下划线,连字符开头,不能以特殊字符开头,比如/person
      3. 对于name属性命名,没有要求

      但是spring发展到了现在,xml中的bean id,已经没有了限制,读者可以自行去试试

 

7、Spring工厂底层实现原理(简易版)

Spring是可以调用私有的构造方法来创建对象的

8、思考

  • 未来开发过程中,是不是所有的对象都要交给Spring工厂来创建?我们下一章见分晓!!!

有不对的地方,或者需要补充的,直接评论,我把这个文章更加完善下去!!!

 

 

 

  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

风清扬逍遥子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值