一篇文章帶你掌握主流基礎框架——Spring

来源:https://www.cnblogs.com/qiuluoyuweiliang/archive/2022/10/03/16750470.html
-Advertisement-
Play Games

一篇文章帶你掌握主流基礎框架——Spring 這篇文章中我們將會介紹Spring的框架以及本體內容,包括核心容器,註解開發,AOP以及事務等內容 那麼簡單說明一下Spring的必要性: Spring技術是JavaEE開發的必備技能,企業開發技術選型率高達90%! Spring可以幫助簡化開發,降低企 ...


一篇文章帶你掌握主流基礎框架——Spring

這篇文章中我們將會介紹Spring的框架以及本體內容,包括核心容器,註解開發,AOP以及事務等內容

那麼簡單說明一下Spring的必要性:

  • Spring技術是JavaEE開發的必備技能,企業開發技術選型率高達90%!
  • Spring可以幫助簡化開發,降低企業級開發的複雜度
  • Spring可以進行框架整合,高效整合其他技術,提高企業級應用開發與運行效率

Spring的核心內容:

  • Ioc技術
  • DI技術
  • AOP
  • 事務處理

Spring可進行的框架整合:

  • MaBatis
  • MyBatis-plus
  • Struts
  • Struts2
  • Hibernate

在接下來的文章中,我們會學習Spring的框架思想,學習Spring的基本操作,結合案例熟練掌握

溫馨提醒:在學習本篇文章前請先學習JavaWeb相關內容

(HTTP,Tomcat,Servlet,Request,Response,MVC,Cookie,Session,Ajax,Vue等內容)

初識Spring

官網:Spring | Home

Spring發展至今已經形成了一套開發的生態圈,Spring提供了相當多的項目,每個項目用於完成特定功能

我們常用的主流技術包括有:

  • Spring Framework:Spring框架
  • Spring Boot:Spring簡化代碼開發
  • Spring Cloud:Spring分佈設計

Spring FrameWork系統架構

在系統學習Spring之前,我們需要先來瞭解FrameWork系統結構

  • Spring FrameWork是Spring生態圈中最基本的項目,是其他項目的根基

我們現在所使用的Spring FrameWork是4.0版本,已經趨於穩定

下麵我們對架構圖進行解釋:

  • Core Container:核心容器
  • AOP:面向切麵編程
  • Aspects:AOP思想實現
  • Data Access:數據訪問
  • Data Intergration:數據集成
  • Web:Web開發
  • Test:單元測試與集成測試

我們可以在官方中獲得如此評價:

  • 強大的基於 JavaBeans 的採用控制反轉(Inversion of Control,IoC)原則的配置管理,使得應用程式的組建更加快捷簡易。
  • 資料庫事務的一般化抽象層,允許插件式事務管理器,簡化事務的劃分使之與底層無關。
  • 一個可用於從 applet 到 Java EE 等不同運行環境的核心 Bean 工廠。

核心概念介紹

首先我們思索一下我們之前的業務層與數據層:

// 數據層介面
public interface BookDao {
    public void save();
}
// 數據層實現
public class BookDaoImpl implements BookDao {
    public void save() {
        System.out.println("book dao save ...");
    }
}
// 業務層介面
public interface BookService {
    public void save();
}
// 業務層實現
public class BookServiceImpl implements BookService {
    private BookDao bookDao;

    public void save() {
        bookDao.save();
    }

}

如果我們修改BookDaoImpl內容,那麼相對應的業務層實現中的bookDao的new實現也要進行修改,甚至下方方法的對象也要進行修改

Spring使用前問題

代碼書寫現狀:

  • 耦合度偏高

解放方案:

  • 使用對象時,在程式中不要主動使用new產生對象,轉換為由外部提供對象

Spring思想以及實現

IoC(Inversion of Control)控制反轉思想:

  • 使用對象時,由主動new創建對象轉換為由外部提供對象
  • 此過程中對象創建控制權由程式轉移到外部,被稱為控制反轉

DI(Dependency Injection)依賴註入:

  • 在容器中建立Bean與Bean之間的依賴關係和整個過程,被稱為依賴註入

Spring技術對Ioc思想進行了實現:

  • Spring提供了一個容器,被稱為Ioc容器,用來充當IoC思想的外部
  • IoC容器負責對象的創建,初始化等一系列工作,被創建和管理的對象在IoC容器中被稱為Bean
// 數據層實現
public class BookDaoImpl implements BookDao {
    public void save() {
        System.out.println("book dao save ...");
    }
}
// IoC容器
/*
包含
dao
service
兩者可以建立連接
*/
// 業務層實現
public class BookServiceImpl implements BookService {
    private BookDao bookDao;

    public void save() {
        bookDao.save();
    }

}

目的:充分解耦

  • IoC:使用IoC容器管理bean
  • DI:在IoC容器內將有依賴關係的bean進行關係綁定

最終效果:

  • 使用對象不僅可以直接從IoC容器中獲取,還可以將已獲得的Bean之間綁定依賴關係

IoC入門

首先我們需要明白IoC的使用規則:

  1. IoC負責管理什麼:Service和Dao
  2. 如何被管理的對象告知IoC容器:(配置)
  3. 被管理的對象交給IoC容器,如何獲得IoC容器:(介面)
  4. IoC容器得到之後,如何獲得Bean:(介面方法)
  5. 使用Spring所需要導入的坐標:(pom.xml)

下麵我們給出IoC入門的詳細步驟:

  1. 創建Maven項目,在pom.xml中導入坐標
  <dependencies>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.2.10.RELEASE</version>
    </dependency>
  </dependencies>
  1. 創建Spring.xml的配置包(applicationContext.xml,導入坐標後xml中更新該XML)
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--2.配置bean-->
    <!--bean標簽標示配置bean
    id屬性標示給bean起名字
    class屬性表示給bean定義類型(註意需要是實現類)-->
    
    <bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"/>

    <bean id="bookService" class="com.itheima.service.impl.BookServiceImpl"/>

</beans>
  1. 主函數
package com.itheima;

import com.itheima.dao.BookDao;
import com.itheima.service.BookService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App2 {
    public static void main(String[] args) {
        //3.獲取IoC容器
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        
        //4.獲取bean(根據bean配置id獲取)
		//BookDao bookDao = (BookDao) ctx.getBean("bookDao");
		//bookDao.save();
        
        // 註意:需要類型轉化

        BookService bookService = (BookService) ctx.getBean("bookService");
        bookService.save();

    }
}

DI入門

首先我們需要明白DI的使用規則:

  1. 基於IoC管理bean
  2. Service中使用new形式創建Dao對象是否保留:(否)
  3. Service中需要Dao對象如何進入到Service中:(提供方法)
  4. Service與Dao之間的關係如何描述:(配置)

下麵我們給出DI入門的詳細步驟(基於IoC入門):

  1. 刪除new方法
public class BookServiceImpl implements BookService {
    //5.刪除業務層中使用new的方式創建的dao對象
    private BookDao bookDao;

    public void save() {
        System.out.println("book service save ...");
        bookDao.save();
    }

}
  1. 創建對象的set方法
public class BookServiceImpl implements BookService {
    //5.刪除業務層中使用new的方式創建的dao對象
    private BookDao bookDao;

    public void save() {
        System.out.println("book service save ...");
        bookDao.save();
    }
    
    //6.提供對應的set方法
    public void setBookDao(BookDao bookDao) {
        this.bookDao = bookDao;
    }
}
  1. 創建Dao和Service的連接
<?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.配置bean-->
    <!--
	bean標簽標示配置bean
    id屬性標示給bean起名字
    class屬性表示給bean定義類型
	-->
    <bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"/>

    <bean id="bookService" class="com.itheima.service.impl.BookServiceImpl">
        <!--7.配置server與dao的關係-->
        <!--
		註意:在server中配置關係
		property標簽表示配置當前bean的屬性
        name屬性表示配置哪一個具體的屬性
        ref屬性表示參照哪一個bean
		-->
        <property name="bookDao" ref="bookDao"/>
    </bean>

</beans>

Bean整體介紹

Bean是保存在IoC中的對象,我們通過配置的方式獲得Bean

下麵我們從三個方面分別講解Bean:

bean基本配置

首先我們先介紹bean本身性質:

類別 描述
名稱 bean
類型 標簽
所屬 beans標簽
功能 定義Spring核心容器管理對象
格式 <beans>
<bean> </bean>
</beans>
屬性列表 id:bean的id,使用容器可以通過id值獲得對應的bean,在一個容器中id值唯一
class:bean的類型,即配置的bean的全路徑類名
範例 <bean id="bookService" class="com.itheima.service.impl.BookServiceImpl">

然後我們介紹一下bean的別名:

類別 描述
名稱 name
類型 標簽
所屬 bean標簽
功能 定義bean的別名,可定義多個,使用逗號,分號,空格分隔
範例 <bean id="bookService" name="service service4 bookEbi" class="com.itheima.service.impl.BookServiceImpl">

正常情況下,使用id和name都可以獲得bean,但推薦還是使用唯一id

獲得bean無論通過id還是name獲取,如果無法找到則拋出異常NosuchBeanDefinitionException

最後我們介紹一下bean的作用範圍scope:

類別 描述
名稱 scope
類型 標簽
所屬 bean標簽
功能 定義bean的作用範圍,可選範圍如下:
singleton:單列(預設)
prototype:非單列
範例 <bean id="bookDao" name="dao" class="com.itheima.dao.impl.BookDaoImpl" scope="prototype"/>

這裡的scope指產生對象的數量

我們的scope在預設情況下是singleton,因為很多對象只需要創建一次,多次創建會導致記憶體膨脹

合適交給容器進行管理的bean(singleton):

  • 表現層對象
  • 業務層對象
  • 數據層對象
  • 工具對象

不合適交給容器進行管理的bean(prototype):

  • 封裝實體的域對象(帶有狀態的bean)

bean實例化

bean的實例化通常分為四種方法,我們在下麵一一介紹:

  1. 構造方法(常用)

我們需要在數據類中提供構造方法,配置條件中不需要改變

// 數據類

public class BookDaoImpl implements BookDao {

    public BookDaoImpl() {
        System.out.println("book dao constructor is running ....");
    }

    public void save() {
        System.out.println("book dao save ...");
    }

}
<?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-->
    <bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"/>

</beans>

若無參構造方法不存在,則拋出異常BeanCreationException

  1. 靜態工廠(瞭解)

我們在之前的案例中存在有對象工廠的說法,我們可以設置工廠並調用其方法得到bean

// 靜態工廠
package com.itheima.factory;

import com.itheima.dao.OrderDao;
import com.itheima.dao.impl.OrderDaoImpl;
//靜態工廠創建對象
public class OrderDaoFactory {
    public static OrderDao getOrderDao(){
        System.out.println("factory setup....");
        return new OrderDaoImpl();
    }
}
<?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-->
    <bean id="orderDao" class="com.itheima.factory.OrderDaoFactory" factory-method="getOrderDao"/>

</beans>
  1. 實例工廠(瞭解)

和靜態工廠相同,但不同點是方法不是靜態,我們需要提前創建一個bean

// 實例工廠
package com.itheima.factory;

import com.itheima.dao.UserDao;
import com.itheima.dao.impl.UserDaoImpl;
//實例工廠創建對象
public class UserDaoFactory {
    public UserDao getUserDao(){
        return new UserDaoImpl();
    }
}

<?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-->
    <bean id="userFactory" class="com.itheima.factory.UserDaoFactory"/>

    <!--
	factory-bean:實例工廠本身bean
	factory-method:使用調用bean的方法
	-->
    <bean id="userDao" factory-method="getUserDao" factory-bean="userFactory"/>

</beans>
  1. FactoryBean(重要實用)

除了我們之前自己定義的工廠外,Spring提供了一種官方版本的FactoryBean

// FactoryBean工廠(需介面,< >中填寫數據類介面)
package com.itheima.factory;

import com.itheima.dao.UserDao;
import com.itheima.dao.impl.UserDaoImpl;
import org.springframework.beans.factory.FactoryBean;
//FactoryBean創建對象
public class UserDaoFactoryBean implements FactoryBean<UserDao> {
    //代替原始實例工廠中創建對象的方法
    
    // 返回創建對象類型為UserDaoImpl()
    public UserDao getObject() throws Exception {
        return new UserDaoImpl();
    }

    // 這裡填寫介面類型
    public Class<?> getObjectType() {
        return UserDao.class;
    }

    // 可以修改來修改其scope屬性
    public boolean isSingleton() {
        return false;
    }
}
<?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">

    <!--方式四:使用FactoryBean實例化bean-->
    <bean id="userDao" class="com.itheima.factory.UserDaoFactoryBean"/>

</beans>

bean生命周期

我們先來接單介紹生命周期相關概念:

  • 生命周期:從創建到消亡的完整過程
  • bean生命周期:bean從創建到銷毀的整體過程
  • bean生命周期控制:在bean創建後到銷毀前做一些事情

接下來我們介紹生命周期控制方法:

  1. 數據層提供控制方法

由數據層提供方法,在xml配置文件中設置該方法

// 數據層
package com.itheima.dao.impl;

import com.itheima.dao.BookDao;

public class BookDaoImpl implements BookDao {
    
    public void save() {
        System.out.println("book dao save ...");
    }
    
    //表示bean初始化對應的操作
    public void init(){
        System.out.println("init...");
    }
    //表示bean銷毀前對應的操作
    public void destory(){
        System.out.println("destory...");
    }

}
<!--配置文件-->

<?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">

    <!--init-method:設置bean初始化生命周期回調函數-->
    <!--destroy-method:設置bean銷毀生命周期回調函數,僅適用於單例對象-->
    <bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl" init-method="init" destroy-method="destory"/>

    <bean id="bookService" class="com.itheima.service.impl.BookServiceImpl">
        <property name="bookDao" ref="bookDao"/>
    </bean>

</beans>
  1. 介面控制方法(瞭解)

Spring為創建提供了兩個介面,我們只需要繼承並實現該方法即可

package com.itheima.service.impl;

import com.itheima.dao.BookDao;
import com.itheima.service.BookService;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;

// InitializingBean,DisposableBean 分別對應afterPropertiesSet,destroy方法,代表創建和銷毀
public class BookServiceImpl implements BookService, InitializingBean, DisposableBean {
    private BookDao bookDao;

    public void setBookDao(BookDao bookDao) {
        System.out.println("set .....");
        this.bookDao = bookDao;
    }

    public void save() {
        System.out.println("book service save ...");
        bookDao.save();
    }

    public void destroy() throws Exception {
        System.out.println("service destroy");
    }

    public void afterPropertiesSet() throws Exception {
        System.out.println("service init");
    }
}

<?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="bookDao" class="com.itheima.dao.impl.BookDaoImpl" init-method="init" destroy-method="destory"/>
    
    <!--直接調用即可-->
    <bean id="bookService" class="com.itheima.service.impl.BookServiceImpl">
        <property name="bookDao" ref="bookDao"/>
    </bean>

</beans>

我們需要提及一下bean的銷毀時機:(瞭解即可)

  • 因為預設情況下,我們的bean不會被銷毀,因為虛擬機會直接退出,ClassPathXmlApplicationContext會被忽略銷毀過程

所以如果我們希望銷毀bean觀察到destroy的實現,需要手動關閉:

  1. 手動關閉容器方法:
package com.itheima;

import com.itheima.dao.BookDao;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class AppForLifeCycle {
    public static void main( String[] args ) {
        // 註意:這裡需要採用ClassPathXmlApplicationContext作為對象,因為只有這個類才具有close方法
        ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");

        BookDao bookDao = (BookDao) ctx.getBean("bookDao");
        bookDao.save();
        //關閉容器
        ctx.close();
    }
}

  1. 註冊關閉鉤子,在虛擬機退出前先關閉容器再推出虛擬機
package com.itheima;

import com.itheima.dao.BookDao;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class AppForLifeCycle {
    public static void main( String[] args ) {
        ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");

        BookDao bookDao = (BookDao) ctx.getBean("bookDao");
        bookDao.save();
        //註冊關閉鉤子函數,在虛擬機退出之前回調此函數,關閉容器
        ctx.registerShutdownHook();
    }
}

最後我們統計一下整體生命周期:

  1. 初始化容器:創建對象(分配記憶體)->執行構造方法->執行屬性註入(set操作)->執行bean初始化方法
  2. 使用bean:執行業務操作
  3. 關閉/銷毀容器:執行bean銷毀方法

依賴註入方式

首先我們要知道類中傳遞數據的方法有兩種:

  • 普通方法(Set方法)
  • 構造方法

然後我們要知道數據的類型大體分為兩種:

  • 引入類型(數據層)
  • 簡單類型(基本數據類型和String)

所以我們把依賴註入方式分為四種:

  • setter註入
    • 簡單類型
    • 引用類型
  • 構造器註入
    • 簡單類型
    • 引入類型

setter註入簡單類型

首先我們需要在bean種定義簡單類型屬性並提供可以訪問的set方法

package com.itheima.dao.impl;

import com.itheima.dao.BookDao;

public class BookDaoImpl implements BookDao {

    private String databaseName;
    private int connectionNum;
    //setter註入需要提供要註入對象的set方法
    public void setConnectionNum(int connectionNum) {
        this.connectionNum = connectionNum;
    }
    //setter註入需要提供要註入對象的set方法
    public void setDatabaseName(String databaseName) {
        this.databaseName = databaseName;
    }

    public void save() {
        System.out.println("book dao save ..."+databaseName+","+connectionNum);
    }
}

然後在配置中使用property標簽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.xsd">

    <!--註入簡單類型-->
    <bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl">
        <!--property標簽:設置註入屬性-->
        <!--name屬性:設置註入的屬性名,實際是set方法對應的名稱-->
        <!--value屬性:設置註入簡單類型數據值-->
        <property name="connectionNum" value="100"/>
        <property name="databaseName" value="mysql"/>
    </bean>

</beans>

setter註入引用類型

首先我們需要在bean種定義引用類型屬性並提供可以訪問的set方法

package com.itheima.service.impl;

import com.itheima.dao.BookDao;
import com.itheima.dao.UserDao;
import com.itheima.service.BookService;

public class BookServiceImpl implements BookService{
    private BookDao bookDao;
    private UserDao userDao;
    //setter註入需要提供要註入對象的set方法
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }
    //setter註入需要提供要註入對象的set方法
    public void setBookDao(BookDao bookDao) {
        this.bookDao = bookDao;
    }

    public void save() {
        System.out.println("book service save ...");
        bookDao.save();
        userDao.save();
    }
}

然後在配置中使用property標簽ref屬性註入引用類型數據

<?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="bookDao" class="com.itheima.dao.impl.BookDaoImpl">
        <property name="connectionNum" value="100"/>
        <property name="databaseName" value="mysql"/>
    </bean>

    <bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"/>

    <!--註入引用類型-->
    <bean id="bookService" class="com.itheima.service.impl.BookServiceImpl">
        <!--property標簽:設置註入屬性-->
        <!--name屬性:設置註入的屬性名,實際是set方法對應的名稱-->
        <!--ref屬性:設置註入引用類型bean的id或name-->
        <property name="bookDao" ref="bookDao"/>
        <property name="userDao" ref="userDao"/>
    </bean>

</beans>

構造器註入簡單類型(瞭解)

在bean中定義簡單類型屬性並提供可訪問的set方法

public class BookDaoImpl implements BookDao{
	private int connectionNumber;
    
    pubilc void setConnectionNumber(int connectionNumber){
		this.connectionNumber = connectionNumber;
    }
}

配置中使用constructor-arg標簽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.xsd">

    <bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl">
        根據構造方法參數名稱註入
        <constructor-arg name="connectionNum" value="10"/>
    </bean>
    <bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"/>

</beans>

構造器註入引用類型(瞭解)

在bean中定義引用類型屬性並提供可訪問的構造方法

public class BookDaoImpl implements BookDao{
	private BookBao bookBao;
    
    pubilc void setConnectionNumber(int connectionNumber){
		this.bookBao = bookBao;
    }
}

配置中使用constructor-arg標簽ref屬性註入簡單類型數據

<?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="bookService" class="com.itheima.service.impl.BookServiceImpl">
        <constructor-arg name="userDao" ref="userDao"/>
        <constructor-arg name="bookDao" ref="bookDao"/>
    </bean>

</beans>

構造器註入參數配置問題(瞭解)

在前面我們已經介紹了構造器的註入方法

但如果我們在bean中的數據名稱發生改變,配置就不再適配,所以提供了一些方法來解決參數配置問題:

  • 配置中使用constructor-arg標簽type屬性設置按形參類型註入
	<!--解決形參名稱的問題,與形參名不耦合-->
    <bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl">
        根據構造方法參數類型註入
        <constructor-arg type="int" value="10"/>
        <constructor-arg type="java.lang.String" value="mysql"/>
    </bean>
    <bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"/>

    <bean id="bookService" class="com.itheima.service.impl.BookServiceImpl">
        <constructor-arg name="userDao" ref="userDao"/>
        <constructor-arg name="bookDao" ref="bookDao"/>
    </bean>

  • 配置中使用constructor-arg標簽index屬性設置按形參類型註入
    <!--解決參數類型重覆問題,使用位置解決參數匹配-->
    <bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl">
        <!--根據構造方法參數位置註入-->
        <constructor-arg index="0" value="mysql"/>
        <constructor-arg index="1" value="100"/>
    </bean>
    <bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"/>

    <bean id="bookService" class="com.itheima.service.impl.BookServiceImpl">
        <constructor-arg name="userDao" ref="userDao"/>
        <constructor-arg name="bookDao" ref="bookDao"/>
    </bean>

依賴註入方式選擇

依賴註入方式有以下選擇標準:

  1. 強制依賴使用構造器進行,使用setter註入有概率不進行註入導致null對象出現
  2. 可選依賴使用setter註入進行,靈活性高
  3. Spring框架倡導使用構造器,第三方框架內部大多數採用構造器註入的形式進行數據初始化,相對嚴謹
  4. 如果有必要可以兩者並用,使用構造器註入完成強制依賴的註入,使用setter註入完成可選依賴的註入
  5. 實際開發中根據情況分析,如果受控對象沒有提供setter方法則只能採用構造器註入
  6. 自己開發的模塊儘量推薦setter註入

依賴自動裝配

在前面我們學習了手動註入的方法,但Spring其實為我們提供了一種依賴自動裝配的語法:

  • IoC容器根據bean所依賴的資源在容器中自動查找並註入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.xsd">

    <bean class="com.itheima.dao.impl.BookDaoImpl"/>
    <!--autowire屬性:開啟自動裝配,通常使用按類型裝配-->
    <bean id="bookService" class="com.itheima.service.impl.BookServiceImpl" autowire="byType"/>

</beans>

依賴自動裝配特征:

  1. 自動裝配用於引用類型註入,不能對簡單類型進行操作
  2. 使用按類型裝配時(byType)必須保障容器中相同類型的bean唯一,推薦使用
  3. 使用按名稱裝配時(byName)必須保障容器中具有指定名稱的bean,因變數名與配置耦合,不推薦使用
  4. 自動裝配優先順序低於setter註入和構造器註入,同時出現時,自動裝配配置失效

依賴集合註入

除了基本類型和引入類型外,我們有時也需要註入集合

下麵我們簡單介紹一下結合的註入:

// 數據類 

package com.itheima.dao.impl;

import com.itheima.dao.BookDao;

import java.util.*;

public class BookDaoImpl implements BookDao {

    private int[] array;

    private List<String> list;

    private Set<String> set;

    private Map<String,String> map;

    private Properties properties;




    public void setArray(int[] array) {
        this.array = array;
    }

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

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

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

    public void setProperties(Properties properties) {
        this.properties = properties;
    }




    public void save() {
        System.out.println("book dao save ...");

        System.out.println("遍曆數組:" + Arrays.toString(array));

        System.out.println("遍歷List" + list);

        System.out.println("遍歷Set" + set);

        System.out.println("遍歷Map" + map);

        System.out.println("遍歷Properties" + properties);
    }
}

<!--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="bookDao" class="com.itheima.dao.impl.BookDaoImpl">
        <!--數組註入-->
        <!--
		註意:
		name:對應實現類中的內部成員名稱
		<>里的array等為固定辭彙
		-->
        <property name="array">
            <array>
                <value>100</value>
                <value>200</value>
                <value>300</value>
            </array>
        </property>
        <!--list集合註入-->
        <property name="list">
            <list>
                <value>itcast</value>
                <value>itheima</value>
                <value>boxuegu</value>
                <value>chuanzhihui</value>
            </list>
        </property>
        <!--set集合註入-->
        <property name="set">
            <set>
                <value>itcast</value>
                <value>itheima</value>
                <value>boxuegu</value>
                <value>boxuegu</value>
            </set>
        </property>
        <!--map集合註入-->
        <property name="map">
            <map>
                <entry key="country" value="china"/>
                <entry key="province" value="henan"/>
                <entry key="city" value="kaifeng"/>
            </map>
        </property>
        <!--Properties註入-->
        <property name="properties">
            <props>
                <prop key="country">china</prop>
                <prop key="province">henan</prop>
                <prop key="city">kaifeng</prop>
            </props>
        </property>
    </bean>
</beans>

案例:數據源對象管理

針對一個新的數據源對象,我們採用兩步來創建bean(我們以druid為案例):

  • 導入druid坐標
<?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.itheima</groupId>
    <artifactId>spring_09_datasource</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.2.10.RELEASE</version>
        </dependency>
        <!--這裡導入druid坐標-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.16</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>
    </dependencies>
</project>
  • 配置數據源對象作為Spring管理的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.xsd
            ">
    
<!--    管理DruidDataSource對象-->
    <!--起id 設置class地址-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <!--配置基本信息-->
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/spring_db"/>
        <property name="username" value="root"/>
        <property name="password" value="123456"/>
    </bean>

</beans>

案例:載入properties文件

這個案例我們將會介紹如何載入properties文件,並將文件帶入到property基本信息中

我們大致將步驟分為以下三步:

  • 開闢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"
       xsi:schemaLocation="
            http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/context
            http://www.springframework.org/schema/context/spring-context.xsd
            ">
<!--
上述beans中的內容是我們的命名空間開闢過程
在原本的xml中只有:
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
            ">
在下麵的內容中我們添加:
       xmlns:context="http://www.springframework.org/schema/context"
併在xsi:schemaLocation中添加:
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd
(整體從上述內容複製,然後修改末尾xsi即可)
-->
</beans>
  • 使用context命名空間,載入指定properties文件
<!--    2.使用context空間載入properties文件-->

<context:property-placeholder location="jdbc.properties"/>
  • 使用${}讀取載入的屬性值
<!--    3.使用屬性占位符${}讀取properties文件中的屬性-->

<!--    說明:idea自動識別${}載入的屬性值,需要手工點擊才可以查閱原始書寫格式-->
    <bean class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${jdbc.driver}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>

除了上述的基本操作,我們在context命名空間的使用中有很多需要註意的點:

  • 不載入系統屬性
<!--
因為我們的系統屬性優先順序>定義優先順序,當我們properties中的屬性與系統設置屬性名相同時,會優先匹配系統屬性導致錯誤
可以採用system-properties-mode進行設置
-->
<context:property-placeholder location="jdbc.properties" system-properties-mode="NEVER"/>
  • 載入多個properties文件
<!--
我們可以採用逗號或空格分隔載入多個properties文件
-->
<context:property-placeholder location="jdbc.properties,jdbc2.properties" system-properties-mode="NEVER"/>
  • 載入所有properties文件
<!--
我們可以採用通配符來設置載入文件
用*來代替所有首碼,只保留尾碼為properties即可
-->
<context:property-placeholder location="*.properties" system-properties-mode="NEVER"/>
  • 載入properties文件標準格式
<!--
我們通常以classpath表示路徑,下述形式更為標準
classpath:*.properties  :   設置載入當前工程類路徑中的所有properties文件
-->
 <context:property-placeholder location="classpath:*.properties" system-properties-mode="NEVER"/>
  • 從類路徑或jar包中搜索並載入properties文件
<!--
我們通常以classpath*來表示路徑來源
classpath*:*.properties  :  設置載入當前工程類路徑和當前工程所依賴的所有jar包中的所有properties文件
-->
<context:property-placeholder location="classpath*:*.properties" system-properties-mode="NEVER"/>

核心容器

前面已經完成bean與依賴註入的相關知識學習,接下來我們主要學習的是IOC容器中的核心容器。

這裡所說的核心容器,大家可以把它簡單的理解為ApplicationContext,接下來我們從以下幾個問題入手來學習下容器的相關知識:

  • 如何創建容器?
  • 創建好容器後,如何從容器中獲取bean對象?
  • 容器類的層次結構是什麼?
  • BeanFactory是什麼?

容器的創建方式

案例中創建ApplicationContext的方式為(類路徑下的XML配置文件):

ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");

除了上面這種方式,Spring還提供了另外一種創建方式為(文件的絕對路徑):

ApplicationContext ctx = new FileSystemXmlApplicationContext("D:\\workspace\\spring\\spring_10_container\\src\\main\\resources\\applicationContext.xml");

Bean的三種獲取方式

方式一,就是目前案例中獲取的方式:

BookDao bookDao = (BookDao) ctx.getBean("bookDao");

這種方式存在的問題是每次獲取的時候都需要進行類型轉換

方式二:

BookDao bookDao = ctx.getBean("bookDao",BookDao.class);

這種方式可以解決類型強轉問題,但是參數又多加了一個,相對來說沒有簡化多少。

方式三:

BookDao bookDao = ctx.getBean(BookDao.class);

這種方式就類似我們之前所學習依賴註入中的按類型註入。必須要確保IOC容器中該類型對應的bean對象只能有一個。

容器類層次結構

下麵我們給出容器的層次圖

BeanFactory的使用

使用BeanFactory來創建IOC容器的具體實現方式為:

public class AppForBeanFactory {
    public static void main(String[] args) {
        Resource resources = new ClassPathResource("applicationContext.xml");
        BeanFactory bf = new XmlBeanFactory(resources);
        BookDao bookDao = bf.getBean(BookDao.class);
        bookDao.save();
    }
}

為了更好的看出BeanFactory和ApplicationContext之間的區別,在BookDaoImpl添加如下構造函數:

public class BookDaoImpl implements BookDao {
    public BookDaoImpl() {
        System.out.println("constructor");
    }
    public void save() {
        System.out.println("book dao save ..." );
    }
}

如果不去獲取bean對象,列印會發現:

  • BeanFactory是延遲載入,只有在獲取bean對象的時候才會去創建

  • ApplicationContext是立即載入,容器載入的時候就會創建bean對象

  • ApplicationContext要想成為延遲載入,只需要按照如下方式進行配置

    <?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="bookDao" class="com.itheima.dao.impl.BookDaoImpl"  lazy-init="true"/>
    </beans>
    

核心概念總結

接下來我們對前面知識的一個總結,共包含如下內容:

容器相關

  • BeanFactory是IoC容器的頂層介面,初始化BeanFactory對象時,載入的bean延遲載入
  • ApplicationContext介面是Spring容器的核心介面,初始化時bean立即載入
  • ApplicationContext介面提供基礎的bean操作相關方法,通過其他介面擴展其功能
  • ApplicationContext介面常用初始化類
    • ClassPathXmlApplicationContext(常用)
    • FileSystemXmlApplicationContext

bean相關

依賴註入相關

註解開發

在上述的開發中,我們採用xml配置文件的形式來說依舊顯得有些複雜

這時我們就需要發揮Spring的優點:簡化開發,通過註解來簡化開發過程

下麵我們會通過多個方面將Bean逐步轉化為註解

註解開發Bean

在前面的內容中,我們的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.xsd">
    
    <!--原生bean-->
    <bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"/>
    
</beans>

在後期,我們的bean可以採用註解的形式,直接在實現類中註解表示為bean

我們採用@Component定義bean,可以添加參數表示id,也可以不添加參數,後期我們採用class類的類型來進行匹配

package com.itheima.dao.impl;

import com.itheima.dao.BookDao;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Repository;

//@Component定義bean
@Component("bookDao")
public class BookDaoImpl implements BookDao {
    public void save() {
        System.out.println("book dao save ...");
    }
}
package com.itheima.service.impl;

import com.itheima.dao.BookDao;
import com.itheima.service.BookService;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

//@Component定義bean
@Component
public class BookServiceImpl implements BookService {
    private BookDao bookDao;

    public void setBookDao(BookDao bookDao) {
        this.bookDao = bookDao;
    }

    public void save() {
        System.out.println("book service save ...");
        bookDao.save();
    }
}

@Componenty延伸出了三種類型,在實現手法上是一致,但可以具體使用於各種類中(僅用於自我識別)

  • @Controller:用於表現層bean定義
  • @Service:用於業務層bean定義
  • @Repository:用於數據層定義
package com.itheima.dao.impl;

import com.itheima.dao.BookDao;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Repository;
//@Component定義bean
//@Component("bookDao")
//@Repository:@Component衍生註解
@Repository("bookDao")
public class BookDaoImpl implements BookDao {
    public void save() {
        System.out.println("book dao save ...");
    }
}
package com.itheima.service.impl;

import com.itheima.dao.BookDao;
import com.itheima.service.BookService;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
//@Component定義bean
//@Component
//@Service:@Component衍生註解
@Service
public class BookServiceImpl implements BookService {
    private BookDao bookDao;

    public void setBookDao(BookDao bookDao) {
        this.bookDao = bookDao;
    }

    public void save() {
        System.out.println("book service save ...");
        bookDao.save();
    }
}

但是,在上述情況下,即使我們將@Component的類定義為bean

我們的xml文件是無法探測到的,所以我們需要配置相關掃描組件來掃描bean

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

    <!--
	<context:component-scan />:表示掃描文件
	base-package:表示掃描路徑	
	-->
    
    <context:component-scan base-package="com.itheima"/>

</beans>

純註解開發

我們前面所提到的註解開發屬於2.5的附屬版本

在Spring3.0版本,Spring就提供了純註解開發模式,利用java類代替配置文件,開啟了Spring快速開發時代

在之前我們的xml配置文件是很繁瑣的:

<!--原生xml配置文件-->

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="
            http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    
    
    <bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"/>
    
</beans>

但是我們可以通過創建單獨的類來表示配置文件:

  • @Configuration:用於聲明當前類為Spring配置類
  • @ComponentScan:用於掃描類文件(類似於<context:component-scan base-package="com.itheima"/>)
package com.itheima.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

//聲明當前類為Spring配置類
@Configuration
//設置bean掃描路徑,多個路徑書寫為字元串數組格式
@ComponentScan({"com.itheima.service","com.itheima.dao"})
public class SpringConfig {
}

註意:因為該類屬於配置類,我們通常單列一個文件夾來表示

常用文件夾:config

命名規範:SpringConfig,UserConfig...

因為我們的開發不再依靠於xml配置文件,所以在主函數中的Spring容器獲得方式也發生了改變:

package com.itheima;

import com.itheima.dao.BookDao;
import com.itheima.service.BookService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App {
    public static void main(String[] args) {
        
        // 這是我們之前的獲取方式,採用路徑獲取xml文件
        // ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        
        // 這是新的獲取方式,直接提供配置類的類型
        // AnnotationConfigApplicationContext載入Spring配置類初始化Spring容器
        ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
        
        // 後面操作無需變化
        
        BookDao bookDao = (BookDao) ctx.getBean("bookDao");
        System.out.println(bookDao);
        //按類型獲取bean
        BookService bookService = ctx.getBean(BookService.class);
        System.out.println(bookService);
    }
}

註解開發Bean作用範圍與管理

既然我們的Bean開發從xml轉移到註解開發,那麼一些配置設置同樣發生改變

首先我們介紹Scope範圍的設置方式:

  • @Scope:定義bean的作用範圍
package com.itheima.dao.impl;

import com.itheima.dao.BookDao;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Repository;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

@Repository
//@Scope設置bean的作用範圍(singleton或prototype),可以不添加預設singleton
@Scope("singleton")
public class BookDaoImpl implements BookDao {

    public void save() {
        System.out.println("book dao save ...");
    }

}

然後我們介紹一下bean生命周期的init和destroy操作:

  • @PostConstruct:定義init操作,表示構造後操作
  • @PreDestroy:定義destroy操作,表示銷毀前操作

依賴註入(自動裝配)

在Spring3.0中,省略掉了前面繁瑣的依賴註入,我們的bean依賴註入只留下了自動裝配這一操作:

  • 使用@Autowired註解開啟自動裝配模式(按類型)
  • 當存在相同類型時,我們採用@Qualifier開啟按名自動裝配
package com.itheima.service.impl;

import com.itheima.dao.BookDao;
import com.itheima.service.BookService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

@Service
public class BookServiceImpl implements BookService {
    //@Autowired:註入引用類型,自動裝配模式,預設按類型裝配
    @Autowired
    //@Qualifier:自動裝配bean時按bean名稱裝配
    @Qualifier("bookDao")
    private BookDao bookDao;

    public void save() {
        System.out.println("book service save ...");
        bookDao.save();
    }
}

註意:自動裝配基於反射設計創建對象並暴力反射對應屬性為私有屬性初始化數據,因此無需提供setter方法

註意:自動轉配建議使用無參構造方法創建對象(預設),如果不提供對應構造方法,請提供唯一的構造方法

註意:@Qualifier是基於@Autowired實現的,必須保證先有Autowired才能存在Qualifier

除了上述的bean類型裝配,我們的簡單類型裝配依舊存在:

  • 我們採用@Value的形式來配置簡單類型的值
package com.itheima.dao.impl;

import com.itheima.dao.BookDao;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Repository;

@Repository("bookDao")
public class BookDaoImpl implements BookDao {
    //@Value:註入簡單類型(無需提供set方法)
    @Value("123")
    private String name;

    public void save() {
        System.out.println("book dao save ..." + name);
    }
}

之所以使用@Value的形式配置,是因為我們的類型值不一定是由手動輸入的,有可能來自於Properties資源:

  • 首先我們需要在Springconfig中配置相關資源
package com.itheima.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;

@Configuration
@ComponentScan("com.itheima")
//@PropertySource載入properties配置文件
@PropertySource({"jdbc.properties"})
public class SpringConfig {
}
  • 然後我們在數據層調用時,採用${}來匹配數據
package com.itheima.dao.impl;

import com.itheima.dao.BookDao;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Repository;

@Repository("bookDao")
public class BookDaoImpl implements BookDao {
    //@Value:註入簡單類型(無需提供set方法)
    @Value("${name}")
    private String name;

    public void save() {
        System.out.println("book dao save ..." + name);
    }
}

註解開發第三方bean

我們在實際開發中不僅僅需要對自己的bean進行管理,有時候可能需要引進其他的bean

下麵我們以Druid為例進行講解:

  1. 首先在pom.xml中導入Druid坐標
<?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.itheima</groupId>
  <artifactId>spring_14_annotation_third_bean_manager</artifactId>
  <version>1.0-SNAPSHOT</version>

  <dependencies>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.2.10.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>druid</artifactId>
      <version>1.1.16</version>
    </dependency>
  </dependencies>
</project>

  1. 使用@Bean配置第三方Bean
// 該bean同樣屬於config文件,我們同樣放置在config文件夾下
// 在後續我們將會講解如何進行連接

package com.itheima.config;

import com.alibaba.druid.pool.DruidDataSource;
import com.itheima.dao.BookDao;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.sql.DataSource;

public class JdbcConfig {
    
    // 1.定義一個方法獲得要管理的對象    
    // 2.添加@Bean,表示當前方法的返回值是一個bean
    // @Bean修飾的方法,形參根據類型自動裝配
    @Bean
    public DataSource dataSource(){
        DruidDataSource ds = new DruidDataSource();
        ds.setDriverClassName("com.mysql.jdbc.Driver");
        ds.setUrl("jdbc:mysql://localhost:3306/spring_db");
        ds.setUsername("root");
        ds.setPassword("123456");
        return ds;
    }
}
  1. 將獨立的配置類加入核心配置(導入法)
// SpringConfig

package com.itheima.config;

import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

import javax.sql.DataSource;

@Configuration
@ComponentScan("com.itheima")
//@Import:導入配置信息(如果需要多個,同樣採用{}數組形式)
@Import({JdbcConfig.class})
public class SpringConfig {
}

// JdbcConfig

package com.itheima.config;

import com.alibaba.druid.pool.DruidDataSource;
import com.itheima.dao.BookDao;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.sql.DataSource;

//@Configuration
public class JdbcConfig {
    //@Bean修飾的方法,形參根據類型自動裝配
    @Bean
    public DataSource dataSource(){
        DruidDataSource ds = new DruidDataSour

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 現如今,手機錄屏是必不可少的能力之一。對於游戲領域作者來說,在平時直播玩游戲、製作攻略、操作集錦時,不方便切屏,這時在游戲內如果有一個錄製按鈕就可以隨時開啟,記錄下每個精彩瞬間,減少後期剪輯工作量;在直播App中開啟一鍵錄屏,不光方便主播後續的賬號運營與復盤,用戶也能隨時截取有意思的片段傳播在社交媒 ...
  • 效果演示圖 可拖拽側邊欄的使用情況非常多啊,博客園後臺管理左側邊欄就可以拖拽喲!廢話不多說,本隨筆實現的可拖拽側邊欄效果演示圖如下: HTML 代碼 <div class="container"> <div class="left"> <div class="resize-bar"></div> < ...
  • 前言 此文我首發於CSDN(所以裡面的圖片有它的水印) 趁著隔離梳理一下之前做的一個有用的功能:在瀏覽器中去切割多解析度瓦片圖 這是一個有趣的過程,跟我一起探索吧 閱讀本文需具備前置知識:對krpano有所瞭解,如:使用krpano去開發全景 本著故弄玄虛的原則,最精彩的會放到最後揭曉,由淺入深,層 ...
  • 淺學Vue 引入 <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script> Hello Vue <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <s ...
  • ES6 部分 Typescript 部分 前端工程面經(節流防抖、https、前端攻擊、性能優化...) https://juejin.cn/post/6844903734464495623 ES6面試(點擊可展開) 為什麼選擇 ES6 ? ES6是新一代的 JS 語言標準,規範了JS的使用標準(v ...
  • CDN
    一、CDN的概念 概念:CDN(Content Delivery Network)是指一種通過互聯網互相連接的電腦網路系統,利用最靠近每位用戶的伺服器,更快、更可靠地將音樂、圖片、視頻、應用程式及其他文件發送給用戶,來提供高性能、可擴展性及低成本的網路內容傳遞給用戶。 即內容分髮網絡。 二、CDN的 ...
  • 有時需要在view頁面設置標簽的狀態為disabled,但是客戶反映radio button和checkbox的顏色很淺,難以識別,尤其是列印後,如下: 可以使用下麵的css更改原有的樣式input[type= "radio" ]:checked:disabled { appearance: non ...
  • 背景: 這兩天看了一個視頻,介紹什麼是C/S,什麼是B/S,總覺得很奇怪。裡面說到只要是app的,都是client-server,而網頁端,如h5網站,web網站,小程式等都是brower-server架構。感覺這種劃分非常“反直覺”,因為現在的軟體都是多端,連接在“同一個”伺服器下為使用者提供網路 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...