主頁 > 後端開發 > ??六萬字《Spring框架從入門到精通》(建議收藏)??

??六萬字《Spring框架從入門到精通》(建議收藏)??

2021-09-07 08:13:26 後端開發

?? Spring

代碼:https://github.com/Donkequan/Spring-Study

?? 希望各位博友三連+關注!!!

1、簡介

spring理念:是現有的技術更加容易使用,本身是一個大雜燴,

  • SSH:Struct2 + Spring + Hibernate
  • SSM: SpringMVC + Spring + Mybatis

官網: https://spring.io/projects/spring-framework#overview

官方下載: https://repo.spring.io/release/org/springframework/spring/

GitHub: https://github.com/spring-projects/spring-framework

1.1、匯入包

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

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


1.2、優點

  • spring是開源的免費的容器,
  • spring是一個輕量級的,非入侵式的,
  • 控制反轉(IOC),面向切面編程 (AOP),
  • 支持事務處理,對框架整合的支持,

總結:spring是一個輕量級的控制反轉(IOC)和面向切面編程(AOP)的框架,

1.3、Spring組成

img

img

1.4、拓展

  1. Spring Boot 構建一切
    1. 一個快速開發的腳手架
    2. 基于SpringBoot可以快速的開發單個微服務
    3. 約束大于配置!
  2. Spring Cloud 協調一切
    1. SpringCloud是基于SpringBoot實作的
  3. Spring Cloud Data Flow 連接一切

學習SpringBoot的前提,需要完全掌握Spring以及SpringMVC!

2、IOC理論推導

  1. UserDao
  2. UserDaoImp
  3. UserSevice
  4. UserServiceImp

在之前,用戶的需求可能會影響原來的代碼,

2.1、分析實作

新建一個空白的maven專案

分析實作

我們先用我們原來的方式寫一段代碼 .

1、先寫一個UserDao介面

public interface UserDao {
  public   void getUser();
}

2、再去寫Dao的實作類

public class UserDaoImp implements UserDao{
    @Override
    public void getUser() {
        System.out.println("默認獲取用戶的資料");
    }
}

3、然后去寫UserService的介面

public interface UserService {
    public void getUser();
}

4、最后寫Service的實作類

public class UserServiceImp implements UserService{

    private UserDao userDao = new UserDaoImp();

    public void getUser(){
        userDao.getUser();
    }
}

5、測驗一下

@Test
public void MyTest(){
    UserService service = new UserServiceImpl();
    service.getUser();
}

這是我們原來的方式 , 開始大家也都是這么去寫的對吧 . 那我們現在修改一下 .

把Userdao的實作類增加一個 .

public class UserDaoMysqlImp implements UserDao{
    @Override
    public void getUser() {
        System.out.println("Mysql獲取用戶資料!");
    }
}

緊接著我們要去使用MySql的話 , 我們就需要去service實作類里面修改對應的實作

public class UserServiceImpl implements UserService {
   private UserDao userDao = new UserDaoMySqlImpl();

   @Override
   public void getUser() {
       userDao.getUser();
  }
}

在假設, 我們再增加一個Userdao的實作類 .

public class UserDaoOracleImpl implements UserDao {
   @Override
   public void getUser() {
       System.out.println("Oracle獲取用戶資料");
  }
}

那么我們要使用Oracle , 又需要去service實作類里面修改對應的實作 . 假設我們的這種需求非常大 , 這種方式就根本不適用了, 甚至反人類對吧 , 每次變動 , 都需要修改大量代碼 . 這種設計的耦合性太高了, 牽一發而動全身 .

那我們如何去解決呢 ?

我們可以在需要用到他的地方 , 不去實作它 , 而是留出一個介面 , 利用set , 我們去代碼里修改下 .

public class UserServiceImpl implements UserService {
   private UserDao userDao;
// 利用set實作
   public void setUserDao(UserDao userDao) {
       this.userDao = userDao;
  }

   @Override
   public void getUser() {
       userDao.getUser();
  }
}

現在去我們的測驗類里 , 進行測驗 ;

public class MyTest {
    public static void main(String[] args) {
        //用戶實際呼叫的是業務層,dao層他們不需要接觸!
        UserServiceImp userService = new UserServiceImp();
        ((UserServiceImp) userService).setUserDao(new UserDaoSqlserviceImp());
        userService.getUser();
    }
}

使用一個set,

   private UserDao userDao;
      //利用set進行動態實作值的注入
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }
  • 之前是主動創建物件,控制權在程式猿手上!
  • 使用set之后,程式不再具有主動性,而是變成了被動接受對象,

這種思想,從本質上解決了問題,我們程式猿不用再去管理物件的創建,系統的耦合性大大降低,可以更加專注在業務的實作上!這是IOC的原型!

2.2、IOC本質

控制反轉IoC(Inversion of Control),是一種設計思想,**DI(依賴注入)是實作IoC的一種方法,**也有人認為DI只是IoC的另一種說法,沒有IoC的程式中 , 我們使用面向物件編程 , 物件的創建與物件間的依賴關系完全硬編碼在程式中,物件的創建由程式自己控制,控制反轉后將物件的創建轉移給第三方,個人認為所謂控制反轉就是:獲得依賴物件的方式反轉了,

img

IoC是Spring框架的核心內容,使用多種方式完美的實作了IoC,可以使用XML配置,也可以使用注解,新版本的Spring也可以零配置實作IoC,

Spring容器在初始化時先讀取組態檔,根據組態檔或元資料創建與組織物件存入容器中,程式使用時再從Ioc容器中取出需要的物件,

img

采用XML方式配置Bean的時候,Bean的定義資訊是和實作分離的,而采用注解的方式可以把兩者合為一體,Bean的定義資訊直接以注解的形式定義在實作類中,從而達到了零配置的目的,

控制反轉是一種通過描述(XML或注解)并通過第三方去生產或獲取特定物件的方式,在Spring中實作控制反轉的是IoC容器,其實作方法是依賴注入(Dependency Injection,DI),

示例:

HelloSpring

1、匯入Jar包

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

2、撰寫一個Hello物體類

public class Hello {
   private String name;

   public String getName() {
       return name;
  }
   public void setName(String name) {
       this.name = name;
  }

   public void show(){
       System.out.println("Hello,"+ name );
  }
}

3、撰寫我們的spring檔案 , 這里我們命名為beans.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
        型別 變數名  = new 型別
        Hello hello = new Hello();
        bean=物件 new Hello()

        id=變數名
        class=new 的物件
        property 相當于給物件中的屬性設定有一個值
-->
    <bean id="hello" class="com.kk.pojo.Hello">
        <property name="str" value="Spring">
        </property>
    </bean>


</beans>

4、測驗

import com.kk.pojo.Hello;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyTest {
    public static void main(String[] args) {
        //獲取Spring的背景關系物件
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        //我們的物件現在都在Spring中管理了,我們要使用,直接去里面取出來就可以了
        Hello hello = (Hello)context.getBean("hello");
        hello.show();
//        System.out.println(hello.toString());


    }
}

思考

  • Hello 物件是誰創建的 ? 【hello 物件是由Spring創建的
  • Hello 物件的屬性是怎么設定的 ? hello 物件的屬性是由Spring容器設定的

這個程序就叫控制反轉 :

  • 控制 : 誰來控制物件的創建 , 傳統應用程式的物件是由程式本身控制創建的 , 使用Spring后 , 物件是由Spring來創建的
  • 反轉 : 程式本身不創建物件 , 而變成被動的接收物件 .

依賴注入 : 就是利用set方法來進行注入的.

IOC是一種編程思想,由主動的編程變成被動的接收

可以通過newClassPathXmlApplicationContext去瀏覽一下底層原始碼 .

修改案例一

我們在案例一中, 新增一個Spring組態檔beans.xml

注入:
1.ref:參考Spring容器中創建好的物件
2.value:具體的值,基本資料型別

<?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-3.0.xsd">
        <bean id="mysqlImp" class="com.kk.dao.UserDaoMysqlImp"></bean>
        <bean id="oracleImp" class="com.kk.dao.UserDaoOracleImp"></bean>
        <bean id="SqlserviceImp" class="com.kk.dao.UserDaoSqlserviceImp"></bean>

        <bean id="UserServiceImp" class="com.kk.service.UserServiceImp">
            <property name="userDao" ref="SqlserviceImp"></property>
        </bean>
    <!--            注入-->
    <!--            ref:參考Spring容器中創建好的物件
                    value:具體的值,基本資料型別-->

</beans>

測驗:

import com.kk.dao.UserDaoImp;
import com.kk.dao.UserDaoSqlserviceImp;
import com.kk.service.UserServiceImp;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyTest {
    public static void main(String[] args) {
        //獲取ApplicationContext  拿到Spring的容器
      ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");

        UserServiceImp userServiceImp = (UserServiceImp)context.getBean("UserServiceImp");
        userServiceImp.getUser();
    }
}

2.3、IOC創建物件方式

  1. 使用無參構造創建物件,默認,

    物體類

    1. package com.kk.pojo;
      
      public class User {
          private String name;
          public User() {
              System.out.println("user無參構造方法");
          }
          public String getName() {
            return name;
          }
          public void setName(String name) {
              this.name = name;
          }
      
          public void show(){
              System.out.println("name="+ name );
          }
      }
      

      2.beans.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-3.0.xsd">
      
          <bean id="user" class="com.kk.pojo.User">
      <!--       有一個屬性name需要注入,-->
              <property name="name" value="KK"></property>
          </bean>
      
      </beans>
      

      3、測驗類

      import com.kk.pojo.User;
      import org.springframework.context.ApplicationContext;
      import org.springframework.context.support.ClassPathXmlApplicationContext;
      
      	public class MyTest {
          public static void main(String[] args) {
              ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
      
              User  user = (User)context.getBean("user");
              user.show();
          }
      }
      
  2. 使用有參構造

    1. 下標賦值

      物體類

package com.kk.pojo;

public class User {
    private String name;

    public User(String name){
        this.name = name;
    }
    public String getName() {
      return name;
    }
    public void setName(String name) {
        this.name = name;
    }

    public void show(){
        System.out.println("name="+ name );
    }
}

beans.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-3.0.xsd">

    <bean id="user" class="com.kk.pojo.User">
<!--        第一種:下標賦值-->
        <constructor-arg index="0" value="kkkkkk"></constructor-arg>
    </bean>

</beans>

測驗

import com.kk.pojo.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyTest {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");

        User  user = (User)context.getBean("user");
        user.show();
    }
}

2.通過型別創建

<!--   第二種方式:通過型別創建  不建議使用以下方法-->
    <bean id="user" class="com.kk.pojo.User">
        <constructor-arg type="java.lang.String" value="k11"></constructor-arg>
    </bean>

3.直接通過引數名創建

<!--    第三種方式:直接通過引數名創建-->
    <bean id="user" class="com.kk.pojo.User">
        <constructor-arg name="name" value="k111"></constructor-arg>
    </bean>

3、 Spring配置

3.1、別名

<!--    別名,如果添加了別名,我們也可以通過別名獲取-->
    <alias name="user" alias="abc"></alias>
import com.kk.pojo.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyTest {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        User  user = (User)context.getBean("abc");
        user.show();
    }
}

3.2、Bean的配置

  • id:bean的id識別符號
  • class:bean物件所對應的型別
  • name:別名,更高級,可以同時取多個別名,
<!--    id:bean的唯一識別符號,也是相當于我們學的物件名
        class:bean物件所對應的權限定名:包名+型別
        name :也是別名 而且name可以取多個別名
        -->
    <bean id="userT" class="com.kk.pojo.UserT" name="user2,u2 u3;u4">
        <property name="name" value="KK"></property>
    </bean>

3.3、import

這個import,一般用于團隊開發使用,可以將多個組態檔,匯入合并為一個

<?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-3.0.xsd">
    <import resource="beans.xml"></import>
    <import resource="beans2.xml"></import>
    <import resource="beans3.xml"></import>

</beans>

4、DI依賴注入

4.1、構造器注入

4.2、Set方式注入

  • 依賴注入:Set注入
    • 依賴:bean物件的創建依賴于容器
    • 注入,bean物件中的所有屬性由容器來注入

環境搭建

1.復雜型別

public class Address {
    private String address;
    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

}

2.真實測驗物件

package com.kk.pojo;


import java.util.*;
public class Student {
    private String name;
    private Address address;
    private String[] books;
    private List<String> hobbys;
    private Map<String,String> card;
    private Set<String> games;
    private String wife;
    private Properties info;

    public Student() {

    }

    public Student(String name, Address address, String[] books,
                   List<String> hobbys, Map<String, String> card,
                   Set<String> games, String wife, Properties info) {
        this.name = name;
        this.address = address;
        this.books = books;
        this.hobbys = hobbys;
        this.card = card;
        this.games = games;
        this.wife = wife;
        this.info = info;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }

    public String[] getBooks() {
        return books;
    }

    public void setBooks(String[] books) {
        this.books = books;
    }

    public List<String> getHobbys() {
        return hobbys;
    }

    public void setHobbys(List<String> hobbys) {
        this.hobbys = hobbys;
    }

    public Map<String, String> getCard() {
        return card;
    }

    public void setCard(Map<String, String> card) {
        this.card = card;
    }

    public Set<String> getGames() {
        return games;
    }

    public void setGames(Set<String> games) {
        this.games = games;
    }

    public String getWife() {
        return wife;
    }

    public void setWife(String wife) {
        this.wife = wife;
    }

    public Properties getInfo() {
        return info;
    }

    public void setInfo(Properties info) {
        this.info = info;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", address=" + address +
                ", books=" + Arrays.toString(books) +
                ", hobbys=" + hobbys +
                ", card=" + card +
                ", games=" + games +
                ", wife='" + wife + '\'' +
                ", info=" + info +
                '}';
    }
}

3.bean.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-3.0.xsd">

<!--    第一種:普通值注入  使用value值注入-->
    <bean id="student" class="com.kk.pojo.Student">
        <property name="name" value="火神"></property>
    </bean>

</beans>

4.測驗類:

import com.kk.pojo.Student;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyTest {
    public static void main(String[] args) {
    ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        Student student =(Student) context.getBean("student");
        System.out.println(student.getName());
    }
}

5.完善注入資訊:

<?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-3.0.xsd">
    <bean id="address" class="com.kk.pojo.Address">
        <property name="address" value="廣東"></property>
    </bean>


    <bean id="student" class="com.kk.pojo.Student">
        <!--    第一種:普通值注入  使用value值注入-->
        <property name="name" value="火神"></property>
<!--        第二種:Bean注入 ,使用ref注入-->
        <property name="address" ref="address"></property>
<!--        陣列注入,-->
        <property name="books">
            <array>
                <value>紅樓夢</value>
                <value>西游記</value>
                <value>三國演義</value>
                <value>水滸傳</value>
            </array>
        </property>

<!--        list注入-->
        <property name="hobbys">
            <list>
                <value>編程</value>
                <value>聽歌</value>
                <value></value>
            </list>
        </property>

<!--        map注入-->
        <property name="card">
            <map>
                <entry key="身份證" value="4412002121223***"></entry>
                <entry key="銀行卡" value="654645454546"></entry>
            </map>
        </property>

<!--        set注入-->
        <property name="games">
            <set>
                <value>LOL</value>
                <value>CSOL</value>
            </set>
        </property>

<!--        wife注入-->
        <property name="wife">
            <null></null>
        </property>

<!--        Properties-->
        <property name="info">
            <props>
                <prop key="學號">2011***</prop>
                <prop key="性別"></prop>
                <prop key="姓名">k</prop>
                <prop key="password">123456</prop>
            </props>
        </property>
     </bean>

</beans>

4.3、其他方式注入

物體類:

package com.kk.pojo;

public class User {
    private int age;
    private String name;

    //c命名空間需要有參構造器


    public User(int age, String name) {
        this.age = age;
        this.name = name;
    }

    public User() {

    }

    public int getAge() {
        return age;
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "User{" +
                "age=" + age +
                ", name='" + name + '\'' +
                '}';
    }
}

? 1、P命名空間注入 : 需要在頭檔案中加入約束檔案

 匯入約束 : xmlns:p="http://www.springframework.org/schema/p"

 <!--P(屬性: properties)命名空間 , 屬性依然要設定set方法-->
 <bean id="user" class="com.kuang.pojo.User" p:name="kk" p:age="17"/>

測驗類:

    @Test
    public void test2(){
       ApplicationContext context = new ClassPathXmlApplicationContext("userbeans.xml");
//        User user =(User) context.getBean("user");
        User user = context.getBean("user", User.class);
        System.out.println(user);

    }

2、c 命名空間注入 : 需要在頭檔案中加入約束檔案

 匯入約束 : xmlns:c="http://www.springframework.org/schema/c"
 <!--C(構造: Constructor)命名空間 , 屬性依然要設定set方法-->
 <bean id="user" class="com.kuang.pojo.User" c:name="kk" c:age="17"/>

測驗類:

@Test
public void test3(){
    ApplicationContext context = new ClassPathXmlApplicationContext("userbeans.xml");
    User user = context.getBean("user2", User.class);
    System.out.println(user);

}

4.4、bean的作用域

在Spring中,那些組成應用程式的主體及由Spring IOC容器所管理的物件,被稱之為bean,簡單地講,bean就是由IoC容器初始化、裝配及管理的物件

img

? 幾種作用域中,request、session作用域僅在基于web的應用中使用(不必關心你所采用的是什么web應用框架),只能用在基于web的Spring ApplicationContext環境,

4.4.1、Singleton單例模式(Spring默認機制)

? 當一個bean的作用域為Singleton,那么Spring IOC容器中只會存在一個共享的bean實體,并且所有對bean的請求,只要id與該bean定義相匹配,則只會回傳bean的同一實體,Singleton是單例型別,就是在創建起容器時就同時自動創建了一個bean的物件,不管你是否使用,他都存在了,每次獲取到的物件都是同一個物件,注意,Singleton作用域是Spring中的預設作用域,要在XML中將bean定義成singleton,可以這樣配置:

    <bean id="user2" class="com.kk.pojo.User" c:name="kk" c:age="99" scope="singleton"></bean>

測驗:

@Test
public void test3(){
    ApplicationContext context = new ClassPathXmlApplicationContext("userbeans.xml");
    User user = context.getBean("user2", User.class);
    User user2 = context.getBean("user2", User.class);
    System.out.println(user==user2);//true	
    System.out.println(user);

}

4.4.2、Prototype(原型模式)每次get的時候都會產生新的物件

? 當一個bean的作用域為Prototype,表示一個bean定義對應多個物件實體,Prototype作用域的bean會導致在每次對該bean請求(將其注入到另一個bean中,或者以程式的方式呼叫容器的getBean()方法)時都會創建一個新的bean實體,Prototype是原型型別,它在我們創建容器的時候并沒有實體化,而是當我們獲取bean的時候才會去創建一個物件,而且我們每次獲取到的物件都不是同一個物件,根據經驗,對有狀態的bean應該使用prototype作用域,而對無狀態的bean則應該使用singleton作用域,在XML中將bean定義成prototype,可以這樣配置:

<!--    每次get的時候都會產生新的物件-->
    <bean id="user2" class="com.kk.pojo.User" c:name="kk" c:age="99" scope="prototype"></bean>

測驗:

@Test
public void test3(){
    ApplicationContext context = new ClassPathXmlApplicationContext("userbeans.xml");
    User user = context.getBean("user2", User.class);
    User user2 = context.getBean("user2", User.class);
    System.out.println(user.hashCode());
    System.out.println(user2.hashCode());
    //兩個值不同
    System.out.println(user==user2);//false

    System.out.println(user);

}

4.4.3、Request

? 當一個bean的作用域為Request,表示在一次HTTP請求中,一個bean定義對應一個實體;即每個HTTP請求都會有各自的bean實體,它們依據某個bean定義創建而成,該作用域僅在基于web的Spring ApplicationContext情形下有效,考慮下面bean定義:

 <bean id="loginAction" class=cn.csdn.LoginAction" scope="request"/>

? 針對每次HTTP請求,Spring容器會根據loginAction bean的定義創建一個全新的LoginAction bean實體,且該loginAction bean實體僅在當前HTTP request內有效,因此可以根據需要放心的更改所建實體的內部狀態,而其他請求中根據loginAction bean定義創建的實體,將不會看到這些特定于某個請求的狀態變化,當處理請求結束,request作用域的bean實體將被銷毀,

4.4.4、Session

當一個bean的作用域為Session,表示在一個HTTP Session中,一個bean定義對應一個實體,該作用域僅在基于web的Spring ApplicationContext情形下有效,考慮下面bean定義:

 <bean id="userPreferences" class="com.foo.UserPreferences" scope="session"/>

? 針對某個HTTP Session,Spring容器會根據userPreferences bean定義創建一個全新的userPreferences bean實體,且該userPreferences bean僅在當前HTTP Session內有效,與request作用域一樣,可以根據需要放心的更改所創建實體的內部狀態,而別的HTTP Session中根據userPreferences創建的實體,將不會看到這些特定于某個HTTP Session的狀態變化,當HTTP Session最終被廢棄的時候,在該HTTP Session作用域內的bean也會被廢棄掉,

5、Bean的自動裝配

  • 自動裝配是Spring滿足bean依賴的一種方式!
  • Spring會在背景關系中自動尋找,并自動給bean裝配屬性!

在Spring中有三種自動裝配的方式

  1. 在xml中顯示的配置
  2. 在java中顯示配置
  3. 隱式的自動裝配bean(重要)

5.1、測驗

環境搭建:一個人有兩個寵物!

物體類:

Cat

package com.kk.pojo;

public class Cat {
    public void shout(){
        System.out.println("miao~");
    }
}

Dog

package com.kk.pojo;

public class Dog {
    public void shout(){
        System.out.println("Wang~");
    }
}

People

package com.kk.pojo;

public class People {
    private Cat cat;
    private Dog dog;
    private String name;

    public Cat getCat() {
        return cat;
    }

    public void setCat(Cat cat) {
        this.cat = cat;
    }

    public Dog getDog() {
        return dog;
    }

    public void setDog(Dog dog) {
        this.dog = dog;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "People{" +
                "cat=" + cat +
                ", dog=" + dog +
                ", name='" + name + '\'' +
                '}';
    }
}

beans.xml:

5.2、ByName自動裝配

byName:會自動在容器背景關系中查找,和自己物件set方法后面的值對應的bean!

    <bean id="cat" class="com.kk.pojo.Cat"></bean>
    <bean id="dog" class="com.kk.pojo.Dog"></bean>

<!--    byName:會自動在容器背景關系中查找,和自己物件set方法后面的值對應的bean!-->
    <bean id="people" class="com.kk.pojo.People" autowire="byName">
        <property name="name" value="kk"></property>
<!--        <property name="dog" value="dog"></property>-->
<!--        <property name="cat" value="cat"></property>-->
    </bean>

5.3、ByType自動裝配

byType:會自動在容器背景關系中查找,和自己物件屬性型別相同的bean! 必須保證類目全域唯一

<?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-3.0.xsd">
    <bean id="cat" class="com.kk.pojo.Cat"></bean>
<!--    <bean id="dog1212" class="com.kk.pojo.Dog"></bean>-->
    <bean  class="com.kk.pojo.Dog"></bean>

    <!--    byType:會自動在容器背景關系中查找,和自己物件屬性型別相同的bean! 必須保證類目全域唯一-->
    <bean id="people" class="com.kk.pojo.People" autowire="byType">
        <property name="name" value="kk"></property>
        <!--        <property name="dog" value="dog"></property>-->
        <!--        <property name="cat" value="cat"></property>-->
    </bean>

</beans>

測驗類:

import com.kk.pojo.People;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyTest {
    @Test
    public void test1(){
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        People people = context.getBean("people", People.class);
        people.getDog().shout();
        people.getCat().shout();
    }
}

小結

  • ByName的時候,需要保證所有bean的id唯一,并且這個bean需要和自動注入的屬性的set方法的值一致!
  • ByType的時候,需要保證所有bean的class唯一,并且這個bean需要和自動注入的屬性的型別一致!

5.4、使用注解實作自動裝配

使用注解

jdk1.5開始支持注解,spring2.5開始全面支持注解,

準備作業:利用注解的方式注入屬性,

1、在spring組態檔中引入context檔案頭

 xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
  http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context-3.0.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop-3.0.xsd

2、開啟屬性注解支持!

<!--    開啟注解的支持-->
    <context:annotation-config/>

5.4.1、Autowired

直接在屬性上使用即可!也可以在set方式上使用!

使用Autowired我們可以不用撰寫set方法,前提是這個自動裝配的屬性在IOC(Spring)容器中存在,且符合名字ByName!

測驗:

物體類

package com.kk.pojo;

public class cat {
    public void shout(){
        System.out.println("miao~");
    }
}
package com.kk.pojo;

public class dog {
    public void shout(){
        System.out.println("Wang~");
    }
}
package com.kk.pojo;

import org.springframework.beans.factory.annotation.Autowired;

public class People {
    @Autowired
    private cat cat;
    @Autowired
    private dog dog;
    private String name;

    public com.kk.pojo.cat getCat() {
        return cat;
    }

    public void setCat(com.kk.pojo.cat cat) {
        this.cat = cat;
    }

    public com.kk.pojo.dog getDog() {
        return dog;
    }

    public void setDog(com.kk.pojo.dog dog) {
        this.dog = dog;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "People{" +
                "cat=" + cat +
                ", dog=" + dog +
                ", name='" + name + '\'' +
                '}';
    }
}

beans.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"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context-3.0.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">

    <!--    開啟注解的支持-->
        <context:annotation-config/>
    <bean id="cat" class="com.kk.pojo.cat"></bean>
    <bean id="dog" class="com.kk.pojo.dog"></bean>
    <bean id="people" class="com.kk.pojo.People"></bean>

</beans>

測驗類:

import com.kk.pojo.People;
import org.testng.annotations.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyTest {
    @Test
    public void test1(){
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        People people = context.getBean("people", People.class);
        people.getCat().shout();
        people.getDog().shout();

    }
}

注意:

@Nullable 欄位標記了這個

public @interface Autowired{
booleam required() default true;
}
public class People {
    //如果顯示定義了Autowired的required的屬性為false,說明這個物件可以為null,否則不允許為空
    @Autowired(required = false)
    private cat cat;
    @Autowired
    private dog dog;
    private String name;
    }

@Qualifier

如果@Autowired自動裝配的環境比較復雜,自動裝配無法通過一個注解@Autowired完成的時候,我們可以使用@Qualifier(value=“xxxx”)去配置@Autowired的使用,指定一個唯一的bean物件注入!

  • @Autowired是根據型別自動裝配的,加上@Qualifier則可以根據byName的方式自動裝配
  • @Qualifier不能單獨使用,

測驗實驗步驟:

1、組態檔修改內容,保證型別存在物件,且名字不為類的默認名字!

<bean id="dog1" class="com.kk.pojo.dog"/>
<bean id="dog2" class="com.kk.pojo.dog"/>
<bean id="cat1" class="com.kk.pojo.cat"/>
<bean id="cat2" class="com.kk.pojo.cat"/>

2、沒有加Qualifier測驗,直接報錯

3、在屬性上添加Qualifier注解

@Autowired
@Qualifier(value = "cat2")
private cat cat;
@Autowired
@Qualifier(value = "dog2")
private dog dog;

測驗,成功輸出!

@Resource

  • @Resource如有指定的name屬性,先按該屬性進行byName方式查找裝配;
  • 其次再進行默認的byName方式進行裝配;
  • 如果以上都不成功,則按byType的方式自動裝配,
  • 都不成功,則報例外,

物體類:

public class People {
    //如果顯示定義了Autowired的required的屬性為false,說明這個物件可以為null,否則不允許為空
//    @Autowired(required = false)
    @Resource(name = "cat2")
    private cat cat;
//    @Autowired
//    @Qualifier(value="dog1")
    @Resource
    private dog dog;
    private String name;
}

beans.xml

<!--    開啟注解的支持-->
    <context:annotation-config/>

        <bean id="cat1" class="com.kk.pojo.cat"></bean>
        <bean id="cat2" class="com.kk.pojo.cat"></bean>
        <bean id="dog" class="com.kk.pojo.dog"></bean>
        <bean id="dog11" class="com.kk.pojo.dog"></bean>
        <bean id="people" class="com.kk.pojo.People"></bean>


測驗:結果OK

組態檔2:beans.xml , 刪掉cat2

    <bean id="dog" class="com.kk.pojo.dog"></bean>
    <bean id="cat1" class="com.kk.pojo.cat"></bean>

物體類上只保留注解

@Resource
private cat cat;
@Resource
private dog dog;

結果:OK

結論:先進行byName查找,失敗;再進行byType查找,成功,

小結

@Autowired與@Resource異同:

? 1、@Autowired與@Resource都可以用來裝配bean,都可以寫在欄位上,或寫在setter方法上,

? 2、@Autowired默認按型別裝配(屬于spring規范),默認情況下必須要求依賴物件必須存在,如果要允許null 值,可以設定它的required屬性為false,如:@Autowired(required=false) ,如果我們想使用名稱裝配可以結合@Qualifier注解進行使用

? 3、@Resource(屬于J2EE復返),默認按照名稱進行裝配,名稱可以通過name屬性進行指定,如果沒有指定name屬性,當注解寫在欄位上時,默認取欄位名進行按照名稱查找,如果注解寫在setter方法上默認取屬性名進行裝配,當找不到與名稱匹配的bean時才按照型別進行裝配,但是需要注意的是,如果name屬性一旦指定,就只會按照名稱進行裝配,

它們的作用相同都是用注解方式注入物件,但執行順序不同,@Autowired先byType,@Resource先byName,

6、使用注解開發

在Spring4之后,要使用注解開發,必須保證aop的包匯入了

img

使用注解開發需要匯入context約束,增加注解的支持!

<?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:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context-3.0.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">

    <!--    開啟注解的支持-->
    <context:annotation-config/>

</beans>

6.1、bean

我們之前都是使用 bean 的標簽進行bean注入,但是實際開發中,我們一般都會使用注解!

1、配置掃描哪些包下的注解

<!--指定注解掃描包-->
<context:component-scan base-package="com.kk.pojo"/>

2、在指定包下撰寫類,增加注解

package com.kk.pojo;


import org.springframework.stereotype.Component;
//這里等價于    <bean id="user" class="com.kk.pojo.User"></bean>
//Component 組件
@Component
public class User {
    public String name="k";
}

3、測驗

import com.kk.pojo.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyTest {
    public static void main(String[] args) {
      ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//        User user = (User)context.getBean("user");
        User user = context.getBean("user", User.class);
        System.out.println(user.name);
    }
}

6.2、屬性如何注入

package com.kk.pojo;


import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
//這里等價于    <bean id="user" class="com.kk.pojo.User"></bean>
//Component 組件
@Component
public class User {

    public String name;
    // 相當于 <property name="name" value="kk"></property>
    @Value("kk")
    public void setName(String name) {
        this.name = name;
    }
}

6.3、衍生的注解

@Component有幾個衍生注解,我們在web開發中,會按照MVC三層架構分層!

  • dao【@Repository】
  • service【@Service】
  • controller【@Controller】

這四個注解的功能都是一樣的,都是代表將某個類注冊到Spring中,裝配Bean

6.4、自動裝配置

-@Autowired :自動裝配通過型別  名字
如果Autowired不能唯一自動裝配上屬性,則需要通過@Qualifier(value="xxxx")
-@Nullable 欄位標記了這個注解,說明這個欄位可以為null
-Resource:自動裝配通過名字  型別

6.5、作用域

<?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:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context-3.0.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<!--    指定要掃描的包,這個包下的注解就會生效-->
    <context:component-scan base-package="com.kk"></context:component-scan>
    <!--    開啟注解的支持-->
    <context:annotation-config/>


<!--    <bean id="user" class="com.kk.pojo.User">-->
<!--        <property name="name" value="kk"></property>-->
<!--    </bean>-->

</beans>
package com.kk.pojo;


import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
//這里等價于    <bean id="user" class="com.kk.pojo.User"></bean>
//Component 組件
@Component
@Scope("prototype")
public class User {

    public String name;
    // 相當于 <property name="name" value="kk"></property>
    @Value("kk")
    public void setName(String name) {
        this.name = name;
    }
}
/*
@scope

singleton:默認的,Spring會采用單例模式創建這個物件,關閉工廠 ,所有的物件都會銷毀,

prototype:多例模式,關閉工廠 ,所有的物件不會銷毀,內部的垃圾回識訓制會回收
*/

6.6、小結

XML與注解比較

  • XML可以適用任何場景 ,結構清晰,維護方便
  • 注解不是自己提供的類使用不了,開發簡單方便,維護相對復雜

xml與注解整合開發 :推薦最佳實踐

  • xml管理Bean
  • 注解只負責完成屬性注入
  • 我們在使用的程序中,只需要注意一個問題,必須讓注解生效,就需要開啟注解的支持
<!--    指定要掃描的包,這個包下的注解就會生效-->
    <context:component-scan base-package="com.kk"></context:component-scan>
    <!--    開啟注解的支持-->
    <context:annotation-config/>

作用:

  • 進行注解驅動注冊,從而使注解生效
  • 用于激活那些已經在spring容器里注冊過的bean上面的注解,也就是顯示的向Spring注冊
  • 如果不掃描包,就需要手動配置bean
  • 如果不加注解驅動,則注入的值為null!

7、基于Java的方式配置Spring

完全不使用Spring的xml配置,全權交給java來做!

JavaConfig 是Spring的一個子專案.在Spring之后,成為了一個核心功能!

? img

測驗

物體類:User

package com.kk.pojo;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;

//使用這個注解的意思,就是說明這個類被Spring接管了,就是注冊到了容器中
@Component
public class User {
    private String name;

    public String getName() {
        return name;
    }
    @Value("kk")//屬性注入值
    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                '}';
    }
}

組態檔:MyConfig

package com.kk.config;

import com.kk.pojo.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

//@Configuration 代表這是一個配置類,就和beans.xml一樣的
//這個也會被Spring容器托管,注冊到容器中,因為它本來就是一個@Component
@Configuration
@ComponentScan("com.kk.pojo")
@Import(MyConfig2.class)  //引入
public class MyConfig {

    //注冊一個bean,就相當于之前寫的一個bean標簽
    //這個方法的名字就相當于bean標簽中的id屬性
    //這個方法的回傳值,就相當于bean標簽的的class屬性
    @Bean
    public User getUser(){
        return new User();//就是回傳要注入到bean的物件
    }
}

組態檔:MyConfig2

package com.kk.config;

import org.springframework.context.annotation.Configuration;

@Configuration
public class MyConfig2 {
}

測驗類:

import com.kk.config.MyConfig;
import com.kk.pojo.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class MyTest {
    public static void main(String[] args) {

        //如果完全使用了配置類去做,我們就只能通過AnnotationConfig 背景關系來獲取容器,通過配置類的class物件加載!
        ApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class);
        User getUser = (User)context.getBean("user");
        System.out.println(getUser.getName());
    }
}

8、靜態/動態代理模式

為什么要學習代理模式,因為AOP的底層機制就是動態代理!

代理模式:

  • 靜態代理

  • 動態代理

    img

8.1、靜態代理

靜態代理角色分析

  • 抽象角色 : 一般使用介面或者抽象類來實作
  • 真實角色 : 被代理的角色
  • 代理角色 : 代理真實角色 ; 代理真實角色后 , 一般會做一些附屬的操作 .
  • 客戶 : 使用代理角色來進行一些操作 .

代碼步驟:

1、介面

//租房的介面
public interface Rent {
    public void rent();
}

2、真實角

//房東
public class Host {
    public void rent(){
        System.out.println("房東要出租房子");
    }
}

3、代理角色

public class Proxy implements Rent{
    private Host host;

    public Proxy() {
    }

    public Proxy(Host host) {
        this.host = host;
    }

    @Override
    public void rent() {
        seeHouse();
        host.rent();
        hetong();
        fare();

    }

    //看房
    public void seeHouse(){
        System.out.println("帶房客看房");
    }
    //租賃
    public void hetong(){
        System.out.println("簽租賃合同");
    }
    //收中介費
    public void fare(){
        System.out.println("收中介費");
    }
}

4、客戶端訪問代理角色

public class Client {
    public static void main(String[] args) {
        //房東要租房子
        Host host = new Host();
        //代理,中介幫方法租房子
        //代理操作一般會帶一些附屬操作
        Proxy proxy = new Proxy(host);
        proxy.rent();
    }
}

分析:在這個程序中,你直接接觸的就是中介,就如同現實生活中的樣子,你看不到房東,但是你依舊租到了房東的房子通過代理,這就是所謂的代理模式,程式源自于生活,所以學編程的人,一般能夠更加抽象的看待生活中發生的事情,

靜態代理的好處:

  • 可以使得我們的真實角色更加純粹 . 不再去關注一些公共的事情 .
  • 公共的業務由代理來完成 . 實作了業務的分工 ,
  • 公共業務發生擴展時變得更加集中和方便 .

缺點 :

  • 類多了 , 多了代理類 , 作業量變大了 . 開發效率降低 .

我們想要靜態代理的好處,又不想要靜態代理的缺點,所以 , 就有了動態代理 !

靜態代理再理解

1、創建一個抽象角色,比如咋們平時做的用戶業務,抽象起來就是增刪改查!

public interface UserService {
    public void add();
    public void delete();
    public void update();
    public void query();
}

2、我們需要一個真實物件來完成這些增刪改查操作

//真實物件,完成增刪改查操作的人
public class UserServiceImpl implements UserService {

   public void add() {
       System.out.println("增加了一個用戶");
  }

   public void delete() {
       System.out.println("洗掉了一個用戶");
  }

   public void update() {
       System.out.println("更新了一個用戶");
  }

   public void query() {
       System.out.println("查詢了一個用戶");
  }
}

3、需求來了,現在我們需要增加一個日志功能,怎么實作!

  • 思路1 :在實作類上增加代碼 【麻煩!】
  • 思路2:使用代理來做,能夠不改變原來的業務情況下,實作此功能就是最好的了!

4、設定一個代理類來處理日志!代理角色

//代理角色,在這里面增加日志的實作
public class UserServiceProxy implements UserService {
   private UserServiceImpl userService;

   public void setUserService(UserServiceImpl userService) {
       this.userService = userService;
  }

   public void add() {
       log("add");
       userService.add();
  }

   public void delete() {
       log("delete");
       userService.delete();
  }

   public void update() {
       log("update");
       userService.update();
  }

   public void query() {
       log("query");
       userService.query();
  }

   public void log(String msg){
       System.out.println("執行了"+msg+"方法");
  }

}

5、測驗訪問類:

public class Client {
   public static void main(String[] args) {
       //真實業務
       UserServiceImpl userService = new UserServiceImpl();
       //代理類
       UserServiceProxy proxy = new UserServiceProxy();
       //使用代理類實作日志功能!
       proxy.setUserService(userService);

       proxy.add();
  }
}

OK,到了現在代理模式大家應該都沒有什么問題了,重點大家需要理解其中的思想;

我們在不改變原來的代碼的情況下,實作了對原有功能的增強,這是AOP中最核心的思想

AOP:縱向開發,橫向開發

img

8.2、動態代理

  • 動態代理的角色和靜態代理的一樣 .

  • 動態代理的代理類是動態生成的 . 靜態代理的代理類是我們提前寫好的

  • 動態代理分為兩類 : 一類是基于介面動態代理 , 一類是基于類的動態代理

    • 基于介面的動態代理----JDK動態代理
    • 基于類的動態代理–cglib
    • 現在用的比較多的是 javasist 來生成動態代理
    • 我們這里使用JDK的原生代碼來實作,其余的道理都是一樣的!、

JDK的動態代理需要了解兩個類

核心 : InvocationHandler 和 Proxy

【InvocationHandler:呼叫處理程式】

img

Object invoke(Object proxy, 方法 method, Object[] args)//引數
//proxy - 呼叫該方法的代理實體
//method -所述方法對應于呼叫代理實體上的介面方法的實體,方法物件的宣告類將是該方法宣告的介面,它可以是代理類繼承該方法的代理介面的超級介面,
//args -包含的方法呼叫傳遞代理實體的引數值的物件的陣列,或null如果介面方法沒有引數,原始型別的引數包含在適當的原始包裝器類的實體中,例如java.lang.Integer或java.lang.Boolean ,

【Proxy : 代理】

img

img

img

//生成代理類
public Object getProxy(){
   return Proxy.newProxyInstance(this.getClass().getClassLoader(),
                                 rent.getClass().getInterfaces(),this);
}

代碼實作

Rent.java 即抽象角色

//抽象角色:租房
public interface Rent {
   public void rent();
}

Host.java 即真實角色

package com.kk.demo03;

//房東
public class Host implements Rent {
    public void rent(){
        System.out.println("房東要出租房子");
    }
}

ProxyInvocationHandler. java 即代理角色

package com.kk.demo03;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;


//使用該類自動生成代理類
public class ProxyInvocationHandler implements InvocationHandler {

    //被代理的介面
    private Rent rent;

    public void setRent(Rent rent) {
        this.rent = rent;
    }

    //生成得到代理類
    public Object getProxy(){
     return    Proxy.newProxyInstance(this.getClass().getClassLoader(), rent.getClass().getInterfaces(),this);
    }

    //處理代理事例,并回傳結果
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //動態代理的本質就是使用反射機制實作!
        seeHouse();
        fare();
        Object result = method.invoke(rent, args);
        return result;
    }
    public void seeHouse(){
        System.out.println("中介帶看房子");
    }
    public void fare(){
        System.out.println("收中介費");
    }
}

Client.java

package com.kk.demo03;

public class Client {
    public static void main(String[] args) {
        //真實角色
        Host host = new Host();

        //代理角色:現在無
        ProxyInvocationHandler pih = new ProxyInvocationHandler();
        //通過呼叫程式處理角色來處理我們需要呼叫的介面物件!
        pih.setRent(host);
        Rent proxy =(Rent) pih.getProxy();//這里的proxy就是動態代理
        proxy.rent();
    }

}

核心:一個動態代理 , 一般代理某一類業務 , 一個動態代理可以代理多個類,代理的是介面!

深化理解

我們來使用動態代理實作代理我們后面寫的UserService!

我們也可以撰寫一個通用的動態代理實作的類!所有的代理物件設定為Object即可!

package com.kk.demo04;

import com.kk.demo03.Rent;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;


//使用該類自動生成代理類
public class ProxyInvocationHandler implements InvocationHandler {

    //被代理的介面
    private Object target;

    public void setTarget(Object target) {
        this.target = target;
    }

    //生成得到代理類
    public Object getProxy(){
     return    Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(),this);
    }

    //處理代理事例,并回傳結果
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //動態代理的本質就是使用反射機制實作!
        log(method.getName());
        Object result = method.invoke(target, args);
        return result;
    }

    public void log(String msg){
        System.out.println("執行了"+msg+"方法");
    }
}

測驗!

package com.kk.demo04;

import com.kk.demo02.UserService;
import com.kk.demo02.UserServiceImp;

public class Client {
    public static void main(String[] args) {
        //真實物件
        UserServiceImp userService = new UserServiceImp();
        //代理角色 不存在
        ProxyInvocationHandler pih = new ProxyInvocationHandler();
        pih.setTarget(userService);//pih呼叫userService,設定要代理的物件
        //動態生成代理類
        UserService proxy = (UserService)pih.getProxy();
        proxy.add();
    }

}
動態代理的好處

靜態代理有的它都有,靜態代理沒有的,它也有!

  • 可以使得我們的真實角色更加純粹 . 不再去關注一些公共的事情 .
  • 公共的業務由代理來完成 . 實作了業務的分工 ,
  • 公共業務發生擴展時變得更加集中和方便 .
  • 一個動態代理 , 一般代理某一類業務
  • 一個動態代理可以代理多個類,代理的是介面!

9、AOP

9.1、什么是AOP

AOP(Aspect Oriented Programming)意為:面向切面編程,通過預編譯方式和運行期動態代理實作程式功能的統一維護的一種技術,AOP是OOP的延續,是軟體開發中的一個熱點,也是Spring框架中的一個重要內容,是函式式編程的一種衍生范型,利用AOP可以對業務邏輯的各個部分進行隔離,從而使得業務邏輯各部分之間的耦合度降低,提高程式的可重用性,同時提高了開發的效率,

img

9.2、Aop在Spring中的作用

提供宣告式事務;允許用戶自定義切面

以下名詞需要了解下:

  • 橫切關注點:跨越應用程式多個模塊的方法或功能,即是,與我們業務邏輯無關的,但是我們需要關注的部分,就是橫切關注點,如日志 , 安全 , 快取 , 事務等等 …
  • 切面(ASPECT):橫切關注點 被模塊化 的特殊物件,即,它是一個類,
  • 通知(Advice):切面必須要完成的作業,即,它是類中的一個方法,
  • 目標(Target):被通知物件,
  • 代理(Proxy):向目標物件應用通知之后創建的物件,
  • 切入點(PointCut):切面通知 執行的 “地點”的定義,
  • 連接點(JointPoint):與切入點匹配的執行點,

img

SpringAOP中,通過Advice定義橫切邏輯,Spring中支持5種型別的Advice:

img

9.3、使用Spring實作Aop

【重點】使用AOP織入,需要匯入一個依賴包!

<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
   <groupId>org.aspectj</groupId>
   <artifactId>aspectjweaver</artifactId>
   <version>1.9.4</version>
</dependency>

第一種方式

9.3.1、通過 Spring API 實作【主要Spring API介面實作】

首先撰寫我們的業務介面和實作類



public interface UserService {
    public void add();
    public void delete();
    public void update();
    public void select();
}


public class UserServiceImp implements UserService{
    @Override
    public void add() {
        System.out.println("增加了一個用戶");

    }

    @Override
    public void delete() {
        System.out.println("洗掉了一個用戶");

    }

    @Override
    public void update() {
        System.out.println("修改了一個用戶");
    }

    @Override
    public void select() {
        System.out.println("查詢了一個用戶");
    }
}

然后去寫我們的增強類 , 我們撰寫兩個 , 一個前置增強 一個后置增強

import org.springframework.aop.MethodBeforeAdvice;

import java.lang.reflect.Method;

public class log implements MethodBeforeAdvice {
   //method 要執行的目標物件的方法
    //args:引數
    //target目標物件
    @Override
    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println(target.getClass().getName()+"的"+method.getName()+"被執行了");

    }
}
package com.kk.log;

import org.springframework.aop.AfterReturningAdvice;

import java.lang.reflect.Method;

public class AfterLog implements AfterReturningAdvice {

    //returnValue 回傳值
    @Override
    public void afterReturning(Object returnValue, Method method, Object[] objects, Object o1) throws Throwable {
        System.out.println("執行了"+method.getName()+"方法,回傳結果為:"+returnValue);
    }
}

最后去spring的檔案中注冊 , 并實作aop切入實作 , 注意匯入約束 .

<?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:aop="http://www.springframework.org/schema/aop"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd">

<!--    注冊bean-->
    <bean id="userService" class="com.kk.service.UserServiceImp"></bean>
    <bean id="log" class="com.kk.log.log"></bean>
    <bean id="afterLog" class="com.kk.log.AfterLog"></bean>

    <!--方式一:使用原生的Spring API介面-->
<!--    配置aop,需要aop的約束-->
    <aop:config >
<!--        需要切入點 expression:運算式     execution() 要執行的位置-->
        <aop:pointcut id="poincut"  expression="execution(* com.kk.service.UserServiceImp.*(..))"></aop:pointcut>
       
<!--       執行環繞增加!  -->
        <aop:advisor advice-ref="log" pointcut-ref="poincut"/>
        <aop:advisor advice-ref="afterLog" pointcut-ref="poincut"/>



    </aop:config>


</beans>

測驗

import com.kk.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyTest {
    public static void main(String[] args) {
      ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
      //動態代理  代理的是介面
        UserService userService = context.getBean("userService", UserService.class);
        userService.add();
    }
}

第二種方式

9.3.2、自定義類來實作Aop【主要是切面定義】

目標業務類不變依舊是userServiceImpl

第一步 : 寫我們自己的一個切入類

public class DiyPointcut {

   public void before(){
       System.out.println("---------方法執行前---------");
  }
   public void after(){
       System.out.println("---------方法執行后---------");
  }
   
}

去spring中配置

<?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:aop="http://www.springframework.org/schema/aop"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd">

<!--    注冊bean-->
    <bean id="userService" class="com.kk.service.UserServiceImp"></bean>
    <bean id="log" class="com.kk.log.log"></bean>
    <bean id="afterLog" class="com.kk.log.AfterLog"></bean>

<!--    方式二,自定義類-->
    <bean id="diy" class="com.kk.diy.DiyPointCut"></bean>

    <aop:config>
<!--        自定義切面,使用ref呼叫要參考的類-->
        <aop:aspect ref="diy">
<!--            切入點-->
            <aop:pointcut id="point" expression="execution(* com.kk.service.UserServiceImp.*(..))"/>
<!--            通知-->
            <aop:before method="before" pointcut-ref="point"/>
            <aop:after method="after" pointcut-ref="point"/>
        </aop:aspect>
    </aop:config>


</beans>

測驗:

public class MyTest {
   @Test
   public void test(){
       ApplicationContext context = newClassPathXmlApplicationContext("beans.xml");
       UserService userService = (UserService) context.getBean("userService");
       userService.add();
  }
}

第三種方式

9.3.3、使用注解實作

第一步:撰寫一個注解實作的增強類

package com.kk.diy;

//方式三:使用注解方式實作AOP

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

@Aspect  //使用注解標記這個類是一個切面
public class AnnotationPointCut {
    @Before("execution(* com.kk.service.UserServiceImp.*(..))")  //注解的內容  應寫入插入點
    public void before(){
        System.out.println("===========方法執行前==========");
    }

    @After("execution(* com.kk.service.UserServiceImp.*(..))")
    public void after(){
        System.out.println("===========方法執行后==========");
    }

    //在環繞增加中,我們可以給定一個引數,代表我們要獲取處理的切入點
    @Around("execution(* com.kk.service.UserServiceImp.*(..))")
    public void around(ProceedingJoinPoint jp) throws Throwable {

        System.out.println("環繞前");
        Object proceed = jp.proceed();        //執行方法
        System.out.println("環繞后");

        Signature signature = jp.getSignature();//獲得簽名
        System.out.println("signature:"+signature);
        System.out.println(proceed);

    }
}

第二步:在Spring組態檔中,注冊bean,并增加支持注解的配置

<!--    方式三:使用注解實作AOP-->
    <bean id="AnnotationPointCut" class="com.kk.diy.AnnotationPointCut"></bean>

<!--    開啟注解支持  jdk(默認) proxy-target-class="false"        cglib proxy-target-class="true"   -->
    <aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy>

aop:aspectj-autoproxy:說明

通過aop命名空間的<aop:aspectj-autoproxy />宣告自動為spring容器中那些配置@aspectJ切面的bean創建代理,織入切面,當然,spring 在內部依舊采用AnnotationAwareAspectJAutoProxyCreator進行自動代理的創建作業,但具體實作的細節已經被<aop:aspectj-autoproxy />隱藏起來了

<aop:aspectj-autoproxy />有一個proxy-target-class屬性,默認為false,表示使用jdk動態代理織入增強,當配為<aop:aspectj-autoproxy  poxy-target-class="true"/>時,表示使用CGLib動態代理技術織入增強,不過即使proxy-target-class設定為false,如果目標類沒有宣告介面,則spring將自動使用CGLib動態代理,

10、整合MyBatis

步驟

1、匯入相關jar包

junit

<dependency>
   <groupId>junit</groupId>
   <artifactId>junit</artifactId>
   <version>4.12</version>
</dependency>

mybatis

<dependency>
   <groupId>org.mybatis</groupId>
   <artifactId>mybatis</artifactId>
   <version>3.5.2</version>
</dependency>

mysql-connector-java

<dependency>
   <groupId>mysql</groupId>
   <artifactId>mysql-connector-java</artifactId>
   <version>5.1.47</version>
</dependency>

spring相關

<dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-webmvc</artifactId>
   <version>5.1.10.RELEASE</version>
</dependency>
<dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-jdbc</artifactId>
   <version>5.1.10.RELEASE</version>
</dependency>

aspectJ AOP 織入器

<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
   <groupId>org.aspectj</groupId>
   <artifactId>aspectjweaver</artifactId>
   <version>1.9.4</version>
</dependency>

mybatis-spring整合包 【重點】

<dependency>
   <groupId>org.mybatis</groupId>
   <artifactId>mybatis-spring</artifactId>
   <version>2.0.2</version>
</dependency>

配置Maven靜態資源過濾問題!

<build>
   <resources>
       <resource>
           <directory>src/main/java</directory>
           <includes>
               <include>**/*.properties</include>
               <include>**/*.xml</include>
           </includes>
           <filtering>true</filtering>
       </resource>
   </resources>
</build>

2、撰寫組態檔

3、代碼實作

10.1、回憶MyBatis

1、撰寫pojo物體類

package com.kk.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;

@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class User {
    private int id;  //id
    private String name;   //姓名
    private String pwd;   //密碼

}

2、實作mybatis的組態檔

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>

    <typeAliases>
        <package name="com.kk.pojo"/>
    </typeAliases>

    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&amp;
                useUnicode=true&amp;characterEncoding=utf-8&amp;serverTimezone=GMT%2B8&amp;
                allowPublicKeyRetrieval=true"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>

    <mappers>
      <mapper class="com.kk.mapper.UserMapper"/>
    </mappers>
</configuration>

3、UserDao介面撰寫

package com.kk.mapper;

import com.kk.pojo.User;

import java.util.List;

public interface UserMapper {
    public List<User> selectUser();
}

4、介面對應的Mapper映射檔案

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.kk.mapper.UserMapper">
    <select id="selectUser" resultType="user">
        select * from mybatis.user
    </select>


</mapper>

5、測驗類

import com.kk.mapper.UserMapper;
import com.kk.pojo.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

public class MyTest {
    @Test
    public void selectUser() throws IOException {

        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        SqlSession sqlSession = sqlSessionFactory.openSession();

        UserMapper mapper = sqlSession.getMapper(UserMapper.class);

        List<User> userList = mapper.selectUser();
        for (User user: userList){
            System.out.println(user);
        }

        sqlSession.close();
    }
}

10.2、MyBatis-Spring學習

引入Spring之前需要了解mybatis-spring包中的一些重要類;

http://www.mybatis.org/spring/zh/index.html

img

什么是 MyBatis-Spring?

MyBatis-Spring 會幫助你將 MyBatis 代碼無縫地整合到 Spring 中,

知識基礎

在開始使用 MyBatis-Spring 之前,你需要先熟悉 Spring 和 MyBatis 這兩個框架和有關它們的術語,這很重要

MyBatis-Spring 需要以下版本:

MyBatis-SpringMyBatisSpring 框架Spring BatchJava
2.03.5+5.0+4.0+Java 8+
1.33.4+3.2.2+2.1+Java 6+

如果使用 Maven 作為構建工具,僅需要在 pom.xml 中加入以下代碼即可:

   <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>2.0.6</version>
        </dependency>

要和 Spring 一起使用 MyBatis,需要在 Spring 應用背景關系中定義至少兩樣東西:一個 SqlSessionFactory 和至少一個資料映射器類,

在 MyBatis-Spring 中,可使用SqlSessionFactoryBean來創建 SqlSessionFactory,要配置這個工廠 bean,只需要把下面代碼放在 Spring 的 XML 組態檔中:

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
 <property name="dataSource" ref="dataSource" />
</bean>

注意:SqlSessionFactory需要一個 DataSource(資料源),這可以是任意的 DataSource,只需要和配置其它 Spring 資料庫連接一樣配置它就可以了,

在基礎的 MyBatis 用法中,是通過 SqlSessionFactoryBuilder 來創建 SqlSessionFactory 的,而在 MyBatis-Spring 中,則使用 SqlSessionFactoryBean 來創建,

在 MyBatis 中,你可以使用 SqlSessionFactory 來創建 SqlSession,一旦你獲得一個 session 之后,你可以使用它來執行映射了的陳述句,提交或回滾連接,最后,當不再需要它的時候,你可以關閉 session,

SqlSessionFactory有一個唯一的必要屬性:用于 JDBC 的 DataSource,這可以是任意的 DataSource 物件,它的配置方法和其它 Spring 資料庫連接是一樣的,

一個常用的屬性是 configLocation,它用來指定 MyBatis 的 XML 組態檔路徑,它在需要修改 MyBatis 的基礎配置非常有用,通常,基礎配置指的是 < settings> 或 < typeAliases>元素,

需要注意的是,這個組態檔并不需要是一個完整的 MyBatis 配置,確切地說,任何環境配置(),資料源()和 MyBatis 的事務管理器()都會被忽略,SqlSessionFactoryBean 會創建它自有的 MyBatis 環境配置(Environment),并按要求設定自定義環境的值,

SqlSessionTemplate 是 MyBatis-Spring 的核心,作為 SqlSession 的一個實作,這意味著可以使用它無縫代替你代碼中已經在使用的 SqlSession,

模板可以參與到 Spring 的事務管理中,并且由于其是執行緒安全的,可以供多個映射器類使用,你應該總是用 SqlSessionTemplate 來替換 MyBatis 默認的 DefaultSqlSession 實作,在同一應用程式中的不同類之間混雜使用可能會引起資料一致性的問題,

可以使用 SqlSessionFactory 作為構造方法的引數來創建 SqlSessionTemplate 物件,

<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
 <constructor-arg index="0" ref="sqlSessionFactory" />
</bean>

現在,這個 bean 就可以直接注入到你的 DAO bean 中了,你需要在你的 bean 中添加一個 SqlSession 屬性,就像下面這樣:

package com.kk.mapper;

import com.kk.pojo.User;
import org.mybatis.spring.SqlSessionTemplate;

import java.util.List;

public class UserMapperImp implements UserMapper{

    //在原來,所有的操作,都使用SqlSession來執行; 現在都使用SqlSessionTemplate
    private SqlSessionTemplate sqlSession;
    public void setSqlSession(SqlSessionTemplate sqlSession){
        this.sqlSession=sqlSession;
    }

    @Override
    public List<User> selectUser() {
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        return mapper.selectUser();
    }
}

按下面這樣,注入 SqlSessionTemplate:

 <bean id="userMapper" class="com.kk.mapper.UserMapperImp">
        <property name="sqlSession" ref="sqlSession"/>
 </bean>

整合實作一

1、引入Spring組態檔beans.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">

2、配置資料源替換mybaits的資料源

<!--    DataSource使用Spring的資料源替換Mybatis的配置 c3p0 dbcp druid-->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&amp;
                useUnicode=true&amp;characterEncoding=utf-8&amp;serverTimezone=GMT%2B8&amp;
                allowPublicKeyRetrieval=true"/>
        <property name="username" value="root"/>
        <property name="password" value="123456"/>
    </bean>

3、配置SqlSessionFactory,關聯MyBatis

<!--    sqlSeesionFactory-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
<!--        系結mybatis組態檔-->
        <property name="configLocation" value="classpath:mybatis-config.xml"/>
        <property name="mapperLocations" value="classpath:com/kk/mapper/*.xml"/>
    </bean>

4、注冊sqlSessionTemplate,關聯sqlSessionFactory;

<!--    SqlSessionTemplate就是我們使用的sqlSession-->
    <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<!--        只能用構造器注入sqlSessionFactory,因為它沒有set方法-->
        <constructor-arg index="0" ref="sqlSessionFactory"/>
    </bean>

5、增加Mapper介面的實作類;私有化sqlSessionTemplate

package com.kk.mapper;

import com.kk.pojo.User;
import org.mybatis.spring.SqlSessionTemplate;

import java.util.List;

public class UserMapperImp implements UserMapper{

    //在原來,所有的操作,都使用SqlSession來執行; 現在都使用SqlSessionTemplate
    private SqlSessionTemplate sqlSession;
    public void setSqlSession(SqlSessionTemplate sqlSession){
        this.sqlSession=sqlSession;
    }

    @Override
    public List<User> selectUser() {
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        return mapper.selectUser();
    }
}

6、注冊bean實作

<bean id="userMapper" class="com.kk.mapper.UserMapperImp">
    <property name="sqlSession" ref="sqlSession"/>
</bean>

7、測驗

public class MyTest {
    @Test
    public void selectUser() throws IOException {

       ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
        UserMapper userMapper = context.getBean("userMapper", UserMapper.class);
        List<User> userList = userMapper.selectUser();
        for (User user : userList) {
            System.out.println(user);
        }
    }
}

結果成功輸出!現在我們的Mybatis組態檔的狀態!發現都可以被Spring整合!

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <typeAliases>
        <package name="com.kk.pojo"/>
    </typeAliases>

</configuration>

整合實作二

mybatis-spring1.2.3版以上的才有這個 .

官方檔案截圖 :

dao繼承Support類 , 直接利用 getSqlSession() 獲得 , 然后直接注入SqlSessionFactory . 比起方式1 , 不需要管理SqlSessionTemplate , 而且對事務的支持更加友好 . 可跟蹤原始碼查看

????‰?

測驗:

1、將我們上面寫的UserMapperImp修改一下

package com.kk.mapper;

import com.kk.pojo.User;
import org.apache.ibatis.session.SqlSession;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.support.SqlSessionDaoSupport;

import java.util.List;

public class UserMapperImp2 extends SqlSessionDaoSupport implements UserMapper{

    @Override
    public List<User> selectUser() {
//        SqlSession sqlSession = getSqlSession();
//        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
//        return  mapper.selectUser();
        return getSqlSession().getMapper(UserMapper.class).selectUser();
    }
}

2、修改bean的配置

<bean id="userMapper2" class="com.kk.mapper.UserMapperImp2">
  <property name="sqlSessionFactory" ref="sqlSessionFactory"/>
</bean>

3、測驗

public class MyTest {
    @Test
    public void selectUser() throws IOException {

       ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
        UserMapper userMapper = context.getBean("userMapper2", UserMapper.class);
        List<User> userList = userMapper.selectUser();
        for (User user : userList) {
            System.out.println(user);
        }

    }
}

11、宣告式事務

  • 事務在專案開發程序非常重要,涉及到資料的一致性的問題,不容馬虎!
  • 事務管理是企業級應用程式開發中必備技術,用來確保資料的完整性和一致性,
  • 事務就是把一系列的動作當成一個獨立的作業單元,這些動作要么全部完成,要么全部不起作用,

事務四個屬性ACID

原子性(atomicity)

  • 事務是原子性操作,由一系列動作組成,事務的原子性確保動作要么全部完成,要么完全不起作用

一致性(consistency)

  • 一旦所有事務動作完成,事務就要被提交,資料和資源處于一種滿足業務規則的一致性狀態中

隔離性(isolation)

  • 可能多個事務會同時處理相同的資料,因此每個事務都應該與其他事務隔離開來,防止資料損壞

持久性(durability)

  • 事務一旦完成,無論系統發生什么錯誤,結果都不會受到影響,通常情況下,事務的結果被寫到持久化存盤器中

測驗

將上面的代碼拷貝到一個新專案中

在之前的案例中,我們給userDao介面新增兩個方法,洗掉和增加用戶;

//添加一個用戶
int addUser(User user);

//根據id洗掉用戶
int deleteUser(int id);

mapper檔案,我們故意把 deletes 寫錯,測驗!

<insert id="addUser" parameterType="com.kk.pojo.User">
insert into user (id,name,pwd) values (#{id},#{name},#{pwd})
</insert>

<delete id="deleteUser" parameterType="int">
deletes from user where id = #{id}
</delete>

撰寫介面的實作類,在實作類中,我們去操作一波

public class UserMapperImpl extends SqlSessionDaoSupport implements UserMapper {

   //增加一些操作
   public List<User> selectUser() {
       User user = new User(8,"bb","123456");
       UserMapper mapper = getSqlSession().getMapper(UserMapper.class);
       mapper.addUser(user);
       mapper.deleteUser(4);
       return mapper.selectUser();
  }

   //新增
   public int addUser(User user) {
       UserMapper mapper = getSqlSession().getMapper(UserMapper.class);
       return mapper.addUser(user);
  }
   //洗掉
   public int deleteUser(int id) {
       UserMapper mapper = getSqlSession().getMapper(UserMapper.class);
       return mapper.deleteUser(id);
  }

}

測驗

public class MyTest {
        public static void main(String[] args) {
       ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
        UserMapper userMapper = context.getBean("userMapper", UserMapper.class);
        List<User> userList = userMapper.selectUser();
    }
}

Resources:

mybatis-config.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>

    <typeAliases>
        <package name="com.kk.pojo"/>
    </typeAliases>


</configuration>

spring-dao.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"
        xmlns:aop="http://www.springframework.org/schema/aop"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--    DataSource使用Spring的資料源替換Mybatis的配置 c3p0 dbcp druid-->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&amp;
                useUnicode=true&amp;characterEncoding=utf-8&amp;serverTimezone=GMT%2B8&amp;
                allowPublicKeyRetrieval=true"/>
        <property name="username" value="root"/>
        <property name="password" value="123456"/>
    </bean>

<!--    sqlSeesionFactory-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
<!--        系結mybatis組態檔-->
        <property name="configLocation" value="classpath:mybatis-config.xml"/>
        <property name="mapperLocations" value="classpath:com/kk/mapper/*.xml"/>
    </bean>

<!--    SqlSessionTemplate就是我們使用的sqlSession-->
    <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<!--        只能用構造器注入sqlSessionFactory,因為它沒有set方法-->
        <constructor-arg index="0" ref="sqlSessionFactory"/>
    </bean>

    <bean id="userMapper" class="com.kk.mapper.UserMapperImp">
        <property name="sqlSessionFactory" ref="sqlSessionFactory"/>
    </bean>



</beans>

application.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"
        xmlns:aop="http://www.springframework.org/schema/aop"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd">

    <import resource="spring-dao.xml"/>

    <bean id="userMapper" class="com.kk.mapper.UserMapperImp">
        <property name="sqlSessionFactory" ref="sqlSessionFactory"/>
    </bean>

</beans>

Spring在不同的事務管理API之上定義了一個抽象層,使得開發人員不必了解底層的事務管理API就可以使用Spring的事務管理機制,Spring支持編程式事務管理和宣告式的事務管理,

編程式事務管理

  • 將事務管理代碼嵌到業務方法中來控制事務的提交和回滾
  • 缺點:必須在每個事務操作業務邏輯中包含額外的事務管理代碼

宣告式事務管理

  • 一般情況下比編程式事務好用,
  • 將事務管理代碼從業務方法中分離出來,以宣告的方式來實作事務管理,
  • 將事務管理作為橫切關注點,通過aop方法模塊化,Spring中通過Spring AOP框架支持宣告式事務管理,

JDBC事務

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
       <property name="dataSource" ref="dataSource" />
</bean>

配置好事務管理器后我們需要去配置事務的通知

<!--配置事務通知-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
   <tx:attributes>
       <!--配置哪些方法使用什么樣的事務,配置事務的傳播特性-->
       <tx:method name="add" propagation="REQUIRED"/>
       <tx:method name="delete" propagation="REQUIRED"/>
       <tx:method name="update" propagation="REQUIRED"/>
       <tx:method name="search*" propagation="REQUIRED"/>
       <tx:method name="get" read-only="true"/>
       <tx:method name="*" propagation="REQUIRED"/>
   </tx:attributes>
</tx:advice>

spring事務傳播特性:

事務傳播行為就是多個事務方法相互呼叫時,事務如何在這些方法間傳播,spring支持7種事務傳播行為:

  • propagation_requierd:如果當前沒有事務,就新建一個事務,如果已存在一個事務中,加入到這個事務中,這是最常見的選擇,
  • propagation_supports:支持當前事務,如果沒有當前事務,就以非事務方法執行,
  • propagation_mandatory:使用當前事務,如果沒有當前事務,就拋出例外,
  • propagation_required_new:新建事務,如果當前存在事務,把當前事務掛起,
  • propagation_not_supported:以非事務方式執行操作,如果當前存在事務,就把當前事務掛起,
  • propagation_never:以非事務方式執行操作,如果當前事務存在則拋出例外,
  • propagation_nested:如果當前存在事務,則在嵌套事務內執行,如果當前沒有事務,則執行與propagation_required類似的操作

Spring 默認的事務傳播行為是 PROPAGATION_REQUIRED,它適合于絕大多數的情況,

假設 ServiveX#methodX() 都作業在事務環境下(即都被 Spring 事務增強了),假設程式中存在如下的呼叫鏈:Service1#method1()->Service2#method2()->Service3#method3(),那么這 3 個服務類的 3 個方法通過 Spring 的事務傳播機制都作業在同一個事務中,

就好比,我們剛才的幾個方法存在呼叫,所以會被放在一組事務當中!

配置AOP

匯入aop的頭檔案!

<!--配置aop織入事務-->
<aop:config>
   <aop:pointcut id="txPointcut" expression="execution(* com.kuang.dao.*.*(..))"/>
   <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/>
</aop:config>

刪掉剛才插入的資料,再次測驗!

@Test
public void test2(){
   ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
   UserMapper mapper = (UserMapper) context.getBean("UserMapper");
   List<User> user = mapper.selectUser();
   System.out.println(user);
}

r" class=“com.kk.mapper.UserMapperImp”>

```

application.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"
        xmlns:aop="http://www.springframework.org/schema/aop"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd">

    <import resource="spring-dao.xml"/>

    <bean id="userMapper" class="com.kk.mapper.UserMapperImp">
        <property name="sqlSessionFactory" ref="sqlSessionFactory"/>
    </bean>

</beans>

Spring在不同的事務管理API之上定義了一個抽象層,使得開發人員不必了解底層的事務管理API就可以使用Spring的事務管理機制,Spring支持編程式事務管理和宣告式的事務管理,

編程式事務管理

  • 將事務管理代碼嵌到業務方法中來控制事務的提交和回滾
  • 缺點:必須在每個事務操作業務邏輯中包含額外的事務管理代碼

宣告式事務管理

  • 一般情況下比編程式事務好用,
  • 將事務管理代碼從業務方法中分離出來,以宣告的方式來實作事務管理,
  • 將事務管理作為橫切關注點,通過aop方法模塊化,Spring中通過Spring AOP框架支持宣告式事務管理,

JDBC事務

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
       <property name="dataSource" ref="dataSource" />
</bean>

配置好事務管理器后我們需要去配置事務的通知

<!--配置事務通知-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
   <tx:attributes>
       <!--配置哪些方法使用什么樣的事務,配置事務的傳播特性-->
       <tx:method name="add" propagation="REQUIRED"/>
       <tx:method name="delete" propagation="REQUIRED"/>
       <tx:method name="update" propagation="REQUIRED"/>
       <tx:method name="search*" propagation="REQUIRED"/>
       <tx:method name="get" read-only="true"/>
       <tx:method name="*" propagation="REQUIRED"/>
   </tx:attributes>
</tx:advice>

spring事務傳播特性:

事務傳播行為就是多個事務方法相互呼叫時,事務如何在這些方法間傳播,spring支持7種事務傳播行為:

  • propagation_requierd:如果當前沒有事務,就新建一個事務,如果已存在一個事務中,加入到這個事務中,這是最常見的選擇,
  • propagation_supports:支持當前事務,如果沒有當前事務,就以非事務方法執行,
  • propagation_mandatory:使用當前事務,如果沒有當前事務,就拋出例外,
  • propagation_required_new:新建事務,如果當前存在事務,把當前事務掛起,
  • propagation_not_supported:以非事務方式執行操作,如果當前存在事務,就把當前事務掛起,
  • propagation_never:以非事務方式執行操作,如果當前事務存在則拋出例外,
  • propagation_nested:如果當前存在事務,則在嵌套事務內執行,如果當前沒有事務,則執行與propagation_required類似的操作

Spring 默認的事務傳播行為是 PROPAGATION_REQUIRED,它適合于絕大多數的情況,

假設 ServiveX#methodX() 都作業在事務環境下(即都被 Spring 事務增強了),假設程式中存在如下的呼叫鏈:Service1#method1()->Service2#method2()->Service3#method3(),那么這 3 個服務類的 3 個方法通過 Spring 的事務傳播機制都作業在同一個事務中,

就好比,我們剛才的幾個方法存在呼叫,所以會被放在一組事務當中!

配置AOP

匯入aop的頭檔案!

<!--配置aop織入事務-->
<aop:config>
   <aop:pointcut id="txPointcut" expression="execution(* com.kuang.dao.*.*(..))"/>
   <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/>
</aop:config>

刪掉剛才插入的資料,再次測驗!

@Test
public void test2(){
   ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
   UserMapper mapper = (UserMapper) context.getBean("UserMapper");
   List<User> user = mapper.selectUser();
   System.out.println(user);
}

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/298109.html

標籤:java

上一篇:(快)開學了,各大編程語言在群里吵翻了天!

下一篇:騰訊擬推出微信聊天記錄云存盤付費服務,網友質疑:有必要嗎?

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【C++】Microsoft C++、C 和匯編程式檔案

    ......

    uj5u.com 2020-09-10 00:57:23 more
  • 例外宣告

    相比于斷言適用于排除邏輯上不可能存在的狀態,例外通常是用于邏輯上可能發生的錯誤。 例外宣告 Item 1:當函式不可能拋出例外或不能接受拋出例外時,使用noexcept 理由 如果不打算拋出例外的話,程式就會認為無法處理這種錯誤,并且應當盡早終止,如此可以有效地阻止例外的傳播與擴散。 示例 //不可 ......

    uj5u.com 2020-09-10 00:57:27 more
  • Codeforces 1400E Clear the Multiset(貪心 + 分治)

    鏈接:https://codeforces.com/problemset/problem/1400/E 來源:Codeforces 思路:給你一個陣列,現在你可以進行兩種操作,操作1:將一段沒有 0 的區間進行減一的操作,操作2:將 i 位置上的元素歸零。最終問:將這個陣列的全部元素歸零后操作的最少 ......

    uj5u.com 2020-09-10 00:57:30 more
  • UVA11610 【Reverse Prime】

    本人看到此題沒有翻譯,就附帶了一個自己的翻譯版本 思考 這一題,它的第一個要求是找出所有 $7$ 位反向質數及其質因數的個數。 我們應該需要質數篩篩選1~$10^{7}$的所有數,這里就不慢慢介紹了。但是,重讀題,我們突然發現反向質數都是 $7$ 位,而將它反過來后的數字卻是 $6$ 位數,這就說明 ......

    uj5u.com 2020-09-10 00:57:36 more
  • 統計區間素數數量

    1 #pragma GCC optimize(2) 2 #include <bits/stdc++.h> 3 using namespace std; 4 bool isprime[1000000010]; 5 vector<int> prime; 6 inline int getlist(int ......

    uj5u.com 2020-09-10 00:57:47 more
  • C/C++編程筆記:C++中的 const 變數詳解,教你正確認識const用法

    1、C中的const 1、區域const變數存放在堆疊區中,會分配記憶體(也就是說可以通過地址間接修改變數的值)。測驗代碼如下: 運行結果: 2、全域const變數存放在只讀資料段(不能通過地址修改,會發生寫入錯誤), 默認為外部聯編,可以給其他源檔案使用(需要用extern關鍵字修飾) 運行結果: ......

    uj5u.com 2020-09-10 00:58:04 more
  • 【C++犯錯記錄】VS2019 MFC添加資源不懂如何修改資源宏ID

    1. 首先在資源視圖中,添加資源 2. 點擊新添加的資源,復制自動生成的ID 3. 在解決方案資源管理器中找到Resource.h檔案,編輯,使用整個專案搜索和替換的方式快速替換 宏宣告 4. Ctrl+Shift+F 全域搜索,點擊查找全部,然后逐個替換 5. 為什么使用搜索替換而不使用屬性視窗直 ......

    uj5u.com 2020-09-10 00:59:11 more
  • 【C++犯錯記錄】VS2019 MFC不懂的批量添加資源

    1. 打開資源頭檔案Resource.h,在其中預先定義好宏 ID(不清楚其實ID值應該設定多少,可以先新建一個相同的資源項,再在這個資源的ID值的基礎上遞增即可) 2. 在資源視圖中選中專案資源,按F7編輯資源檔案,按 ID 型別 相對路徑的形式添加 資源。(別忘了先把檔案拷貝到專案中的res檔案 ......

    uj5u.com 2020-09-10 01:00:19 more
  • C/C++編程筆記:關于C++的參考型別,專供新手入門使用

    今天要講的是C++中我最喜歡的一個用法——參考,也叫別名。 參考就是給一個變數名取一個變數名,方便我們間接地使用這個變數。我們可以給一個變數創建N個參考,這N + 1個變數共享了同一塊記憶體區域。(參考型別的變數會占用記憶體空間,占用的記憶體空間的大小和指標型別的大小是相同的。雖然參考是一個物件的別名,但 ......

    uj5u.com 2020-09-10 01:00:22 more
  • 【C/C++編程筆記】從頭開始學習C ++:初學者完整指南

    眾所周知,C ++的學習曲線陡峭,但是花時間學習這種語言將為您的職業帶來奇跡,并使您與其他開發人員區分開。您會更輕松地學習新語言,形成真正的解決問題的技能,并在編程的基礎上打下堅實的基礎。 C ++將幫助您養成良好的編程習慣(即清晰一致的編碼風格,在撰寫代碼時注釋代碼,并限制類內部的可見性),并且由 ......

    uj5u.com 2020-09-10 01:00:41 more
最新发布
  • Rust中的智能指標:Box<T> Rc<T> Arc<T> Cell<T> RefCell<T> Weak

    Rust中的智能指標是什么 智能指標(smart pointers)是一類資料結構,是擁有資料所有權和額外功能的指標。是指標的進一步發展 指標(pointer)是一個包含記憶體地址的變數的通用概念。這個地址參考,或 ” 指向”(points at)一些其 他資料 。參考以 & 符號為標志并借用了他們所 ......

    uj5u.com 2023-04-20 07:24:10 more
  • Java的值傳遞和參考傳遞

    值傳遞不會改變本身,參考傳遞(如果傳遞的值需要實體化到堆里)如果發生修改了會改變本身。 1.基本資料型別都是值傳遞 package com.example.basic; public class Test { public static void main(String[] args) { int ......

    uj5u.com 2023-04-20 07:24:04 more
  • [2]SpinalHDL教程——Scala簡單入門

    第一個 Scala 程式 shell里面輸入 $ scala scala> 1 + 1 res0: Int = 2 scala> println("Hello World!") Hello World! 檔案形式 object HelloWorld { /* 這是我的第一個 Scala 程式 * 以 ......

    uj5u.com 2023-04-20 07:23:58 more
  • 理解函式指標和回呼函式

    理解 函式指標 指向函式的指標。比如: 理解函式指標的偽代碼 void (*p)(int type, char *data); // 定義一個函式指標p void func(int type, char *data); // 宣告一個函式func p = func; // 將指標p指向函式func ......

    uj5u.com 2023-04-20 07:23:52 more
  • Django筆記二十五之資料庫函式之日期函式

    本文首發于公眾號:Hunter后端 原文鏈接:Django筆記二十五之資料庫函式之日期函式 日期函式主要介紹兩個大類,Extract() 和 Trunc() Extract() 函式作用是提取日期,比如我們可以提取一個日期欄位的年份,月份,日等資料 Trunc() 的作用則是截取,比如 2022-0 ......

    uj5u.com 2023-04-20 07:23:45 more
  • 一天吃透JVM面試八股文

    什么是JVM? JVM,全稱Java Virtual Machine(Java虛擬機),是通過在實際的計算機上仿真模擬各種計算機功能來實作的。由一套位元組碼指令集、一組暫存器、一個堆疊、一個垃圾回收堆和一個存盤方法域等組成。JVM屏蔽了與作業系統平臺相關的資訊,使得Java程式只需要生成在Java虛擬機 ......

    uj5u.com 2023-04-20 07:23:31 more
  • 使用Java接入小程式訂閱訊息!

    更新完微信服務號的模板訊息之后,我又趕緊把微信小程式的訂閱訊息給實作了!之前我一直以為微信小程式也是要企業才能申請,沒想到小程式個人就能申請。 訊息推送平臺🔥推送下發【郵件】【短信】【微信服務號】【微信小程式】【企業微信】【釘釘】等訊息型別。 https://gitee.com/zhongfuch ......

    uj5u.com 2023-04-20 07:22:59 more
  • java -- 緩沖流、轉換流、序列化流

    緩沖流 緩沖流, 也叫高效流, 按照資料型別分類: 位元組緩沖流:BufferedInputStream,BufferedOutputStream 字符緩沖流:BufferedReader,BufferedWriter 緩沖流的基本原理,是在創建流物件時,會創建一個內置的默認大小的緩沖區陣列,通過緩沖 ......

    uj5u.com 2023-04-20 07:22:49 more
  • Java-SpringBoot-Range請求頭設定實作視頻分段傳輸

    老實說,人太懶了,現在基本都不喜歡寫筆記了,但是網上有關Range請求頭的文章都太水了 下面是抄的一段StackOverflow的代碼...自己大修改過的,寫的注釋挺全的,應該直接看得懂,就不解釋了 寫的不好...只是希望能給視頻網站開發的新手一點點幫助吧. 業務場景:視頻分段傳輸、視頻多段傳輸(理 ......

    uj5u.com 2023-04-20 07:22:42 more
  • Windows 10開發教程_編程入門自學教程_菜鳥教程-免費教程分享

    教程簡介 Windows 10開發入門教程 - 從簡單的步驟了解Windows 10開發,從基本到高級概念,包括簡介,UWP,第一個應用程式,商店,XAML控制元件,資料系結,XAML性能,自適應設計,自適應UI,自適應代碼,檔案管理,SQLite資料庫,應用程式到應用程式通信,應用程式本地化,應用程式 ......

    uj5u.com 2023-04-20 07:22:35 more