Spring的学习与使用

为什么需要学习 spring
1. 最大程度的简化了开发
spring 是一个非常优秀的 java 框架,其目标是为了简化 java 企业级开发, spring 出来已经十几年
了,这期间也一直围绕着这个目标在进行,像后面需要学习的 springmvc springboot
springcloud ,这些技术也都是围绕着简化开发的目标在努力,到目前为止已经做的足够好了,可
以说 spring 除了不能帮助我们实现业务逻辑代码之外,其他的事情 spring 都尽量去帮我们简化了,
使用 spring 可以帮助我们节约大量开发时间。
不使用 spring 的情况下,开发一个项目可能需要 2 个月,用了 spring 可能 1 个月都不需要,你说这样
的技术你想学么?
2. 大量公司使用
目前 99% 的公司使用了 spring ,可以去各大招聘网站看一下, spring 算是必备技能,所以一定要掌
握。
3. 顶级的源码设计
spring 框架源码设计非常优秀,在 java 开源项目中可以说是顶级的,个人到目前为止还没有发现比
spring 代码更优秀的开源项目,所以想提升代码能力的,强烈建议多看看 spring 的源码;关于提升
代码能力的,还可以去看一下 jdk 的源码,也是非常棒的,里面有很多大师的杰作。
Spring 中有 3 个核心的概念: 控制反转 (Ioc) 、依赖注入 (DI) 、面向切面编程 (AOP) spring 中其他的技术
都是依靠 3 个核心的技术建立起来的,所以玩 spring 需要先对这 3 个概念有个深入的理解。
spring 容器
spring 容器的概念,容器这个名字起的相当好,容器可以放很多东西,我们的程序启动的时候会创建
spring 容器,会给 spring 容器一个清单,清单中列出了需要创建的对象以及对象依赖关系, spring 容器
会创建和组装好清单中的对象,然后将这些对象存放在 spring 容器中,当程序中需要使用的时候,可以
到容器中查找获取,然后直接使用。
IOC :控制反转
使用者之前使用 B 对象的时候都需要自己去创建和组装,而现在这些创建和组装都交给 spring 容器去给完
成了,使用者只需要去 spring 容器中查找需要使用的对象就可以了;这个过程中 B 对象的创建和组装过程
被反转了,之前是使用者自己主动去控制的,现在交给 spring 容器去创建和组装了,对象的构建过程被
反转了,所以叫做控制反转; IOC 是是面相对象编程中的一种设计原则,主要是为了降低系统代码的耦
合度,让系统利于维护和扩展。
DI :依赖注入
依赖注入是 spring 容器中创建对象时给其设置依赖对象的方式,比如给 spring 一个清单,清单中列出了
需要创建 B 对象以及其他的一些对象(可能包含了 B 类型中需要依赖对象),此时 spring 在创建 B 对象的
时候,会看 B 对象需要依赖于哪些对象,然后去查找一下清单中有没有包含这些被依赖的对象,如果有
就去将其创建好,然后将其传递给 B 对象;可能 B 需要依赖于很多对象, B 创建之前完全不需要知道其他
对象是否存在或者其他对象在哪里以及被他们是如何创建,而 spring 容器会将 B 依赖对象主动创建好并将
其注入到 B 中去,比如 spring 容器创建 B 的时候,发现 B 需要依赖于 A ,那么 spring 容器在清单中找到 A
定义并将其创建好之后,注入到 B 对象中。
总结
1. IOC 控制反转,是一种设计理念,将对象创建和组装的主动控制权利交给了 spring 容器去做,控制
的动作被反转了,降低了系统的耦合度,利于系统维护和扩展, 主要就是指需要使用的对象的组装
控制权被反转了,之前是自己要做的,现在交给 spring 容器做了
2. DI 依赖注入,表示 spring 容器中创建对象时给其设置依赖对象的方式,通过某些注入方式可以让系
统更灵活,比如自动注入等可以让系统变的很灵活,这个后面的文章会细说。
3. spring 容器:主要负责容器中对象的创建、组装、对象查找、对象生命周期的管理等等操作。
4. 下一篇开始详细讲解 spring 的使用了
IOC 容器
IOC 容器是具有依赖注入功能的容器,负责 对象的实例化、对象的初始化,对象和对象之间依赖关系配
置、对象的销毁、对外提供对象的查找 等操作,对象的整个生命周期都是由容器来控制。我们需要使用
的对象都由 ioc 容器进行管理,不需要我们再去手动通过 new 的方式去创建对象,由 ioc 容器直接帮我们
组装好,当我们需要使用的时候直接从 ioc 容器中直接获取就可以了。
那么 spring ioc 容器是如何知道需要管理哪些对象呢?
需要我们给 ioc 容器提供一个配置清单,这个配置 支持 xml 格式 java 注解的方式 ,在配置文件中列出需
要让 ioc 容器管理的对象,以及可以指定让 ioc 容器如何构建这些对象,当 spring 容器启动的时候,就会去
加载这个配置文件,然后将这些对象给组装好以供外部访问者使用。
这里所说的 IOC 容器也叫 spring 容器。
Bean 概念
spring 容器管理的对象统称为 Bean 对象。 Bean 就是普通的 java 对象,和我们自己 new 的对象其实是一
样的,只是这些对象是由 spring 去创建和管理的,我们需要在配置文件中告诉 spring 容器需要创建哪些
bean 对象,所以需要先在配置文件中定义好需要创建的 bean 对象,这些配置统称为 bean 定义配置元数
据信息, spring 容器通过读取这些 bean 配置元数据信息来构建和组装我们需要的对象。
Spring 容器使用步骤
1. 引入 spring 相关的 maven 配置
2. 创建 bean 配置文件,比如 bean xml 配置文件
3. bean xml 文件中定义好需要 spring 容器管理的 bean 对象
4. 创建 spring 容器,并给容器指定需要装载的 bean 配置文件,当 spring 容器启动之后,会加载这些配
置文件,然后创建好配置文件中定义好的 bean 对象,将这些对象放在容器中以供使用
5. 通过容器提供的方法获取容器中的对象,然后使用
Spring 容器对象
spring 内部提供了很多表示 spring 容器的接口和对象,我们来看看比较常见的几个容器接口和具体的实
现类。
容器有有形的容器和无形的容器
有形的容器:.xml配置文件
无形的容器:个人认为是在spring配置里
容器创建 bean 实例有多少 种?
1. 通过反射调用构造方法创建 bean 对象
2. 通过静态工厂方法创建 bean 对象
3. 通过实例工厂方法创建 bean 对象
4. 通过 FactoryBean 创建 bean 对象
通过静态工厂方法创建 bean 对象
public class UserStaticFactory {

    public static UserModel buildUser1(){
        System.out.println(UserStaticFactory.class+".buildUser1");
        return new UserModel();
    }

    public static UserModel buildUser2(){
        System.out.println(UserStaticFactory.class+".buildUser1");
        return new UserModel();
    }
}
<bean id="createBeanByStaticFactoryMethod1"
class="com.ljy.lijinyuanspringboot.pojo.UserStaticFactory"
 factory-method="buildUser1">
        <property name="name" value="ljy"/>
</bean>

<bean id="createBeanByStaticFactoryMethod2"
          class="com.ljy.lijinyuanspringboot.pojo.UserStaticFactory"
          factory-method="buildUser2">
        <constructor-arg name="name" value="name"/>
        <constructor-arg name="age" value="21"/>
</bean>
class :指定静态工厂完整的类名
factory-method :静态工厂中的静态方法,返回需要的对象。
constructor-arg 用于指定静态方法参数的值,用法和上面介绍的构造方法一样。
通过实例工厂方法创建 bean 对象
public class UserFactory {
    public  UserModel buildUser1(){
        System.out.println("非静态方法");
        return new UserModel();
    }

    public  UserModel buildUser2(String name,int age){
        return new UserModel(name,age);
    }
}

实例化工厂要先有一个工厂的实例:

<!--通过实例工厂创建bean对象-->
    <bean id="userFactory" class="com.ljy.lijinyuanspringboot.pojo.UserFactory"/>
    
    <bean id="createBeanByBeanMethod1"
          factory-bean="userFactory"
          factory-method="buildUser1">

    </bean>

    <bean id="createBeanByBeanMethod2"
          factory-bean="userFactory"
          factory-method="buildUser2">
        <constructor-arg name="name" value="ljy"/>
        <constructor-arg name="age" value="18"/>
    </bean>

在测试类中通过getBean()就可以通过id调用了

bean 作用域 scope 详解
<bean id="" class="" scope="作用域" />
singleton
scope 的值设置为 singleton 的时候,整个 spring 容器中只会存在一个 bean 实例,通过容器多次查找
bean 的时候(调用 BeanFactory getBean 方法或者 bean 之间注入依赖的 bean 对象的时候),返回的
都是同一个 bean 对象, singleton scope 的默认值,所以 spring 容器中默认创建的 bean 对象是单例的,
通常 spring 容器在启动的时候,会将 scope singleton bean 创建好放在容器中(有个特殊的情况,当
bean lazy 被设置为 true 的时候,表示懒加载,那么使用的时候才会创建),用的时候直接返回。
单例 bean 使用注意
单例 bean 是整个应用共享的,所以需要考虑到线程安全问题,之前在玩 springmvc 的时候,
springmvc controller 默认是单例的,有些开发者在 controller 中创建了一些变量,那么这些变量实
际上就变成共享的了, controller 可能会被很多线程同时访问,这些线程并发去修改 controller 中的共
享变量,可能会出现数据错乱的问题;所以使用的时候需要特别注意。
prototype
如果 scope 被设置为 prototype 类型的了,表示这个 bean 是多例的,通过容器每次获取的 bean 都是不同
的实例,每次获取都会重新创建一个 bean 实例对象。
多例 bean 使用注意
多例 bean 每次获取的时候都会重新创建,如果这个 bean 比较复杂,创建时间比较长,会影响系统的性
能,这个地方需要注意。
request
当一个 bean 的作用域为 request ,表示在一次 http 请求中,一个 bean 对应一个实例;对每个 http 请求都
会创建一个 bean 实例, request 结束的时候,这个 bean 也就结束了, request 作用域用在 spring 容器的
web 环境中,这个以后讲 springmvc 的时候会说, spring 中有个 web 容器接口 WebApplicationContext
这个里面对 request 作用域提供了支持,配置方式:
session
这个和 request 类似,也是用在 web 环境中, session 级别共享的 bean ,每个会话会对应一个 bean
例,不同的 session 对应不同的 bean 实例
application
全局 web 应用级别的作用于,也是在 web 环境中使用的,一个 web 应用程序对应一个 bean 实例,通常情
况下和 singleton 效果类似的,不过也有不一样的地方, singleton 是每个 spring 容器中只有一个 bean
例,一般我们的程序只有一个 spring 容器,但是,一个应用程序中可以创建多个 spring 容器,不同的容
器中可以存在同名的 bean ,但是 sope=aplication 的时候,不管应用中有多少个 spring 容器,这个应用中
同名的 bean 只有一个。
总结
1. spring 容器自带的有 2 种作用域,分别是 singleton prototype ;还有 3 种分别是 spring web 容器环
境中才支持的 request session application
2. singleton spring 容器默认的作用域,一个 spring 容器中同名的 bean 实例只有一个,多次获取得
到的是同一个 bean ;单例的 bean 需要考虑线程安全问题
3. prototype 是多例的,每次从容器中获取同名的 bean ,都会重新创建一个;多例 bean 使用的时候需
要考虑创建 bean 对性能的影响
4. 一个应用中可以有多个 spring 容器
5. 自定义 scope 3 个步骤,实现 Scope 接口,将实现类注册到 spring 容器,使用自定义的 sope
依赖注入之手动注入
spring 依赖注入
spring 中依赖注入主要分为手动注入和自动注入,本文我们主要说一下手动注入,手动注入需要我们明
确配置需要注入的对象。
刚才上面我们回顾了,将被依赖方注入到依赖方,通常有 2 种方式:构造函数的方式和 set 属性的方式,
spring 中也是通过这两种方式实现注入的,下面详解 2 种方式。
通过构造器注入
构造器的参数就是被依赖的对象,构造器注入又分为 3 种注入方式:
根据构造器参数索引注入
根据构造器参数类型注入
根据构造器参数名称注入
<bean id="diByConstructorParamIndex" 
class="com.javacode2018.lesson001.demo5.UserModel"> <constructor-arg index="0" value="路人甲Java"/>
 <constructor-arg index="1" value="上海市"/>
 </bean>

constructor-arg 用户指定构造器的参数
index :构造器参数的位置,从 0 开始
value :构造器参数的值, value 只能用来给简单的类型设置值, value 对应的属性类型只能为
byte,int,long,float,double,boolean,Byte,Long,Float,Double, 枚举, spring 容器内部注入的时候会
value 的值转换为对应的类型。
根据构造器参数类型注入
<bean id="diByConstructorParamType"
 class="com.javacode2018.lesson001.demo5.UserModel"> 
<constructor-arg type="参数类型" value="参数值"/> 
<constructor-arg type="参数类型" value="参数值"/>
 </bean>
constructor-arg 用户指定构造器的参数
type :构造函数参数的完整类型,如: java.lang.String,int,double
value :构造器参数的值, value 只能用来给简单的类型设置值
根据构造器参数名称注入
<bean id="diByConstructorParamName" 
class="com.javacode2018.lesson001.demo5.UserModel"> 
<constructor-arg name="参数类型" value="参数值"/>
 <constructor-arg name="参数类型" value="参数值"/> 
</bean>
constructor-arg 用户指定构造器的参数
name :构造参数名称
value :构造器参数的值, value 只能用来给简单的类型设置值
参数名称可能不稳定的问题, spring 提供了解决方案,通过 ConstructorProperties 注解来定义参数的
名称,将这个注解加在构造方法上面 ,如下:
@ConstructorProperties({"第一个参数名称", "第二个参数的名称",..."第n个参数的名称"})
 public 类名(String p1, String p2...,参数n) { }
@ConstructorProperties({"name", "desc"})
 public CarModel(String p1, String p2) {
 this.name = p1; this.desc = p2; 
}

这样就可以通过

constructor-arg name="desc"

constructor-arg name="name"

引用了

setter 注入
通常情况下,我们的类都是标准的 javabean javabean 类的特点:
属性都是 private 访问级别的
属性通常情况下通过一组 setter (修改器)和 getter (访问器)方法来访问
setter 方法,以 set 开头,后跟首字母大写的属性名,如: setUserName ,简单属性一般只有一
个方法参数,方法返回值通常为 void;
getter 方法,一般属性以 get 开头,对于 boolean 类型一般以 is 开头,后跟首字母大写的属性
名,如: getUserName isOk
spring 对符合 javabean 特点类,提供了 setter 方式的注入,会调用对应属性的 setter 方法将被依赖的对象
注入进去。
其他类型注入
public class Test {
    int age;
    String str;
    String [] s;
    List<Object> list;
    Map map;
    Set set;

    public List<Object> getList() {
        return list;
    }

    public void setList(List<Object> list) {
        this.list = list;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getStr() {
        return str;
    }

    public void setStr(String str) {
        this.str = str;
    }

    public String[] getS() {
        return s;
    }

    public void setS(String[] s) {
        this.s = s;
    }



    public Map getMap() {
        return map;
    }

    public void setMap(Map map) {
        this.map = map;
    }

    public Set getSet() {
        return set;
    }

    public void setSet(Set set) {
        this.set = set;
    }

    @Override
    public String toString() {
        return "Test{" +
                "age=" + age +
                ", str='" + str + '\'' +
                ", s=" + Arrays.toString(s) +
                ", list=" + list +
                ", map=" + map +
                ", set=" + set +
                '}';
    }
}

<bean id="test" class="com.ljy.lijinyuanspringboot.pojo.Test">
        <property name="age" value="21"/>
        <property name="str" value="ljy"/>
        <property name="list">
            <list>
                <value>Spring</value>
                <value>123</value>
            </list>
        </property>
        <property name="map">
            <map>
                <entry key="1" value="1"></entry>
                <entry key="2" value="22"></entry>
            </map>
        </property>
        <property name="s">
            <array>
                <value>123</value>
                <value>456</value>
                <value>abc</value>
            </array>
        </property>
        <property name="set">
            <set>
                <value>123</value>
                <value>abc</value>
            </set>
        </property>
    </bean>
public static void main(String[] args) {
        ApplicationContext context=new ClassPathXmlApplicationContext("bean.xml");
        Test test= (Test) context.getBean("test");
        System.out.println(test);
    }

运行后:

Test{age=21, str='ljy', s=[123, 456, abc], list=[Spring, 123], map={1=1, 2=22}, set=[123, abc]}
总结
1. 主要讲解了 xml bean 的依赖注入,都是采用硬编码的方式进行注入的,这种算是手动的方
2. 注入普通类型通过 value 属性或者 value 元素设置注入的值;注入对象如果是容器的其他 bean 的时 候,需要使用 ref 属性或者 ref 元素或者内置 bean 元素的方式
3. 还介绍了其他几种类型 List Set Map 、数组 的注入,多看几遍加深理解
4. 后面将介绍 spring 为我们提供的更牛逼的自动注入
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值