1. 程式人生 > >Spring學習總結:IOC基礎

Spring學習總結:IOC基礎

spring概述

spring可以做很多事情,它為企業級開發提供了豐富的功能。但是這些功能的底層都依賴於它的兩個核心特性,控制反轉(IOC)和麵向切面(AOP)、
本篇文章主要介紹IOC。

現在 springboot 和spring cloud十分火爆,還是有必要看看兩者之間的關係的

Spring Boot 是 Spring 的一套快速配置腳手架,可以基於Spring Boot 快速開發單個微服務,Spring Cloud是一個基於Spring Boot實現的雲應用開發工具;Spring Boot專注於快速、方便整合的單個微服務個體,Spring Cloud關注全域性的服務治理框架

;Spring Boot使用了約束優於配置的理念,很多整合方案已經幫你選擇好了,能不配置就不配置,Spring Cloud很大的一部分是基於Spring Boot來實現,Spring Boot可以離開Spring Cloud獨立使用開發專案,但是Spring Cloud離不開Spring Boot,屬於依賴的關係

 

Ioc基礎

控制反轉IOC是一種設計思想,DI(依賴注入)是實現IOC的一種方法。(下面的這張圖畫的太好了)

  • 沒有IOC的程式中我們使用面向物件程式設計物件的創建於物件間的依賴關係完全硬編碼在程式中,物件的建立由程式自己控制。
  • 控制反轉後將物件的建立轉移給第三方。

IOC是spring框架的核心內容,使用多種方式完美的實現了IOC,可以使用xml配置,也可以使用註解,新版本的spring可以零配置實現IOC。

使用XML配置方式實現IOC

  • 建立maven專案
  • pom檔案如下
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.kevin</groupId>
    <artifactId>spring</artifactId>
    <version>1.0-SNAPSHOT</version>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <spring.version>4.3.0.RELEASE</spring.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <scope>test</scope>
            <version>4.10</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.8.9</version>
        </dependency>
        <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>3.2.4</version>
        </dependency>
    </dependencies>

</project>

使用無參構造方法建立物件

新建一個Music類

/**
 * 音樂
 *
 * @author: kevin
 * @Date: 2018/12/8
 */
public class Music {
    public Music() {
        System.out.println("播放周杰倫的《七里香》");
    }
}

resources資料夾下新建music.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">
    <bean id="jay" class="com.kevin.spring.demo1.entity.Music"></bean>
</beans>

測試類

package com.kevin.spring.demo1.test;

import com.kevin.spring.demo1.entity.Music;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @author: kevin
 * @Date: 2018/12/8
 */
public class Test {
    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("music.xml");
        Music jay = ctx.getBean("jay", Music.class);
    }
}

執行結果

資訊: Loading XML bean definitions from class path resource [music.xml]
播放周杰倫的《七里香》

使用有參構造方法建立物件

Person

package com.kevin.spring.demo2.entity;

/**
 * 人類
 */
public abstract class Person {

    public String name;
}

Student

package com.kevin.spring.demo2.entity;

/**
 * 學生
 */
public class Student extends Person{

    /**
     * 身高
     */
    public int height;

    /**
     * 有參建構函式
     * @param name
     * @param height
     */
    public Student(String name,int height) {
        this.name = name;
        this.height = height;
    }

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

student.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">
    <bean id="kevin" class="com.kevin.spring.demo2.entity.Student">
        <constructor-arg name="name" value="kevin"></constructor-arg>
        <constructor-arg name="height" value="170"></constructor-arg>
    </bean>

    <!--使用索引指定引數-->
    <bean id="maomao" class="com.kevin.spring.demo2.entity.Student">
        <constructor-arg index="0" value="maomao"></constructor-arg>
        <constructor-arg index="1" value="100"></constructor-arg>
    </bean>
</beans>

測試類

package com.kevin.spring.demo2.test;

import com.kevin.spring.demo2.entity.Person;
import com.kevin.spring.demo2.entity.Student;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test {
    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("student.xml");
        Person kevin = ctx.getBean("kevin", Student.class);
        Person maomao = ctx.getBean("maomao", Student.class);
        System.out.println(maomao);
        System.out.println(kevin);
    }
}

輸出

資訊: Loading XML bean definitions from class path resource [student.xml]
Student{height=100, name='maomao'}
Student{height=170, name='kevin'}

通過屬性賦值

Animal

package com.kevin.spring.demo3.entity;

/**
 * 動物
 */
public class Animal {

    /**
     * 動物名稱
     */
    private String name;

    public Animal() {
    }

    public Animal(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

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

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

animal.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:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="dog" class="com.kevin.spring.demo3.entity.Animal">
        <property name="name" value="dog"></property>
    </bean>

    
    <bean id="cat" class="com.kevin.spring.demo3.entity.Animal" p:name="cat"></bean>
</beans>

測試

package com.kevin.spring.demo3.test;

import com.kevin.spring.demo3.entity.Animal;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * 測試類
 */
public class Test {
    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("animal.xml");
        Animal dog = ctx.getBean("dog",Animal.class);
        Animal cat = ctx.getBean("cat",Animal.class);
        System.out.println(cat);
        System.out.println(dog);
    }
}

輸出結果

資訊: Loading XML bean definitions from class path resource [animal.xml]
Animal{name='cat'}
Animal{name='dog'}

物件引用

Tyre

package com.kevin.spring.demo4.entity;

/**
 * 輪胎
 * @author: kevin
 * @Date: 2018/12/8
 */
public class Tyre {

    private String name;

    public Tyre(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

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

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

Car

package com.kevin.spring.demo4.entity;

/**
 * 車
 */
public class Car {

    private String name;

    private Tyre tyre;

    public Car(String name, Tyre tyre) {
        this.name = name;
        this.tyre = tyre;
    }

    public String getName() {
        return name;
    }

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

    public Tyre getTyre() {
        return tyre;
    }

    public void setTyre(Tyre tyre) {
        this.tyre = tyre;
    }

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

測試

package com.kevin.spring.demo4.test;

import com.kevin.spring.demo4.entity.Car;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test {

    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("car.xml");
        Car bike = ctx.getBean("bike", Car.class);
        System.out.println(bike);
    }
}

輸出結果

資訊: Loading XML bean definitions from class path resource [car.xml]
Car{name='bike', tyre=Tyre{name='自行車輪胎'}}

物件作用域

在大多數情況下,單例bean是很理想的方案。初始化和垃圾回收物件例項所帶來的的成本只留給一些小規模任務,在這些任務中,讓物件保持無狀態並且在應用中反覆重用這些物件可能並不合理。在這種情況下,將class宣告為單例的bean會被汙染,稍後重用的時候會出現意想不到的問題。 -《spring實戰》

Spring定義了多種作用域,可以基於這些作用域建立bean,包括:

作用域 描述
單例(Singleton) 在整個應用中,只建立bean的一個例項
原型(Prototype) 每次注入或者通過spring應用上下文獲取的時候,都會建立一個新的bean例項
會話(Session) 在web應用中,為每個會話建立一個bean例項
請求(Request) 在web應用中,為每個請求建立一個bean例項

1、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:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="dog" class="com.kevin.spring.demo3.entity.Animal">
        <property name="name" value="dog"></property>
    </bean>


    <bean id="cat" class="com.kevin.spring.demo3.entity.Animal" p:name="cat"></bean>
</beans>

測試

package com.kevin.spring.demo3.test;

import com.kevin.spring.demo3.entity.Animal;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * 測試類
 */
public class Test {
    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("animal.xml");
        Animal dog1 = ctx.getBean("dog",Animal.class);
        Animal dog2 = ctx.getBean("dog",Animal.class);

        System.out.println(dog1 == dog2);

    }
}

輸出結果

true

這樣驗證了從容器中取回的物件預設是單例的。

2、設定成Prototype

<?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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="dog" class="com.kevin.spring.demo3.entity.Animal" scope="prototype">
        <property name="name" value="dog"></property>
    </bean>


    <bean id="cat" class="com.kevin.spring.demo3.entity.Animal" p:name="cat"></bean>
</beans>

測試

        ApplicationContext ctx = new ClassPathXmlApplicationContext("animal.xml");
        Animal dog1 = ctx.getBean("dog",Animal.class);
        Animal dog2 = ctx.getBean("dog",Animal.class);

        System.out.println(dog1 == dog2);

輸出結果

false

延遲初始化bean

ApplicationContext實現的預設行為是在啟動時將所有的singleton bean 提前進行例項化。這樣配置中或者執行環境的錯誤就會立刻發現。如果你想延遲初始化。可以在xml中進行配置

    <bean id="kevin" class="com.kevin.spring.demo2.entity.Student" lazy-init="true">
        <constructor-arg name="name" value="kevin"></constructor-arg>
        <constructor-arg name="height" value="170"></constructor-arg>
    </bean>

測試

    public static void main(String[] args) throws InterruptedException {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("student.xml");
        Thread.sleep(3000);
        Person kevin = ctx.getBean("kevin", Student.class);
        System.out.println(kevin);
    }

大家自己執行後發現,確實並不是啟動後就載入的。

回撥方法

Student

    public void init() {
        System.out.println("執行init方法");
    }

    public void over() {
        System.out.println("執行over方法");
    }

student.xml

    <bean id="kevin" class="com.kevin.spring.demo2.entity.Student" lazy-init="true" init-method="init" destroy-method="over">
        <constructor-arg name="name" value="kevin"></constructor-arg>
        <constructor-arg name="height" value="170"></constructor-arg>
    </bean>

測試方法

    public static void main(String[] args) throws InterruptedException {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("student.xml");
        Thread.sleep(3000);
        Person kevin = ctx.getBean("kevin", Student.class);
        System.out.println(kevin);
    }

輸出結果

Student 初始化
執行init方法
Student{height=170, name='kevin'}

我有一個微信公眾號,經常會分享一些Java技術相關的乾貨;如果你喜歡我的分享,可以用微信搜尋“Java團長”或者“javatuanzhang”關注。