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包就可以了

          <!-- https://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="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://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="http://www.springframework.org/schema/beans"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xsi:schemaLocation="http://www.springframework.org/schema/beans
               http://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="http://www.springframework.org/schema/beans"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xmlns:p="http://www.springframework.org/schema/p"
               xmlns:c="http://www.springframework.org/schema/c"
               xsi:schemaLocation="http://www.springframework.org/schema/beans
               http://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="http://www.springframework.org/schema/beans"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns:context="http://www.springframework.org/schema/context"  // 第一句
         xsi:schemaLocation="http://www.springframework.org/schema/beans
         http://www.springframework.org/schema/beans/spring-beans.xsd
         http://www.springframework.org/schema/context     // 第二句
         http://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學習: https://zhangjzm.gitee.io/self_study


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM