Spring系列-SpringBase+IOC

Spring

一.前言

带着这些去验证自己把!

定义?思想(重点)?

干啥的?作用于哪一方面?

基本配置,基本操作?

二.个人理解

  • spring作用?
  • 使现有技术更加容易使用,本身是一个大杂烩,整合了现有的技术框架
  • 从它的容器中可以拿出很多数据!

三.核心要素

  • IOC 控制反转(重点)–面试高频
    • 依赖注入 ID
  • Spring的配置文件(重点,难点,要记)
  • AOP 面向切面编程(重点,难点,面试高频)
    • 代理模式(重点,难点)
  • 事务ACID,声明式的事务特性
  • 整合Mybatis
  • 使用注解开发(重点
  • 设计模式(13种)

四.优点

  • Spring 一个开源的免费的框架(容器)

  • Spring 一个轻量级的,非入侵式的框架。

  • 控制反转(IOC),面向切面编程(AOP)

  • 支持事务处理,对框架整合的支持。

  • 总:spring 就是一个轻量级的控制反转(IOC)和面向切面编程(AOP)的框架

五.介绍

  • 7大模块

  • SpringBoot

    • 一个快速开发的脚手架
    • 基于SpringBoot可以快速的开发单个微服务
    • 约定大于配置
  • SpringCloud

    • SpringCloud是属于SpringBoot实现的
  • 现在大多数公司都在使用SpringBoot进行快速开发

    • 学习SpringBoot的前提,完全掌握Spring及SpringMVC
  • 弊端:发展太久之后,违背了原来的理论。配置很繁琐,人称“配置地狱”

六.IOC—说白了,空调VS电热扇

六.1.IOC理论推导

  • 1.UserDao 接口

  • 2.UserDaoImpl 实现类

  • 3.UserService 业务接口

  • 4.UserServiceImpl 业务实现类

  • 在我们之前的业务中,用户的需求可能会影响我们原来的代码,我们需要根据用户的需求去修改源代码!
    如果程序代码量特别大,修改一次的成本就会特别昂贵

  • 我们使用set接口实现,已经发生了革命性的变化

    • 目的:将程序的控制权由程序(死值)变成了使用者(随用随调)
     // 程序主动创建对象,每次换东西都得这改
    private UserDao userDao1 = new UserDaoImpl();  // 调用时:::每次都得换
    private UserDao userDao1 = new UserDaoMysqlImpl(); // 调用时:::每次都得换
    
    
     // 程序被动创建,控制权封装为一个方法,由使用者调用方法进行
    private UserDao userDao;  // Like-a
    // 使用set进行动态实现值的注入
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

  • 之前,程序是主动创建对象!控制权在程序猿(死代码中)手上!
  • 使用set注入后,程序不再具有主动性,而是被动的接收对象。

六.2.思想:

  • 想不通的可以想想设置(手机等等)—-根据自己的喜好设置一些功能,控制权在使用者的手上,,,没有设置功能的就是程序主动性的创建对象

  • 或者空调(冷热一体,给你个遥控器可调整冷热。。) 而电热扇,电风扇—只能死死的使用热,冷

  • 说到底,目的是为了提高了用户的体验,用户可以依据自己的喜好来,而不是按照装好的东西来使用

  • 这种思想,从本质上解决了问题,我们程序员不用去管理对象的创建了,而是提供一个方法(遥控器),系统耦合性大大降低
    可以更加的专注于业务上!—这是IOC原型

六.3.IOC本质(回归IT)

  • 控制反转IOC(Inversion of Control) DI(依赖注入)是实现IOC的一种方法。

    • 没有IOC的程序,我们使用的是面向对象的编程,对象的创建与对象间的依赖关系完全硬编码在程序中,对象的创建由程序自己控制,
      控制反转后将对象的创建转移到第三方。
    • IOC描述的是对象的事情,DI描述的是对象属性的事情
  • 采用XML方式配置Bean的时候,Bean的定义信息是和实现分离的,而采用注解的方式可以将两者结合在一体,Bean的定义信息直接以注解的形式定义在实现类中,
    从而达到了零配置的目的

    • 使用XML的时候,它所作的就是创对象,对象属性赋值—而类的信息还是由类完成(构造器,属性,方法的定义)

  • 控制反转是一种通过描述(XML或注解)并通过第三方去生产或获取特定对象的方式。在Spring中实现控制反转的是IOC容器。其实现方法是依赖注入(DI)

Spring code start

一.环境需求

  • 1.mavern管理

  • 2.导入Spring包就可以了

          <!-- //mvnrepository.com/artifact/org.springframework/spring-webmvc -->
          <dependency>
              <groupId>org.springframework</groupId>
              <artifactId>spring-webmvc</artifactId>
              <version>5.3.9</version>
          </dependency>
          
          
          <dependency>
              <groupId>org.springframework</groupId>
              <artifactId>spring-jdbc</artifactId>
              <version>5.3.9</version>
          </dependency>
      
    

二.springBean

  • spring 容器,就类似于婚介场,所有数据都在里面。 启动之前就注册了xml

三个Bean要用的标签

  • 1.Bean的配置
     <!--
     id :bean的唯一标识符
     class bean对象的全限定名:包名+类型
     name:别名,而且name更高级,可以取多个别名,使用空格,逗号等等都可以区分
     -->
 
     <bean id = "userT" class="com.zjz.pojo.UserT" name="userT2,userT3">
         <property name="name" value="zjz"/>
     </bean>
 
  • 2.别名

    • 推荐使用bean里的name

          <!--
            id :bean的唯一标识符
            class bean对象的全限定名:包名+类型
           name:别名,而且name更高级,可以取多个别名,使用空格,逗号等等都可以区分
         -->
        <bean id = "userT" class="com.zjz.pojo.UserT" name="userT2,userT3">
        
        <!--如果添加了别名,我们也可以通过别名获取到这个对象-->
        <alias name="user" alias="adafadfafadf"/>    
      
  • 3.import

    • 一般用于开发团队使用,它可以将多个配置文件,导入合并为一个

  • 假设,现在项目组有多个人开发,这三人负责不同的类,不同的类需要注册在不同的bean,我们可以利用import将所有人的beans.xml合并为一个总的

    • 张三
    • 李四
    • 王五
    • applicationContext.xml(核心)
  • 使用的时候,直接使用总的配置就好了

三. spring IOC

三.1.简单认识一下,构造器注入

  • 1.pojo

    • 定义类的属性,以及方法
      
      public class Hello {
      private String str;
    
          public String getStr() {
              return str;
          }
      
          public void setStr(String str) {
              this.str = str;
          }
    
    
          @Override
          public String toString() {
              return "Hello{" +
                      "str='" + str + '\'' +
                      '}';
          }
      }
    
    
  • 2.beans.xml(核心!)

    • 将对象的创建,对象属性的赋值,在xml中完成
          <?xml version="1.0" encoding="UTF-8"?>
        <beans xmlns="//www.springframework.org/schema/beans"
        xmlns:xsi="//www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="//www.springframework.org/schema/beans
        //www.springframework.org/schema/beans/spring-beans.xsd">
        <!--使用Spring来创建对象,在Spring这些都称为Bean-->
        <!--bean就是java对象 , 由Spring创建和管理-->
        <!--
                    类型   变量名 = new 类型();
          before:   Hello hello =  new Hello();
            now :  id = 变量名   class = new 的对象;   property 相当于给对象的属性set值
        -->
    
    
          <!--如果要使用其它对象的属性时:
              第一,要有本类调用其它类时的定义: private UserDao userDao;  // Like-a
              第二:配置 ---   <property name="userDao" ref="userDaoImpl"/>
              property中
              ref :引用spring 容器创建好的对象
              value: 具体的值,基本的数据类型
           -->
    
    
            <bean id="hello" class="com.zjz.pojo.Hello">
                <property name="str" value="Spring"/>
            </bean>
        </beans>
          
    
  • 3.MyTest

    • 获取容器(上下文),然后取数据
    
      public class MyTest {
          public static void main(String[] args) {
      
              // 获取Spring的上下文对象!
              ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
              // 我们的对象,现在都在spring中管理,我们要使用,直接从里面取出来就行
      
              Hello hello = (Hello) context.getBean("hello");
      
              System.out.println(hello.toString());
          }
      }
    
    
    

三.2.注意:

怎么引用其它对象??—目前手动的–

  • 怎么引用一个其它的pojo或者service或者Dao—

使用ref 首先得把ref要用到的Bean注册上!!要不报错

注:定义,声明都还是在中进行,IOC它负责的只是创对象

    <bean id="userDaoImpl" class="com.zjz.dao.UserDaoImpl">
    <bean id="userServiceImpl" class="com.zjz.service.UserServiceImpl">
        <!--ref :引用spring 容器创建好的对象
            value: 具体的值,基本的数据类型
         -->
        <property name="userDao" ref="userDaoImpl"/>
        // 它的功能就将其它类的属性||对象||其它--给引入到本类中
    </bean>
    
    
     
     private UserDao userDao;  // Like-a
     

三.3思考

  • Hello 对象是谁创建的 ?

    • 【 hello 对象是由Spring创建的 】
  • Hello 对象的属性是怎么设置的 ?

    • 【hello 对象的属性是由Spring容器设置的 】
  • 这个过程就叫控制反转 :

    • 控制 : 谁来控制对象的创建, 传统应用程序的对象是由程序本身控制创建的, 使用Spring后, 对象是由Spring来创建的

    • 反转 : 程序本身不创建对象, 而变成被动的接收对象 .

    • 依赖注入 : 就是利用set方法来进行注入的.

    • IOC是一种编程思想,由主动的编程变成被动的接收

  • 我们不需要去程序中去改动了,要实现不同的操作,只需要在xml中配置文件进行修改,所谓IOC,
    一句话搞定:对象由Spring来创建,管理,装配

四.IOC创建对象的方式

同java一样啊,构造器造对象

构造器注入

  • 1.使用无参构建对象,默认

  • 2.假设要使用有参构造创建对象 – 此时对象是有属性的对象

  • 1.下标赋值

      <!-- 第一种,下标赋值-->
      <!--注意是构造器参数种的下标-->
      
         <bean id="user" class="com.zjz.pojo.User">
             <constructor-arg index="0" value="zjzHHH"/>
         </bean>
    
    
  • 2.类型赋值

        <!-- 第一种,下标赋值-->
        <!--
            <bean id="user" class="com.zjz.pojo.User">
                <constructor-arg index="0" value="zjzHHH"/>
            </bean>
        -->
        
        <!--第二种,通过类型创建,两个方法都是Sting就不行了,不建议使用!-->
        <!--
        <bean id="user" class="com.zjz.pojo.User">
            <constructor-arg type="java.lang.String" value="zjz"></constructor-arg>
        </bean>
        -->
    
  • 3.参数名– 重点,使用

      <!--第三种,直接通过参数名来设置-->
      <bean id="user" class="com.zjz.pojo.User">
          <constructor-arg name="name" value="zjz"/>
      </bean>
    
    
    
  • 总结

    • 在配置文件加载的时候,容器中的管理对象就已经初始化了

五 DI依赖注入

依赖注入 – 依赖:bean对象的创建依赖于容器!
注入:bean对象的所有属性,由容器来注入!

说到底,对象的赋值,由容器来进行!

  • 五.1.构造器注入–

    • 特征,有参的话,直接将构造器的参数赋值。。无参你没的办法啊,只能依托property
    • 原理:构造器参数注入。
    • 缺点:只能对有参的构造器的参数进行操作,非常不方便
      
          <!--使用Spring来创建对象,在Spring这些都称为Bean-->
          <!--bean就是java对象 , 由Spring创建和管理-->
          <!--
                      类型   变量名 = new 类型();
            before:   Hello hello =  new Hello();
              now :  id = 变量名   class = new 的对象;   property 相当于给对象的属性set值
          -->
      
            // 无参的
              <bean id="user" class="com.zjz.pojo.User"/>
          // 有参的
          <!--第三种,直接通过参数名来设置-->
            <bean id="user" class="com.zjz.pojo.User">
                <constructor-arg name="name" value="zjz"/>
            </bean>
      
      
      
    
  • 五.2.set注入(重要)

    • 特征—各种property
    • 原理:实际上是在构造器注入的基础上(对象),对属性进行赋值操作
    • 依赖注入 – 依赖:bean对象的创建依赖于容器!
      注入:bean对象的所有属性,由容器来注入!
    • 环境搭建–
      • 1.复杂类型
      • 2.真实测试对象
        <?xml version="1.0" encoding="UTF-8"?>
        <beans xmlns="//www.springframework.org/schema/beans"
               xmlns:xsi="//www.w3.org/2001/XMLSchema-instance"
               xsi:schemaLocation="//www.springframework.org/schema/beans
               //www.springframework.org/schema/beans/spring-beans.xsd">
        
            <bean id="address" class="com.zjz.pojo.Address"/>
            <bean id="student" class="com.zjz.pojo.Student">
        
                <!--第一种,普通值注入,直接使用value-->
                <property name="name" value="zjz"></property>
        
                <!--第二种,bean注入 ref-->
                <property name="address" ref="Address"/>
        
                <!-- 数组注入,ref-->
                <property name="books">
                    <array>
                        <value>博客</value>
                        <value>Gitee</value>
                        <value>DIY博客</value>
                    </array>
                </property>
        
        
                <!--list  -->
                <property name="hobbys">
                    <list>
                        <value>敲代码</value>
                        <value>做算法</value>
                        <value>学知识</value>
                    </list>
                </property>
        
                <!--Map-->
                <property name="card">
                    <map>
                        <entry key="身份证" value="HHH1"/>
                        <entry key="银行卡" value="HHH2"/>
                        <entry key="门禁卡" value="HHH3"/>
                    </map>
                </property>
        
                <!--Set-->
                <property name="game">
                    <set>
                        <value>LOL</value>
                        <value>CF</value>
                        <value>Study</value>
                    </set>
                </property>
        
              <!-- null-->
                <property name="wife">
                    <null></null>
                </property>
        
        
                <!--properties-->
                <property name="info">
                    <props>
                        <prop key="driver"></prop>
                        <prop key="url"></prop>
                        <prop key="username"></prop>
                        <prop key="password"></prop>
                    </props>
        
                </property>
        
        
            </bean>
        
        
        </beans>
    
    
  • 五.3.拓展方式注入

  • p命名 c命名

    • 作用:方便一些操作
    • 原理:在构造器的基础上,使用一些其它方式直接set值
    • 使用注意:要导入约束–xmlns
        <?xml version="1.0" encoding="UTF-8"?>
        <beans xmlns="//www.springframework.org/schema/beans"
               xmlns:xsi="//www.w3.org/2001/XMLSchema-instance"
               xmlns:p="//www.springframework.org/schema/p"
               xmlns:c="//www.springframework.org/schema/c"
               xsi:schemaLocation="//www.springframework.org/schema/beans
               //www.springframework.org/schema/beans/spring-beans.xsd">
        
        
            <!-- p 命名空间注入,可以直接注入属性的值:property-->
            <bean id="user" class="com.zjz.pojo.User" p:name="user1" p:age="18"/>
        
        
            <!--c命名空间注入,通过构造器注入,construct-args -->
            <bean id="user2" class="com.zjz.pojo.User" c:name="user2" c:age="99"></bean>
        
        </beans>
    
    

六.Bean的作用域

  • 六.1.单例模式(Spring默认机制)

    • 目的:减少资源浪费,多个操作从同一容器取值
    • 缺点:并发可能出事
    • <bean id="user" class="com.zjz.pojo.User" p:name="user1" p:age="18" scope="singleton"/>
  • 六.2.原型模式

    • 目的:每次从容器get的时候都会产生一个新的对象!
    • 缺点:特别浪费资源
    • <!-- scope 为prototype 原型模式 --> <bean id="user" class="com.zjz.pojo.User" p:name="user1" p:age="18" scope="prototype"/>
  • 六.3.其余的request,session,application,,,这些只能在web开发中使用到!

七.Bean的装配

三种装配方式

  • 1.在XML中显示的配置(手动)

  • 2.在java中显示配置

  • 3.隐式的自动装配(自动)

  • xml使用注意:

    • ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
    • 这句话会解析xml文件所有的东西,包括不需要用到的—经Test:将其他bean放入进去,然后构造器out下
    • 如何避免,,,你可以将这个方法封装一层。。。

七.一.xml中装配

  • 推荐不使用自动装配xml配置,而使用注解

1.手动装配,

  • XML中每一个对象,每一个属性,,都手动配(property,或构造器参数)—之前练习中

2.自动装配
依据:Bean的特性—

实现方式—Spring满足bean依赖的一种方式

  • Spring的自动装配需要从两个角度来实现,或者说是两个操作:
      1. 组件扫描(component scanning):spring会自动发现应用上下文中所创建的bean;
      • 疑问? 哪里的上下文???—已经在bean容器中的东西!!!
      • 所以,还是得把东西塞进去把~~
      1. 自动装配(autowiring):spring自动满足bean之间的依赖,也就是我们说的IoC/DI;

基于set方法的自动装配:

  • 共同:都是要走set方法的,没set方法怎么弄数据。。。当然,之前也说了,构造器也可哈~

  • byName

    • 依据:类中set方法 以及xmlBean的id
    • 操作:装配bean用id的方式。。。编写主要bean 使用autowire的byName
    • 结果:成功使用上下文中含有 id 中的内容,映射到本身要输出的
    • 缺点:xml中id必须和类中set后的名字必须一致,否则失败
        <!--
          byName: 会自动在上下文中查找,和自己对象set方法后面值对应的beanId
         -->
          <!--手动装配,id的形式,cat,dog 都是构造器的形式-->
          <bean id="cat" class="com.zjz.pojo.Cat"/>
          <bean id="dog" class="com.zjz.pojo.Dog"/>
        
        <!--此时Test 会将cat dog 都打印出来-->
        <bean id="people" class="com.zjz.pojo.People" autowire="byName">
            <property name="name" value="zjz"/>
        </bean>
    
    
  • byType

    • 依据:类中set前面的类型去查找 xml中配上class
    • 操作: 编写主要bean 使用autowire的byType
    • 缺点:只能针对类型返回,针对的类型只能有一个,多了失败
    
    
        <!--byType : 会自动在上下文中查找,和自己对象属性类型相同的bean-->
        <!--手动装配,cat,dog 都是构造器的形式--> 
         <bean class="com.zjz.pojo.Dog"/>
        <bean class="com.zjz.pojo.Cat"/>
    
         <!--此时Test 会将cat dog 都打印出来-->
        <bean id="people" class="com.zjz.pojo.People" autowire="byType">
            <property name="name" value="zjz"></property>
        </bean>
    
    
    

七.二.使用注解—实现自动装配

  • jdk1.5支持的,Spring2.5就支持了

  • 七.二.1.准备工作:

      1. 在spring配置文件中引入context文件头–三句话
      • 只需要在原有的基础上复制过来改下就好了
      1. 开启属性注解支持!(重要!)
      1. 在spring配置文件中引入context文件头
     <beans xmlns="//www.springframework.org/schema/beans"
         xmlns:xsi="//www.w3.org/2001/XMLSchema-instance"
         xmlns:context="//www.springframework.org/schema/context"  // 第一句
         xsi:schemaLocation="//www.springframework.org/schema/beans
         //www.springframework.org/schema/beans/spring-beans.xsd
         //www.springframework.org/schema/context     // 第二句
         //www.springframework.org/schema/context/spring-context.xsd">  // 第三句
    
      2.开启属性注解支持!
      <context:annotation-config/> 
    
    
  • 七.二.2. @Autowired

三个注解 都spring的— @Autowired @Qualifier @Nullable 搭配解决各种问题

用在主类导入子类的字段,方法上(Has-a)

  • 1.使用::查看源码–

        @Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
        @Retention(RetentionPolicy.RUNTIME)
        @Documented
        public @interface Autowired {
            boolean required() default true;
        }
    
  • 可以加的位置有字段,方法,参数(构造器使用)—括号内可以写required=true(default)||false

  • false 就是这里可以为null 同 @Nullable

    1. 机制;
    • 1.优先 byType 其次 byName—-可查看源码beans\factory\support\DefaultListableBeanFactory.class

    • 2.如果多个对象,多个类型怎么处理???
      • 使用@Qualifier(value="value")来指定bean的id值 — Qualifier不能单独使用
  • 3.使用AutoWired我们就可以不用编写set方法了,前提是你这个自动装配的属性在IOC(spring)容器中存在

  • 前提–你得确保是引入对应的bean

  • 使用@Nullable 标注一个字段,说明这个字段可以为null,不会null指针

  • 特别的是java的注解 同样可以完成自动装配 @Resource

@Autowired与@Resource异同

    1. @Autowired与@Resource都可以用来装配bean。都可以写在字段上,或写在setter方法上。
    1. @Autowired默认按类型装配(属于spring规范),默认情况下必须要求依赖对象必须存在,如果
      要允许null 值,可以设置它的required属性为false,如:@Autowired(required=false) ,如果我
      们想使用名称装配可以结合@Qualifier注解进行使用
    1. @Resource(属于J2EE复返),默认按照名称进行装配,名称可以通过name属性进行指定。如果
      没有指定name属性,当注解写在字段上时,默认取字段名进行按照名称查找,如果注解写在
      setter方法上默认取属性名进行装配。 当找不到与名称匹配的bean时才按照类型进行装配。但是
      需要注意的是,如果name属性一旦指定,就只会按照名称进行装配。
  • 它们的作用相同都是用注解方式注入对象,但执行顺序不同。@Autowired先byType,@Resource先 byName。

    • 为啥@Autowired快,,因为名字肯定比类型多–
    • 思想,先判断少的再判断多的,提高速率 — 两层for也是

总:

————————-更多java学习: //zhangjzm.gitee.io/self_study