天天看點

老闆:不懂spring還來做項目?建議離職一、Spring架構二、裝配Bean

一、Spring架構

1.1 Spring架構是什麼

  • Spring是一種容器架構,用于配置各個元件(bean)并且維護各個元件bean之間的關系
  • Spring架構可以管理Web層,業務層,DAO層,持久層。
  • Spring提倡面向接口程式設計,配合DI技術可以實作層與層的解耦(主要是WEB層和業務層)
  • Spring架構圖
    老闆:不懂spring還來做項目?建議離職一、Spring架構二、裝配Bean

1.2 一個簡單的spring項目

目錄結構

  • 引入spring的開發包(最小配置spring.jar以及日志包common-logging.jar)
  • 建立spring的一個核心檔案ApplicationContext.xml,該檔案一般放在src目錄下,該檔案中引入xsd檔案,可以自定義檔案名。
TestSpring
      |---src
          |---com.netease
          |          |---Service
          |                |---HelloService.java
          |                |---ByeService.java
          |          |---Test
          |                |---TestService.java
          |---ApplicationContext.xml
  External Libraries
      |--- spring.jar
      |--- common-logging.jar
      |--- ...
           

代碼詳情

package com.netease.Service;
public class HelloService {
    private String name;
    private ByeService byeService;      /** 引用了一個ByeService*/

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

    public ByeService getByeService() { return byeService;}
    public void setByeService(ByeService byeService) { this.byeService = byeService;}

    public void sayHello() {
        System.out.println("hello "+name);
    }
}
           
package com.netease.Service;
public class ByeService {
    private String name;

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

    public void sayBye() {
        System.out.println("Bye " + name);
    }
}
           
package com.netease.Test;
import com.netease.Service.HelloService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestService {
    public static void main(String[] args) {
        /*通過反射機制,在Spring容器中生成對象*/
        /*如果%%.xml放在某個包下,則就變為<包名+檔案名>*/
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("ApplicationContext.xml");
        HelloService helloService = (HelloService) applicationContext.getBean("helloService");
        helloService.sayHello();
        helloService.getByeService().sayBye();
    }
}
           

Spring核心容器檔案ApplicationContext.xml

  • 在容器檔案中配置Bean(Bean有可能是以下各種類型service/dao/domain/action/資料源)
  • 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"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
				http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
				http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">

    <--注意Spring如何配置Bean以及如何維護Bean之間的依賴-->
    <bean id="helloService" class="com.netease.Service.HelloService">
        <--注入屬性值-->
        <property name="name">
            <value>Today</value>
        </property>
        <--維護Bean之間依賴,ref指向下一個Bean-->
        <property name="byeService" ref="byeService"/>
    </bean>

    <bean id="byeService" class="com.netease.Service.ByeService">
        <property name="name">
            <value>Yesterday</value>
        </property>
    </bean>
</beans>
           

1.3 Spring架構運作原理圖

  • Spring架構什麼時候被加載,Spring中配置的bean怎樣被建立,Bean與Bean之間的關系如何維護
    老闆:不懂spring還來做項目?建議離職一、Spring架構二、裝配Bean

1.4 IOC與DI是什麼

  • IOC(Inverse Of Controll ) 控制反轉:

    所謂控制反轉就是把建立對象(bean),和維護對象(bean)的關系的權利從程式中轉移到spring的容器(applicationContext.xml),而程式本身不再維護.

  • DI(Dependency Injection) 依賴注入:

    實際上DI和IOC是同一個概念,Spring設計者認為DI更準确表示Spring核心技術

二、裝配Bean

2.1 容納Bean

ApplicationContext方式

  • ApplicationContext ac = new

    ClassPathXmlApplicationContext(“com/netease/bean.xml”)

  • 這句話執行時,不僅執行個體化了該容器,其中配置的所有scope為singleton的bean全部通過反射機制被執行個體化,scope為prototype的bean不會被執行個體化

其他三種加載方式

  • ClassPathXmlApplicationContext:從類路徑中加載。
  • FileSystemXmlApplicationContext:從檔案系統加載,需要全路徑
  • XmlWebApplicationContext:從web系統中加載。

好處:預先加載,速度快;缺點:耗記憶體

Bean的作用域,即scope

老闆:不懂spring還來做項目?建議離職一、Spring架構二、裝配Bean

Bean工廠方式

  • BeanFactory factory = new XmlBeanFactory(new

    ClassPathResource(“com/netease/bean.xml”))

  • 這句話執行時,僅執行個體化了該容器,容器中的bean不被執行個體化,隻有當你使用factory.getBean("***")擷取某個bean時,才執行個體化該bean對應的對象。類似于延遲執行個體化
  • 好處:節約記憶體;缺點:速度慢
  • 一般沒有特殊要求,都采用ApplicationContext方式執行個體化(90%),移動端可采用Bean工廠方式

2.2 Bean生命周期

完整生命周期步驟如下(通常隻用到加粗的幾步):

  1. 執行個體化:程式加載ApplicationContext檔案,并把bean(scope=singleton)執行個體化到記憶體
  2. 設定屬性:調用set方法設定bean中指定的屬性 如果你實作了BeanNameAware接口, 則可以通過BeanName
  3. 如果你實作了BeanFactoryAware接口,則可以擷取BeanFactory
  4. 如果你實作了ApplicationContextAware接口,則可以擷取ApplicationContext
  5. 如果bean和一個後置處理器關聯,則會自動去調用 postProcessBeforeInitialization()方法
  6. 如果你實作InitializingBean接口,則會調用afterPropertiesSet()方法
  7. 如果設定了,則可以在bean檔案中定義自己的初始化方法init.
  8. 如果bean和一個後置處理器關聯,則會自動去調

    postProcessAfterInitialization()方法

  9. 使用bean 容器關閉
  10. 可以通過實作DisposableBean接口來調用方法 destory,用來關閉資源等
  11. 可以在 調用定制的銷毀方法destroy

ApplicationContext方式

老闆:不懂spring還來做項目?建議離職一、Spring架構二、裝配Bean

Bean工廠方式

老闆:不懂spring還來做項目?建議離職一、Spring架構二、裝配Bean

2.3 裝配Bean

2.3.1 什麼是裝配Bean

告訴容器有哪些Bean以及容器如何使用依賴注入将它們配合在一起。

2.3.2 裝配方法

  • 在XML進行顯式配置
  • 在Java中進行顯示配置
  • 隐式的bean發現機制和自動裝配

2.3.3 面向XML的裝配方法

2.3.3.1 添加一個Bean

  • 基本配置:一個bean ID + 全稱類名
<beans>
   <bean id="foo" class="...Foo"/>
   <bean id="bar" class="...Bar"/>
</beans>
           
  • scope屬性
<beans>
  <bean id="foo" scope="prototype/singleton" class="...Foo"/>
  <bean id="bar" class="...Bar"/>
</beans>
           

注意盡量使用預設的singleton,以防占用太大記憶體,影響程式性能

init-method 和destroy-method屬性

用途:在Spring執行個體化或者銷毀bean時做一些處理工作

使用方法:

  1. 聲明方式:在XML檔案中先聲明該Bean擁有的初始化和銷毀方法的函數名。在bean.java中實作init和destroy方法,函數名可自定義
  1. 标簽方式:不需要在xml檔案中聲明初始化和銷毀方法,在bean.java中采用标簽方式聲明初始化和銷毀方法
@PostConstruct
public void ini(){…}
@PreDestroy
public void destroy(){…}
           

其他進行初始化和銷毀處理的方法:

Spring還提供了兩個接口供bean.java使用,來進行執行個體化或者銷毀時的處理,但不推薦

2.3.3.2 通過set方法注入屬性和依賴

通過元素的子元素注入屬性和依賴

  • 注入簡單屬性(基本類型和String)
<bean id="foo" class="...Foo">
      <property name="name">
            <value>tom</value>
      </property>
</bean>
           

注入依賴

  • 引用其他的Bean
<bean id="foo" class="...Foo">
      <property name="name">
            <ref bean="bar">
      </property>
</bean>
<bean id="bar" class="...Bar">
</bean>
           
  • 内部bean
<bean id="foo" class="...Foo">
  <property name="bar">
        <bean class="...Bar">...</bean>
  </property>
</bean>
           
  • 注入集合屬性(數組,List,Set,Map)

設定null

<property name="barlist">
       <null/>
</property>
           

數組

<-- 給數組注入值 -->
<property name="empName">
  <list>
    <value>小明</value>
    <value>李雷</value>
    <value>韓梅梅</value>
  </list>
</property>
           

List

<-- 給list注入值 list 中可以有相等的對象 -->
  <property name="empList">
   	<list>
   		<ref bean="emp2" />
   		<ref bean="emp1"/>
   		<ref bean="emp1"/>
   	</list>
  </property>
           

Set

<-- 給set注入值 set不能有相同的對象 -->
  <property name="empsets">
   	<set>
   		<ref bean="emp1" />
   		<ref bean="emp2"/>
   		<ref bean="emp2"/>
   	</set>
  </property>
           

Map

<-- 給map注入值隻要key不同即可 -->
  <property name="empMaps">
   	<map>
   		<entry key="11" value-ref="emp1" />
   		<entry key="22" value-ref="emp2"/>
   		<entry key="33" value-ref="emp1"/>
   	</map>
 </property>
           

property

<property name="pp">
	<props>
		<prop key="pp1">abcd</prop>
		<prop key="pp2">hello</prop>
	</props>
</property>
           

Bean的繼承

  1. public class Student有name和age兩個屬性
  2. public class Gradate extends
  3. Student 有degree屬性 在ApplicationContext檔案中展現配置
即student中配置過的屬性graduate可以不配置 如果配置,則會覆寫父類的屬性
<-- 配置一個學生對象 -->
  <bean id="student" class="com.hsp.inherit.Student">
  	<property name="name" value="順平" />
  	<property name="age" value="30"/>
  </bean>
  <-- 配置Grdate對象 -->
  <bean id="grdate" parent="student" class="com.hsp.inherit.Gradate">
  	<-- 如果自己配置屬性name,age,則會替換從父對象繼承的資料  -->
  	<property name="name" value="小明"/>
  	<property name="degree" value="學士"/>
  </bean>
           

2.3.3.3 通過構造器注入屬性

通過元素的子元素注入屬性

<bean id="test" class ="...Test">
  <constructor-arg index="0" type="java.lang.String" value="朱潔" />
  <constructor-arg index="1" type="int" value="20"/>
  <constructor-arg  index="2" type="double" value="34.5" />
</bean>
           

2.3.3.4 分散配置

通過在ApplicationContext.xml檔案中配置context:property-placeholder 引入屬性檔案,有多個需要使用’,'号間隔.

步驟如下:

  1. 配置屬性檔案db.property
name=scott
 drivername=oracle:jdbc:driver:OracleDirver
 url=jdbc:oracle:thin:@127.0.0.1:1521:hsp
 pwd=tiger
           
  1. 在ApplicationContext.xml檔案中引入db.properties檔案,兩種方式

    第一種

第二種

<bean id="dbPropertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <property name="locations">
         <list>
         <value>xx/yy/db.properties</value>
         <value>xx/yy/db2.properties</value>
         </list>
      </property>
</bean>
           
  1. 在ApplicationContext.xml檔案中配置bean,采用占位符$方式
<bean id="dbutil" class="com.hsp.dispatch.DBUtil">
<property name="name" value="${name}" />
<property name="drivername" value="${drivername}" />
<property name="url" value="${url}" />
<property name="pwd" value="${pwd}" />
</bean>
           

2.3.3.5 自動裝配

  • 通過autowire屬性裝配
<bean id="foo" class="...Foo" autowire="autowire
   type"> 
           

有四種自動裝配類型:

  • byName尋找和屬性名相同的bean,若找不到,則裝不上。(屬性名和bean id名必須相同)
  • byType:尋找和屬性類型相同的bean,找不到,裝不上,找到多個抛異常。
  • constructor:查找和bean的構造參數一緻的一個或多個bean,若找不到或找到多個,抛異常。按照參數的類型裝配
  • autodetect: (3)和(2)之間選一個方式。不确定性的處理與(3)和(2)一緻。
  • defualt : 這個需要在
  • no : 不自動裝配,這是autowrite的預設值。
    老闆:不懂spring還來做項目?建議離職一、Spring架構二、裝配Bean

    default說明

    需要在

  • 如果在指定了default-atuowrite後,所有的bean的預設的autowire就是中指定的裝配方法;
  • 如果沒有在指定defualt-autorwire,則預設是defualt-autorwire=”no”,所有的bean則預設不自動裝配,除非自己配置autowire

篇幅有限,暫時更新到這裡啦!下一篇盡快上傳~

看到這裡的小夥伴,如果你喜歡這篇文章的話,别忘了轉發、收藏、留言互動!

最近我新整理了一些Java資料,包含面經分享、模拟試題、和視訊幹貨,如果你需要的話,歡迎私信我!

如果對文章有任何問題,歡迎在留言區和我交流~

還有,關注我!關注我!關注我!

繼續閱讀