天天看點

Spring-IOC容器進行對象管理IOC概念IOC思想Spring管理對象Spring對Bean的執行個體化方式Spring中依賴注入方式

目錄

IOC概念

IOC思想

Spring管理對象

內建依賴

spring的配置檔案(Applicationcontext.xml)

建立實體類User

Spring對Bean的執行個體化方式

基于配置形式

1.通過無參構造函數執行個體化

2.通過靜态工廠方式執行個體化

3.通過普通工廠方式執行個體化Bean

基于注解形式

Spring中依賴注入方式

基于xml配置實作依賴注入

1.有參構造函數

2.setter方式注入

基于注解形式注入依賴

IOC概念

IOC(Inversion Of Control) 控制反轉,spring中提供了IOC容器,對象的建立交給外部容器完成,這個就是控制反轉,spring中使用控制反轉來實作對象在不同程式中的使用,容器存在的必要性就是管理對象。

通過購買圖書的場景來分析使用java執行個體,使用相關對象是需要new建立并持有,缺點:

  1. 執行個體化一個元件比較困難,例如:bookservice和userservice要建立DataSource執行個體,實際上需要讀取配置,即config,通過config執行個體才建立出DataSourceservice,沒有必要bookservice和UserService分别建立DataSourceservice,可以共享ataSourceservice,誰負責來建立DataSourceservice執行個體,也不好處理。
  2. 很多元件需要銷毀來釋放資源,例如datasouce,如果采用共享,如何確定使用方能正确的銷毀。
  3. 随着映入到的業務元件越來越多,對元件的共享管理也就越來越複雜。

可以提供容器,來管理所有的元件(對象),所有的對象的建立,銷毀也好都交給容器,誰需要使用對象,在容器中擷取該對象的使用權,哪一個對象需要,就将使用的對象注入到該對象中,對于使用方而言,隻需要關注使用即可,對象的生命周期的管理就交給IOC容器進行管理,IOC容器負責執行個體化所有的元件,需要進行依賴的對象都交給容器管理。

IOC思想

對象的建立交給外部容器完成,這個就是控制反轉,spring中使用控制反轉來實作對象在不同程式中的使用,控制反轉解決對象處理的問題,将對象交給容器進行建立。

依賴注入(DI):dendendency injection

對象與對象之間的依賴問題即依賴注入 AOP->DI

Spring使用依賴注入來實作對象之間的依賴關系

在對象建立之後,對象的關系處理就是依賴注入

無論對象的建立,處理對象之間的依賴關系,對象建立的時間還有對象建立的數量,都隻需在spring的IOC容器上配置對象的資訊即可

IOC最簡單的方式就是采用XML方式來進行管理:

<beans> 
  資料源交給容器管理
  <bean id="datasource" class="DataSourceService" >
  
    <bean id="userservice" class="UserService">
       <property name="datasource" ref="datasource"/>
    </bean> 
    
    ...
</beans>
           

在BuyService中使用擷取使用者資訊,通過容器:context 提供的方式來擷取使用者的執行個體context.getName("userservice"),就會在容器中找id=“userservice”,進而擷取該對象執行個體進行使用。

Spring IOC容器中接口的繼承關系,ApplicationContext是BeanFactory子接口實作之一,

BeanFactory是IOC容器定義的最底層的接口。

ApplicationContext是進階實作之一,對BeanFactory的接口做了很多的擴充,大部分情況ApplicationContext使用。

ApplicationContext接口常見的實作類:

  • ClassPathXmlApplicationContext(讀取classpath中的資源)
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationcontext.xml");
           
  • FileSystemXmlApplicationContext(讀取系統指定的資源檔案)
FileSystemXmlApplicationContext applicationContext1 = new FileSystemXmlApplicationContext("d://test.xml");
           
  •  XmlWebApplicationContext(讀取web環境下的資源檔案)
XmlWebApplicationContext applicationcontext = new XmlWebApplicationContext();
           

Spring管理對象

內建依賴

添加依賴的時候要注意版本問題,我的IDEA為2020.2,maven為3.6.3,是以spring的依賴添加的是5.2.8版本 

<?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>org.example</groupId>
  <artifactId>springTest</artifactId>
  <version>1.0-SNAPSHOT</version>

  <name>springTest</name>
  <!-- FIXME change it to the project's website -->
  <url>http://www.example.com</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.7</maven.compiler.source>
    <maven.compiler.target>1.7</maven.compiler.target>
  </properties>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-core</artifactId>
      <version>5.2.8.RELEASE</version>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.2.8.RELEASE</version>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-beans</artifactId>
      <version>5.2.8.RELEASE</version>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-expression</artifactId>
      <version>5.2.8.RELEASE</version>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-core</artifactId>
      <version>5.2.8.RELEASE</version>
    </dependency>

    <dependency>
      <groupId>log4j</groupId>
      <artifactId>log4j</artifactId>
      <version>1.2.12</version>
    </dependency>
  </dependencies>

  <build>
    <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
      <plugins>
        <!-- clean lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#clean_Lifecycle -->
        <plugin>
          <artifactId>maven-clean-plugin</artifactId>
          <version>3.1.0</version>
        </plugin>
        <!-- default lifecycle, jar packaging: see https://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging -->
        <plugin>
          <artifactId>maven-resources-plugin</artifactId>
          <version>3.0.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-compiler-plugin</artifactId>
          <version>3.8.0</version>
        </plugin>
        <plugin>
          <artifactId>maven-surefire-plugin</artifactId>
          <version>2.22.1</version>
        </plugin>
        <plugin>
          <artifactId>maven-jar-plugin</artifactId>
          <version>3.0.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-install-plugin</artifactId>
          <version>2.5.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-deploy-plugin</artifactId>
          <version>2.8.2</version>
        </plugin>
        <!-- site lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#site_Lifecycle -->
        <plugin>
          <artifactId>maven-site-plugin</artifactId>
          <version>3.7.1</version>
        </plugin>
        <plugin>
          <artifactId>maven-project-info-reports-plugin</artifactId>
          <version>3.0.0</version>
        </plugin>
      </plugins>
    </pluginManagement>
  </build>
</project>
           

spring的配置檔案(Applicationcontext.xml)

需要容器管理的對象在該xml檔案中進行配置。

聲明如下:

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

建立實體類User

public class User {
    private Integer id;
    private String name;
}
           

使用bean标簽類管理對象 id:屬性辨別對象,不可重複,class屬性代表要管理的對象的全路徑

<bean id="user" class="org.example.bean.User"/>
           

通過容器擷取對象

//擷取IOC容器,通過讀取classpath路徑下的spring的配置檔案
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationcontext.xml");
        //在IOC容器擷取需要的對象執行個體
        User user = (User) applicationContext.getBean("user");
        System.out.println(user);
           
Spring-IOC容器進行對象管理IOC概念IOC思想Spring管理對象Spring對Bean的執行個體化方式Spring中依賴注入方式

原理:擷取User對象時,new User() ,将對象的全路徑配置在容器中,容器建立對象通過->反射 ->IOC容器底層拿到類的全路徑,然後可以通過反射的技術來建立執行個體。

Spring對Bean的執行個體化方式

基于配置形式

1.通過無參構造函數執行個體化

<!--通過無參構造來執行個體化Bean-->
    <bean id="user" class="org.example.bean.User" scope="singleton"/>
           

spring容器對上面的類的執行個體化采用的是無參構造函數來執行個體化bean

注:如果不指定無參構造函數,會生成一個預設的無參構造函數,如果指定了有參構造函數,(就不會生成預設的無參構造函數),就必須顯性的寫明一個無參構造函數,否則會報錯

2.通過靜态工廠方式執行個體化

首先建立靜态工廠類來擷取User對象

public class staticFactory {
    public static User getUser(){
        return new User();
    }
}
           

spring容器管理配置如下:

<!--通過靜态工廠類擷取User對象-->
   <bean id="user1" class="org.example.factory.staticFactory" factory-method="getUser"></bean>
           

靜态工廠方式擷取對象是 class屬性工廠類的全路徑,factory-method屬性指在工廠類中指定的方法來擷取需要的對象

擷取結果:

Spring-IOC容器進行對象管理IOC概念IOC思想Spring管理對象Spring對Bean的執行個體化方式Spring中依賴注入方式

3.通過普通工廠方式執行個體化Bean

建立一個普通工廠來管理user

/**
 * 普通工廠
 */
public class commonFactory {

    public User getUser(){
        return new User();
    }
}
           

spring容器配置如下:

<!--通過普通工廠類擷取User對象-->
    <!--先擷取工廠執行個體-->
    <bean id="factory" class="org.example.factory.commonFactory"/>
    <!--指定工廠類的方法-->
    <bean id="user2"  factory-bean="factory" factory-method="getUser"/>
           

首先需要擷取工廠執行個體,通過普通工廠執行個體擷取user對象時,factory-bean屬性指的是容器管理的工廠對象,factory-method屬性指的是工廠中擷取user對象的方法

擷取結果:

Spring-IOC容器進行對象管理IOC概念IOC思想Spring管理對象Spring對Bean的執行個體化方式Spring中依賴注入方式

基于注解形式

基于注解形式比xml方式更加簡單,開發更快。

建立了一個新的配置檔案spring-config.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"
       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">


    <!--開啟掃描注解:指定的包路徑下的類,會掃描的到類的方法,屬性上-->
    <context:component-scan base-package="org.example.bean"/>

    <!--隻掃描類中屬性的注解(不建議使用)-->
    <!--<context:annotation-config></context:annotation-config>-->

</beans>
           

隻需在需要管理的類上添加注解即可

@Component("user")
//注解中user=XML配置形式中bean  id屬性
public class User {
    private Integer id;
    private String name;
}
           

這裡使用的注解@Component

@Component:通用注解

@Repository:對DAO層實作類進行标注

@Service:對Service層業務邏輯層進行标注

@Controller:對Controller的實作類進行标注

四個注解可以通用,功能一樣,可以互換,使用不同注解主要是區分被注解的類處在不同的業務層,使邏輯更加清晰。

Spring中依賴注入方式

bean的執行個體化說明的是IOC的問題,建立對象之後對象中的屬性如何指派問題,即依賴注入問題(DI),主要有兩種依賴注入方式:

  • xml配置方式進行依賴注入
  • 注解形式進行依賴注入

基于xml配置實作依賴注入

1.有參構造函數

該種注入方式要求對應的實體類中必須提供有參構造函數,如果沒有構造函數,在配置檔案中就會報錯,無法通過編譯。

public class User {
    private Integer id;
    private String name;

    /**
     * 有參構造函數
     */
    public User(Integer id, String name) {
        this.id = id;
        this.name = name;
    }
           

spring容器的配置如下:

<!--依賴注入:有參構造函數-->
    <bean id="user3" class="org.example.bean.User">
        <!--
        注入屬性
        name屬性:給定類的屬性名稱
        value屬性:對指定屬性名稱指派 ,直接擷取的是String類型的值
        ref屬性:對指定屬性進行指派 指定的是一個容器管理的對象
        -->
        <constructor-arg name="id" value="1"></constructor-arg>
        <constructor-arg name="name" value="tom"></constructor-arg>
    </bean>
           

通過有參構造函數完成依賴注入時,使用constructor-arg标簽進行屬性指派,為友善檢視,在實體類中改寫toString函數進行列印

Spring-IOC容器進行對象管理IOC概念IOC思想Spring管理對象Spring對Bean的執行個體化方式Spring中依賴注入方式

2.setter方式注入

該方式需要為User類的屬性設定setter方法

public class User {
    private Integer id;
    private String name;

    public User() {
    }
    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

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

容器中的配置資訊如下:

<!--依賴注入:setter方式-->
    <bean id="user4" class="org.example.bean.User">
        <property name="id" value="2"></property>
        <property name="name" value="jack"></property>
    </bean>
           

setter方式的依賴注入:使用property标簽進行指派

Spring-IOC容器進行對象管理IOC概念IOC思想Spring管理對象Spring對Bean的執行個體化方式Spring中依賴注入方式

指派類型除了常見的String,Integer這種,還可以指派給自定義類型,自定義類型無論是set方法還是有參構造均可,對自定義類型指派時使用ref。

<bean id="user3" class="org.example.bean.User">
        <constructor-arg name="book" ref="book"/>
    </bean>
           

注入集合類型:數組、Set、List、Map的個形式集合都可以注入,處理集合存在以下标簽:

Spring-IOC容器進行對象管理IOC概念IOC思想Spring管理對象Spring對Bean的執行個體化方式Spring中依賴注入方式

以map類型為例,進行介紹

package org.example.bean;

import org.springframework.stereotype.Component;

import java.util.Map;

/**
 * Description :
 * Created by Resumebb
 * Date :2021/4/2
 */

@Component("user")
public class User {
    private Integer id;
    private String name;
    private Map<Integer, String> map;
    public User(Integer id, String name) {
        this.id = id;
        this.name = name;
    }
    public User(){}

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

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


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

    public Map<Integer, String> getMap() {
        return map;
    }

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

spring容器中的配置:

<bean id="user5" class="org.example.bean.User">
        <property name="id" value="3"></property>
        <property name="name" value="rose"></property>
        <property name="map">
            <map>
                <entry key="1" value="a"></entry>
                <entry key="2" value="b"></entry>
                <entry key="3" value="c"></entry>
            </map>
        </property>
    </bean>
           
Spring-IOC容器進行對象管理IOC概念IOC思想Spring管理對象Spring對Bean的執行個體化方式Spring中依賴注入方式

基于注解形式注入依賴

@Value("3")//注入普通類型屬性

@Resource //注入對象類型

@Autowired //注入對象類型,預設是按照類型注解

依賴的注入都是在類的屬性上。

Resource與Autowired注解差別

Spring中,@Resource和@Autowired都是做bean的注入時使用。使用過程中,有時候@Resource 和 @Autowired可以替換使用;有時,則不可以。

  •   共同點

    @Resource和@Autowired都可以作為注入屬性的修飾,在接口僅有單一實作類時,兩個注解的修飾效果相同,可以互相替換,不影響使用。

  •    不同點

 @Resource是Java自己的注解,@Resource有兩個屬性是比較重要的,分是name和type;Spring将@Resource注解的name屬性解析為bean的名字,而type屬性則解析為bean的類型。是以如果使用name屬性,則使用byName的自動注入政策,而使用type屬性時則使用byType自動注入政策。如果既不指定name也不指定type屬性,這時将通過反射機制使用byName自動注入政策。

@Autowired是spring的注解,是spring2.5版本引入的,Autowired隻根據type進行注入,不會去比對name。如果涉及到type無法辨識注入對象時,那需要依賴@Qualifier或@Primary注解一起來修飾。