Spring入門及IOC

Spring簡介

Spring 意爲 春天,指的是給軟件行業帶來春天。在2002 年,首次推出了Spring框架的雛形interface21框架。Spring框架以interface21框架爲基礎,經過重新設計,並不斷豐富其內涵,於2004年3月24日,發佈了1.0正式版。

Spring 是個Java企業級應用的開源開發框架。Spring主要用來開發Java應用,但是有些擴展是針對構建J2EE平臺的web應用。

Spring 框架目標是:簡化Java企業級應用開發,並通過pojo爲基礎的編程模型促進良好的編程習慣。

Spring理念是:使現有的技術更加容易使用,它整合了現有的技術框架。

有關Spring的網址:

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

官方下載地址: http://repo.spring.io/release/org/springframework/spring

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

Spring的依賴:

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

Spring的優點:

  • Spring是一個開源的免費的框架(容器),支持事務的處理,支持框架整合。
  • Spring是一個輕量級的、非入侵式的框架,基本的版本大約2MB。
  • 控制反轉(IOC),Spring通過控制反轉實現了鬆散耦合,對象們給出它們的依賴,而不是創建或查找依賴的對象們。
  • 面向切面編程(AOP),Spring支持面向切面的編程,並且把應用業務邏輯和系統服務分開。
  • 容器,Spring 包含並管理應用中對象的生命週期和配置。
  • MVC框架,Spring的WEB框架是個精心設計的框架,是Web框架的一個很好的替代品。
  • 事務管理,Spring 提供一個持續的事務管理接口,可以擴展到上至本地事務下至全局事務。
  • 異常處理,Spring 提供方便的API把具體技術相關的異常轉化爲一致的unchecked 異常。

Spring就是一個輕量級的控制反轉(IOC) 和麪向切面編程(AOP)的框架

Spring的組成:

IOC

IOC思想

搭建環境並測試:

  1. 編寫User實體類
  2. 編寫UserMapper接口
  3. 編寫UserMapperImpl實現類
  4. 編寫UserService業務接口
  5. 編寫UserServiceImpl 業務實現類
  6. 編寫測試類

在業務中,用戶的需求可能會發生改變,此時我們的代碼就需要對應地進行修改。如果程序的代碼量很大的話,修改一次的成本代價則會什麼昂貴。

在業務層處理時,是由程序員創建對象的,可以說主動權在程序員手中,程序員決定了程序調用什麼。

但是當使用一個set方法時,會發生革命性的變化。

利用set可以動態地實現值的注入。

對比:

  • 沒使用set之前,程序是主動創建對象,控制權掌握在程序員手中。
  • 使用set注入後,程序不再具有主動性,而是被動地接受對象。

動態的注入這種思想,從本質上解決了問題,我們不用管對象的創建了,同時系統的耦合性大大降低了。我們可以更加專注地在業務的實現上,這就是IOC 的原型。

IOC本質

IOC(Inverse of Control),控制反轉,是一種設計思想;DI(Dependency Injection),依賴注入則是顯示IOC的一種方法。在沒有IOC的程序中,我們使用面向對象編程,對象的創建和對象間的依賴關係完全硬編碼在程序中,對象的創建由程序自己控制,控制反轉後則將對象的創建轉移給第三方,所謂控制反轉可以理解爲:獲得依賴對象的方式反轉了。

採用xml方式配置bean的時候,bean的定義信息是和實現分離的,而採用註解的方式可以把兩者合爲一體,bean的定義信息直接以註解的形式定義在實現類中,從而達到了零配置的目的。

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

第一個Spring程序

1. 導入Spring相關的jar包

Spring需要導入commons-logging進行日誌記錄 。我們使用maven , 他會自動下載對應的依賴項。

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

2. 編寫相關的代碼

編寫一個Hello實體類

package com.llx.pojo;

public class Hello {
    private String name;

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

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

編寫我們的Spring文件,將其命名爲applicationContext.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
        https://www.springframework.org/schema/beans/spring-beans.xsd ">

    <bean id="hello" name="hello2 hello3 hello4" class="com.llx.pojo.Hello">
        <property name="name" value="Spring"/>
    </bean>

</beans>

測試

@Test
    public void testHello(){
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        Hello hello = (Hello) context.getBean("hello");
        hello.show();
    }

進行測試完之後,我們可以理解:

  • Hello對象是由Spring創建的
  • Hello對象的屬性是有Spring容器設置的

這個過程就叫做控制反轉。

控制:誰來控制對象的創建?傳統應用程序的對象是由程序本身控制創建的;使用Spring後,對象則是由Spring來創建的。

反轉:程序本身不創建對象,而變成被動地接受對象。

依賴注入:利用set方法來進行注入。

IOC是一種編程思想,由主動編程變爲被動接受。

理解了IOC之後,我們可以徹底不用再去程序中進行改動了,要實現不同的操作,只需要在xml配置文件中進行修改。所謂的IOC,即 對象由Spring來創建,管理和裝配。

IOC創建對象的方式

使用無參構造創建對象

可以使用無參構造創建對象,這是默認的方式。

使用有參構造創建對象

如果要使用有參構造來創建對象,有以下幾種方式:

  • 下標賦值

    <!--第一種,下標賦值!-->
    <bean id="user" class="com.llx.pojo.User">
        <constructor-arg index="0" value="llx"/>
    </bean>
    
  • 類型

    <!--第二種方式:通過類型創建,不建議使用!-->
    <bean id="user" class="com.llx.pojo.User">
        <constructor-arg type="java.lang.String" value="LLX"/>
    </bean>
    
  • 參數名

    <!--第三種,直接通過參數名來設置-->
    <bean id="user" class="com.kuang.pojo.User">
        <constructor-arg name="name" value="LLX1"/>
    </bean>
    

在配置文件加載的時候,容器中管理的對象就已經初始化了!

Spring配置

別名

對對象設置別名,設置別名後,也可以通過別名獲取到這個對象。

<alias name="user" alias="userNew"/>

Bean的配置

bean標籤 中有幾個常用的屬性:

屬性 含義
id id是bean的唯一標識符,即相當於我們學的對象名
class class是bean對象所對應的全限定名即 包名+類名
name name是別名,而且name可以同時取多個別名
<bean id="hello" name="hello2 hello3 hello4" class="com.llx.pojo.Hello">
        <property name="name" value="Spring"/>
</bean>

import

import,一般用於團隊開發,可以將多個配置文件導入合併爲一個。

將多個配置文件,使用import標籤,導入在applicationContext.xml中即可。

<import resource="user.xml"/>
<import resource="hello.xml"/>
<import resource="bean.xml"/>

在使用的時候,使用總的配置文件applicationContext.xml即可。

依賴注入

依賴注入的方式有好幾種:

  • 構造器注入
  • set方式注入
  • p命令空間和c命令空間

set方式注入

set注入:

  • 依賴:bean對象的創建依賴於容器
  • 注入:bean對象中的所有屬性,由容器來注入

環境搭建

1、編寫一個Address類,複雜類型:

package com.llx.pojo;

public class Address {
    private String address;

    private com.llx.pojo.Student student;

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

    public String getAddress() {
        return address;
    }
}

2、編寫Student類,真實測試對象

package com.llx.pojo;

import java.util.*;

public class Student {

    private String name;
    private Address address;
    private String[] books;
    private List<String> list;
    private Map<String,String> map;
    private Set<String> set;
    private String wife ;// null
    private Properties info;

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

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

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

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

    public void setMap(Map<String, String> map) {
        this.map = map;
    }

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

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

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

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", address=" + address.getAddress() +
                ", books=" + Arrays.toString(books) +
                ", list=" + list +
                ", map=" + map +
                ", set=" + set +
                ", wife='" + wife + '\'' +
                ", info=" + info +
                '}';
    }
}

3、編寫student.xml配置文件,並將其導入applicationContext.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
        https://www.springframework.org/schema/beans/spring-beans.xsd">
    
    <bean id="student" class="com.llx.pojo.Student">
        <property name="name" value="llx"/>
    </bean>

</beans>

4、測試類

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

完整的注入信息如下:

<?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
        https://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="addr" class="com.llx.pojo.Address">
        <property name="address" value="西安"/>
    </bean>
    <bean id="student" class="com.llx.pojo.Student" scope="singleton">
        <!--第一種,普通值注入,value-->
        <property name="name" value="llx"/>
        <!--第二種,Bean注入,ref-->
        <property name="address" ref="addr"/>
        <!--數組-->
        <property name="books">
            <array>
                <value>西遊記</value>
                <value>紅樓夢</value>
                <value>水滸傳</value>
            </array>
        </property>
        <!--List-->
        <property name="list">
            <list>
                <value>list1</value>
                <value>list2</value>
                <value>list3</value>
            </list>
        </property>
        <!--Map-->
        <property name="map">
            <map>
                <entry key="key1" value="v1"/>
                <entry key="key2" value="v2"/>
                <entry key="key3" value="v3"/>
            </map>
        </property>
         <!--Set-->
        <property name="set">
            <set>
                <value>set1</value>
                <value>set2</value>
                <value>set3</value>
            </set>
        </property>
        <!--null-->
        <property name="wife">
            <null/>
        </property>
        <!--Properties-->
        <property name="info">
            <props>
                <prop key="id">122</prop>
                <prop key="name">llx</prop>
                <prop key="sex">female</prop>
            </props>
        </property>
    </bean>
</beans>

拓展方式注入

可以使用 p命名空間和c命名空間進行注入。

<?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
        https://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--p命名空間注入,可以直接注入屬性的值:property-->
    <bean id="user" class="com.llx.pojo.User" p:name="llx" p:age="20"/>

    <!--c命名空間注入,通過構造器注入:construct-args-->
    <bean id="user2" class="com.llx.pojo.User" c:age="20" c:name="llx2"/>

</beans>

測試:

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

需要注意的是,p命名和c命名空間不能直接使用,需要導入xml約束纔可以。

xmlns:c="http://www.springframework.org/schema/c"
xmlns:p="http://www.springframework.org/schema/p"

bean的作用域

單例模式

單例模式是Spring的默認機制。

<bean id="student" class="com.llx.pojo.Student" scope="singleton">
        <property name="name" value="劉麗俠"/>
</bean>

原型模式

原型模式,每次從容器中get的時候,都會產生一個新的對象

<bean id="student" class="com.llx.pojo.Student" scope="prototype">
        <property name="name" value="劉麗俠"/>
</bean>

其餘的 request、session、application,這些只能在web開發中使用到。

Bean的自動裝配

自動裝配是Spring滿足bean依賴的一種方式。

Spring會在上下文中自動尋找,並自動給bean裝配屬性。

在Spring中有三中配置的方式:

  • 在xml配置文件中顯式地配置
  • 在java中顯式地配置
  • 隱式地自動裝配

自動裝配有兩種方式:ByName和ByType。

測試環境搭建:

以一個人有貓和狗兩個寵物爲例。

1、編寫實體類:

Cat類

package com.llx.entity;

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

Dog類

package com.llx.entity;

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

User類

package com.llx.entity;

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

import javax.annotation.Resource;

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = 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;
    }

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

    }
}

2、編寫user.xml文件,並導入到applicationContext.xml中

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd">

    <bean id="cat" class="com.llx.entity.Cat"/>
    <bean id="dog" class="com.llx.entity.Dog"/>

    <bean id="user" class="com.llx.entity.User">
        <property name="cat" ref="cat"/>
        <property name="dog" ref="dog"/>
        <property name="name" value="llx"/>
    </bean>

</beans>

3、編寫測試類

@Test
    public void test4(){
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        User user = (User) context.getBean("user");
        System.out.println(user.toString());

    }

ByName自動裝配

設置bean的autowire屬性爲byName。

byName:會自動在容器上下文中查找,和自己對象set方法後面的值對應的bean id。

 <bean id="cat" class="com.llx.entity.Cat"/>
 <bean id="dog" class="com.llx.entity.Dog"/>

 <bean id="user" class="com.llx.entity.User" autowire="byName">
     <property name="name" value="llx"/>
 </bean>

ByType自動匹配

設置bean的autowire屬性爲byType。

byType:會自動在容器上下文中查找,和自己對象屬性類型相同的bean

 <bean id="cat" class="com.llx.entity.Cat"/>
 <bean id="dog" class="com.llx.entity.Dog"/>

 <bean id="user" class="com.llx.entity.User" autowire="byType">
     <property name="name" value="llx"/>
 </bean>

總結:

  • 使用byname的時候,需要保證所有bean的id唯一,並且這個bean需要和自動注入的屬性的set方法的值一致!
  • 使用bytype的時候,需要保證所有bean的class唯一,並且這個bean需要和自動注入的屬性的類型一致!

使用註解實現自動裝配

使用註解的時候,需要導入約束(context約束);配置註解的支持<context:annotation-config/>

在xml文件中配置<context:annotation-config/>

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

    <context:annotation-config/>

</beans>

@Autowired註解

@Autowired註解可以直接在屬性上使用,也可以在set方法是使用。

@Autowired 通過byType的方式實現。

使用@Autowired註解,我們可以不用編寫set方法,但是前提是自動裝配的屬性在 IOC(Spring)容器中存在,且符合名字byname。

package com.llx.entity;

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

import javax.annotation.Resource;

public class User {
    private String name;
    @Autowired
    private Cat cat;
    @Autowired
    private Dog dog;

    public String getName() {
        return name;
    }

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

    public Cat getCat() {
        return cat;
    }

    public Dog getDog() {
        return dog;
    }

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

如果顯示定義了Autowired的required屬性爲false,說明這個對象可以爲null,否則不允許爲空。

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

@Autowired
@Qualifier("dog1")  // 匹配指定對象,若沒有,則會報紅
private Dog dog;
<bean id="dog1" class="com.llx.entity.Dog"/>
<bean id="dog2" class="com.llx.entity.Dog"/>

@Resource註解

@Resource註解是java的註解,作用同 Autowired 和 Qualifier。

@ Resource 默認通過byname的方式實現。

@Resource(name = "cat2")   // java 的註解 配置 作用同 Autowired 和 Qualifier
private Cat cat;

@Resource 和@ Autowired 的區別:

  • 兩者都是用來自動裝配的,都可以放在屬性字段上
  • @ Autowired 通過byType的方式實現,而且必須要求這個對象存在! 【常用】
  • @ Resource 默認通過byname的方式實現,如果找不到名字,則通過byType實現!如果兩個都找不到的情況下,就報錯! 【常用】
  • 執行順序不同:@ Autowired 通過byType的方式實現。@ Resource 默認通過byname的方式實現。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章