Spring小結

Spring

官方文檔 https://spring.io/projects/spring-framework#learnhtml

IOC

控制反轉是一種經過描述並經過第三方去生產或獲取特定對象的方式java

IOC建立對象方式

經過無參構造方法來建立

<bean id="user" class="com.pojo.User">
    <property name="name" value="張三"/>
</bean>

經過有參構造方法來建立

<!-- 第一種根據index參數下標設置 -->
<bean id="user1" class="com.pojo.User">
    <!-- index指構造方法 , 下標從0開始 -->
    <constructor-arg index="0" value="張三"/>
</bean>
<!-- 第二種根據參數名字設置 -->
<bean id="user2" class="com.pojo.User">
    <!-- name指參數名 -->
    <constructor-arg name="name" value="李四"/>
</bean>
<!-- 第三種根據參數類型設置 -->
<bean id="user3" class="com.pojo.User">
    <constructor-arg type="java.lang.String" value="王五"/>

配置

別名

<!--設置別名:在獲取Bean的時候可使用別名獲取-->
<alias name="user" alias="userNew"/>

Bean的配置

<!--bean就是java對象,由Spring建立和管理-->

<!--
    id 是bean的標識符,要惟一,若是沒有配置id,name就是默認標識符
    若是配置id,又配置了name,那麼name是別名
    name能夠設置多個別名,能夠用逗號,分號,空格隔開
    若是不配置id和name,能夠根據applicationContext.getBean(.class)獲取對象;

    class是bean的全限定名=包名+類名
-->
<bean id="hello" name="hello2 h2,h3;h4" class="com.pojo.Hello">
    <property name="name" value="Spring"/>
</bean>

import

<import resource="{path}/beans.xml"/>

DI

構造器注入同上

setter注入

要求被注入的屬性,必須有set方法,set方法的方法名由set + 屬性首字母大寫,若是屬性是boolean類型,沒有set方法,是 ismysql

  1. 常量注入web

    <bean id="student" class="com.pojo.Student">
         <property name="name" value="小明"/>
     </bean>
  2. Bean注入spring

    <bean id="addr" class="com.pojo.Address">
         <property name="address" value="重慶"/>
     </bean>
    
     <bean id="student" class="com.pojo.Student">
         <property name="address" ref="addr"/>
     </bean>
  3. 數組注入sql

    <bean id="student" class="com.pojo.Student">
         <property name="books">
             <array>
                 <value>西遊記</value>
                 <value>紅樓夢</value>
             </array>
         </property>
     </bean>
  4. List注入數據庫

    <property name="hobbys">
         <list>
             <value>聽歌</value>
             <value>看電影</value>
         </list>
     </property>
  5. Map注入express

    <property name="card">
         <map>
             <entry key="中國郵政" value="456456456465456"/>
             <entry key="建設" value="1456682255511"/>
         </map>
     </property>
  6. set注入設計模式

    <property name="games">
         <set>
             <value>LOL</value>
             <value>BOB</value>
         </set>
     </property>
  7. Null注入數組

    <property name="wife"><null/></property>
  8. Properties注入

    <property name="info">
         <props>
             <prop key="性別">男</prop>
             <prop key="姓名">小明</prop>
         </props>
     </property>

拓展注入方式

p命名空間注入

導入約束:xmlns:p="http://www.springframework.org/schema/p"

<!--P(屬性: properties)命名空間 , 屬性依然要設置set方法-->
<bean id="user" class="com.pojo.User" p:name="小明" p:age="18"/>

c命名空間注入

導入約束:xmlns:c="http://www.springframework.org/schema/c"

<!--C(構造: Constructor)命名空間 , 屬性依然要設置set方法-->
<bean id="user" class="com.pojo.User" c:name="小明" c:age="18"/>

Bean的做用域

  1. singleton 單例
  2. Prototype 原型
  3. Request
  4. Session
  5. global-session:全局做用域,global-session和Portlet應用相關。當你的應用部署在Portlet容器中工做時,它包含不少portlet。若是你想要聲明讓全部的portlet共用全局的存儲變量的話,那麼這全局變量須要存儲在global-session中。全局做用域與Servlet中的session做用域效果相同。

自動裝配

按名稱自動裝配

<bean id="user" class="com.pojo.User" autowire="byName">
    <property name="str" value="小明"/>
</bean>

經過set方法查找

按類型自動裝配

<bean id="user" class="com.pojo.User" autowire="byType">
    <property name="str" value="小明"/>
</bean>

須要同一類型的對象在Spring容器中惟一

@Autowired

按類型自動裝配

public class User {
    @Autowired
    private Cat cat;

    public Cat getCat() {
        return cat;
    }
}

此時配置文件內容

<!-- 開啓註解支持 -->
<context:annotation-config/>

<bean id="cat" class="com.pojo.Cat"/>
<bean id="user" class="com.pojo.User"/>

required

默認爲true,@Autowired(required=false)說明對象能夠爲null

@Qualifier

@Autowired是根據類型自動裝配的,加上@Qualifier則能夠根據byName的方式自動裝配
@Qualifier不能單獨使用

@Autowired
@Qualifier(value = "cat2")
private Cat cat;

@Resource

  1. @Resource若有指定的name屬性,先按該屬性進行byName方式查找裝配;
  2. 其次再進行默認的byName方式進行裝配;
  3. 若是以上都不成功,則按byType的方式自動裝配。
  4. 都不成功,則報異常。
@Resource(name = "cat2")
private Cat cat;

@Autowired與@Resource異同:

  1. @Autowired與@Resource均可以用來裝配bean。均可以寫在字段上,或寫在setter方法上。
  2. @Autowired默認按類型裝配(屬於spring規範),默認狀況下必需要求依賴對象必須存在,若是要容許null 值,能夠設置它的required屬性爲false,如:@Autowired(required=false) ,若是咱們想使用名稱裝配能夠結合@Qualifier註解進行使用
  3. @Resource(屬於J2EE復返),默認按照名稱進行裝配,名稱能夠經過name屬性進行指定。若是沒有指定name屬性,當註解寫在字段上時,默認取字段名進行按照名稱查找,若是註解寫在setter方法上默認取屬性名進行裝配。 當找不到與名稱匹配的bean時才按照類型進行裝配。可是須要注意的是,若是name屬性一旦指定,就只會按照名稱進行裝配。

它們的做用相同都是用註解方式注入對象,但執行順序不一樣。@Autowired先byType,@Resource先byName。

註解開發

配置文件中引入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>

Bean的實現

配置掃描哪些包

<!--指定註解掃描包-->
<context:component-scan base-package="com.pojo"/>

掃描過濾

<context:include-filter  type="annotation" expression="org.springframework.stereotype.Controller"/>>//包含
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service"/>>//排除

過濾方式

annotation:註解
assignable:指定class或interface的全名
aspectj:AspectJ語法
regex:正則

若是配置了 <context:component-scan> 那麼 <context:annotation-config/> 標籤就能夠不用再xml中配置了,由於前者包含了後者

給類加上註解

@Component
    @Controller:web層
    @Service:service層
    @Repository:dao層

屬性注入

@Component("user")
// 至關於配置文件中 <bean id="user" class="當前註解的類"/>
public class User {
    @Value("小明")
    // 至關於配置文件中 <property name="name" value="小明"/>
    public String name;
}

或者在set方法上添加@value("值")

做用域

@Controller("user")
@Scope("prototype")
public class User {
    @Value("小明")
    public String name;
}

基於Java類的純註解配置

@Configuration//表明這是一個配置類
@Import(MyConfig2.class)//導入合併其餘配置類,相似於配置文件中的 inculde 標籤
@ComponentScan("com.pojo")//指定掃描的包
public class MyConfig {

    @Bean(name="dog2")//經過方法註冊一個bean,這裏的返回值就Bean的類型,方法名就是bean的id!也能夠手動指定名稱
    public Dog dog(){
        return new Dog();
    }
}

AOP

官方文檔https://docs.spring.io/spring/docs/5.2.1.RELEASE/spring-framework-reference/core.html#aop

相關術語

  • Joinpoint(鏈接點):
    所謂鏈接點是指那些被攔截到的點。在 Spring 中,這些點指的是方法,由於 Spring 只支持方法類型的鏈接點。
  • Pointcut(切入點):
    所謂切入點是指咱們要對哪些 Joinpoint 進行攔截的定義。
  • Advice(通知/加強):
    所謂通知是指攔截到 Joinpoint 以後所要作的事情就是通知。
  • Introduction(引介):
    引介是一種特殊的通知在不修改類代碼的前提下,Introduction 能夠在運行期爲類動態地添加一些方法或 Field。
  • Target(目標對象):
    代理的目標對象。
  • Weaving(織入):
    是指把加強應用到目標對象來建立新的代理對象的過程。
    Spring 採用動態代理織入,而 AspectJ 採用編譯期織入和類裝載期織入。
  • Proxy(代理) :
    一個類被 AOP 織入加強後,就產生一個結果代理類。
  • Aspect(切面):
    是切入點和通知(引介)的結合。

通知類型

通知類型 名稱 說明
前置通知 Before advice 鏈接點前執行,除非拋出異常,不然不能阻止方法的繼續執行
後置通知(最終通知) After (finally) advice 鏈接點執行完成後執行,總會執行
正常返回通知 After returning advice 在鏈接點正常執行完成後執行,若是鏈接點拋出異常,則不會執行
異常返回通知 After throwing advice 在鏈接點拋出異常後執行
環繞通知 Around advice 鏈接點先後執行

切入點表達式語法

execution([修飾符] 返回值類型 包名.類名.方法名(參數))

* 表示任意一個
.. 表示多個
xml中鏈接子表達式用 and, or, not
註解中用 &&, ||, !

XML配置AOP

<!-- 聲明開始aop的配置 -->
<aop:config>
    <!-- 配置切面。
        id:惟一標識,
        ref:引用配置好的通知類bean的id
    -->
    <aop:aspect id="txAdvice" ref="txManager">
        <!-- 配置切入點表達式。就是指定對哪些類的哪些方法進行加強。
            expression:用於定義切入點表達式,
            id:切入點惟一標識 
        -->
        <aop:pointcut expression="execution(表達式)" id="pt1"/>
        <!-- 前置通知。
            method:指定通知類中的加強方法名稱;
            pointcut:指定切入點表達式
            pointcut-ref:指定切入點的表達式的引用
        -->
        <aop:before method="beginTransaction" pointcut-ref="pt1"/>
        <!-- 正常返回通知
            returning:獲取返回值傳遞到對應的參數上,method的方法必須聲明一個名爲retVal的參數
        -->
        <aop:after-returning method="commit" returning="retVal" pointcut-ref="pt1"/>
        <!-- 異常返回通知
            throwing:獲取異常傳遞到對應的參數上,method的方法必須聲明一個名爲dataAccessEx的參數
        -->
        <aop:after-throwing method="rollback" throwing="dataAccessEx" pointcut-ref="pt1"/>
        <!-- 最終通知 -->
        <aop:after method="release" pointcut-ref="pt1"/>
        <!-- 環繞通知 
            一般狀況獨立使用
        -->
        <aop:advisor method="release" pointcut-ref="pt1"/>
    </aop:aspect>
</aop:config>

註解配置AOP

@Component("txManager")
@Aspect
public class AnnotationPointcut {
    @Before("execution(* com.service.UserServiceImpl.*(..))")
    public void before(){
        System.out.println("---------方法執行前---------");
    }

    @After("execution(* com.service.UserServiceImpl.*(..))")
    public void after(){
        System.out.println("---------方法執行後---------");
    }

    @Around("execution(* com.service.UserServiceImpl.*(..))")
    public void around(ProceedingJoinPoint jp) throws Throwable {
        System.out.println("環繞前");
        System.out.println("簽名:"+jp.getSignature());
        //執行目標方法proceed
        Object proceed = jp.proceed();
        System.out.println("環繞後");
        System.out.println(proceed);
    }
}

開啓註解AOP的支持

在 spring 配置文件中開啓 spring 對註解 AOP 的支持

<!-- 開啓 spring 對註解 AOP 的支持 -->
<aop:aspectj-autoproxy/>

不使用 XML 的配置方式

@Configuration
@ComponentScan(basePackages="...")
@EnableAspectJAutoProxy
public class SpringConfiguration {
}

aop:aspectj-autoproxy:說明

  1. 經過aop命名空間的 聲明自動爲spring容器中那些配置@aspectJ切面的bean建立代理,織入切面。固然,spring 在內部依舊採用AnnotationAwareAspectJAutoProxyCreator進行自動代理的建立工做,但具體實現的細節已經被 隱藏起來了

  2. 有一個proxy-target-class屬性,默認爲false,表示使用jdk動態代理織入加強,當配爲 時,表示使用CGLib動態代理技術織入加強。不過即便proxy-target-class設置爲false,若是目標類沒有聲明接口,則spring將自動使用CGLib動態代理。

整合MyBatis(MyBatis-Spring)

官方文檔:http://mybatis.org/spring/zh/index.html

Maven依賴

<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis-spring</artifactId>
    <version>2.0.2</version>
</dependency>

版本對應

MyBatis-Spring MyBatis Spring 框架 Spring Batch Java
2.0 3.5+ 5.0+ 4.0+ Java 8+
1.3 3.4+ 3.2.2+ 2.1+ Java 6+

方式一

  1. 引入Spring配置文件的beans.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. 配置數據源替換mybatis的數據源

    <!--配置數據源:數據源有很是多,可使用第三方的,也可以使使用Spring的-->
     <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
         <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
         <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&amp;useUnicode=true&amp;characterEncoding=utf8"/>
         <property name="username" value="root"/>
         <property name="password" value="123456"/>
     </bean>
  3. 配置SqlSessionFactory,關聯MyBatis

    <!--配置SqlSessionFactory-->
     <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
         <property name="dataSource" ref="dataSource"/>
         <!--關聯Mybatis-->
         <property name="configLocation" value="classpath:mybatis-config.xml"/>
         <property name="mapperLocations" value="classpath:com/dao/*.xml"/>
     </bean>
  4. 註冊SqlSessionTemplate,關聯SqlSessionFactory

    <!--註冊sqlSessionTemplate , 關聯sqlSessionFactory-->
     <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
         <!--利用構造器注入-->
         <constructor-arg index="0" ref="sqlSessionFactory"/>
     </bean>
  5. 增長Dao接口的實現類;私有化SqlSessionTemplate

    public class UserDaoImpl implements UserMapper {
    
         //sqlSession不用咱們本身建立了,Spring來管理
         private SqlSessionTemplate sqlSession;
    
         public void setSqlSession(SqlSessionTemplate sqlSession) {
             this.sqlSession = sqlSession;
         }
    
         public List<User> selectUser() {
             UserMapper mapper = sqlSession.getMapper(UserMapper.class);
             return mapper.selectUser();
         }
    
     }
  6. 註冊bean實現

    <bean id="userDao" class="com.kuang.dao.UserDaoImpl">
         <property name="sqlSession" ref="sqlSession"/>
     </bean>

方式二:SqlSessionDaoSupport

官方文檔http://mybatis.org/spring/zh/sqlsession.html#SqlSessionDaoSupport

聲明式事務

官方文檔https://docs.spring.io/spring/docs/5.2.1.RELEASE/spring-framework-reference/data-access.html#transaction-declarative

事務

事務四個屬性ACID

  • 原子性(atomicity)

    事務是原子性操做,由一系列動做組成,事務的原子性確保動做要麼所有完成,要麼徹底不起做用

  • 一致性(consistency)

    一旦全部事務動做完成,事務就要被提交。數據和資源處於一種知足業務規則的一致性狀態中

  • 隔離性(isolation)

    可能多個事務會同時處理相同的數據,所以每一個事務都應該與其餘事務隔離開來,防止數據損壞

  • 持久性(durability)

    事務一旦完成,不管系統發生什麼錯誤,結果都不會受到影響。一般狀況下,事務的結果被寫到持久化存儲器中

事務傳播行爲

Spring支持7種傳播行爲

  • propagation_requierd:若是當前沒有事務,就新建一個事務,若是已存在一個事務中,加入到這個事務中,這是最多見的選擇。
  • propagation_supports:支持當前事務,若是沒有當前事務,就以非事務方法執行。
  • propagation_mandatory:使用當前事務,若是沒有當前事務,就拋出異常。
  • propagation_required_new:新建事務,若是當前存在事務,把當前事務掛起。
  • propagation_not_supported:以非事務方式執行操做,若是當前存在事務,就把當前事務掛起。
  • propagation_never:以非事務方式執行操做,若是當前事務存在則拋出異常。
  • propagation_nested:若是當前存在事務,則在嵌套事務內執行。若是當前沒有事務,則執行與propagation_required相似的操做

事務隔離級別

spring中事務的隔離級別能夠經過隔離屬性指定

DEFAULT 使用底層數據庫的默認隔離級別,大部分數據庫,默認隔離級別都是READ_COMMITED
READ_COMMITED 只容許事務讀取已經被其餘事務提交的更改,能夠避免髒讀,但不可重複讀和幻讀問題仍然可能出現
READ_UNCOMMITED 容許事務讀取未被其餘事務提交的更改。髒讀,不可重複讀,幻讀均可能會出現
REPEATABLE_READ 確保事務能夠屢次從一個字段中讀取相同的值。在這個事務持續期間,禁止其餘事務對這個字段進行更新,能夠避免髒讀和不可重複讀,可是幻讀的問題依然存在
SERIALIZABLE 確保事務能夠從一個表中讀取相同的行,在這個事務持續期間,禁止其餘事務對該表執行插入,更新,刪除。全部的併發問題都能避免,可是性能比較低。

注意:事務的隔離級別須要底層數據庫引擎的支持,而不是應用程序或者框架的支持

  • Oracle支持2種事務隔離級別:READ_COMMITED,SERIALIZABLE
  • MySQL支持4種事務隔離級別

基於XML

導入 aop 和 tx 兩個名稱空間

步驟:

  1. 配置事務管理器

    <!-- 配置一個事務管理器 -->
     <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
         <!-- 注入 DataSource -->
         <property name="dataSource" ref="dataSource"></property>
     </bean>
  2. 配置事務的通知引用事務管理器

    <!-- 事務的配置 -->
     <tx:advice id="txAdvice" transaction-manager="transactionManager"></tx:advice>
  3. 配置事務的屬性

    <!--在 tx:advice 標籤內部 配置事務的屬性 -->
     <tx:attributes>
         <!-- 指定方法名稱:是業務核心方法
             read-only:是不是隻讀事務。默認 false,不僅讀。
             isolation:指定事務的隔離級別。默認值是使用數據庫的默認隔離級別。
             propagation:指定事務的傳播行爲。
             timeout:指定超時時間。默認值爲: -1。永不超時。
             rollback-for:用於指定一個異常,當執行產生該異常時,事務回滾。產生其餘異常,事務不回滾。沒有默認值,任何異常都回滾。
             no-rollback-for:用於指定一個異常,當產生該異常時,事務不回滾,產生其餘異常時,事務回滾。沒有默認值,任何異常都回滾。
         -->
         <tx:method name="*" read-only="false" propagation="REQUIRED"/>
         <tx:method name="find*" read-only="true" propagation="SUPPORTS"/>
     </tx:attributes>
  4. 配置 AOP 切入點表達式

    <!-- 配置 aop -->
     <aop:config>
         <!-- 配置切入點表達式 -->
         <aop:pointcut expression="execution(* com.service.impl.*.*(..))" id="pt1"/>
     </aop:config>
  5. 配置切入點表達式和事務通知的對應關係

    <!-- 在 aop:config 標籤內部: 創建事務的通知和切入點表達式的關係 -->
     <aop:advisor advice-ref="txAdvice" pointcut-ref="pt1"/>

基於註解

  1. 配置事務管理器並注入數據源

    <!-- 配置事務管理器 -->
     <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
         <property name="dataSource" ref="dataSource"></property>
     </bean>
  2. 在業務層使用 @Transactional 註解

    @Service("accountService")
     @Transactional(readOnly=true,propagation=Propagation.SUPPORTS)
     public class AccountServiceImpl implements IAccountService {
         ...
     }
    • 該註解的屬性和 xml 中的屬性含義一致。該註解可- 以出如今接口上,類上和方法上。
    • 出現接口上,表示該接口的全部實現類都有事務支持。
    • 出如今類上,表示類中全部方法有事務支持
    • 出如今方法上,表示方法有事務支持。
    • 以上三個位置的優先級:方法>類>接口
  3. 在配置文件中開啓 spring 對註解事務的支持

    <!-- 開啓 spring 對註解事務的支持 -->
     <tx:annotation-driven transaction-manager="transactionManager"/>

使用java配置類替換xml實現全註解

@Configuration
@EnableTransactionManagement
public class SpringTxConfiguration {
    //裏面配置數據源,配置 JdbcTemplate,配置事務管理器
}

知識點

Spring使用到的設計模式

  1. 工廠模式:BeanFactory就是簡單工廠模式的體現,用來建立對象的實例;
  2. 單例模式:Bean默認爲單例模式。
  3. 代理模式:Spring的AOP功能用到了JDK的動態代理和CGLIB字節碼生成技術;
  4. 模板方法:用來解決代碼重複的問題。好比. RestTemplate, JmsTemplate, JpaTemplate。
  5. 觀察者模式:定義對象鍵一種一對多的依賴關係,當一個對象的狀態發生改變時,全部依賴於它的對象都會獲得通知被制動更新,如Spring中listener的實現--ApplicationListener。

Spring如何處理線程併發問題?

  • 在通常狀況下,只有無狀態的Bean才能夠在多線程環境下共享,在Spring中,絕大部分Bean均可以聲明爲singleton做用域,由於Spring對一些Bean中非線程安全狀態採用ThreadLocal進行處理,解決線程安全問題。

  • ThreadLocal和線程同步機制都是爲了解決多線程中相同變量的訪問衝突問題。同步機制採用了「時間換空間」的方式,僅提供一份變量,不一樣的線程在訪問前須要獲取鎖,沒得到鎖的線程則須要排隊。而ThreadLocal採用了「空間換時間」的方式。

  • ThreadLocal會爲每個線程提供一個獨立的變量副本,從而隔離了多個線程對數據的訪問衝突。由於每個線程都擁有本身的變量副本,從而也就沒有必要對該變量進行同步了。ThreadLocal提供了線程安全的共享對象,在編寫多線程代碼時,能夠把不安全的變量封裝進ThreadLocal。

Spring事務的實現方式和實現原理

Spring事務的本質其實就是數據庫對事務的支持,沒有數據庫的事務支持,spring是沒法提供事務功能的。真正的數據庫層的事務提交和回滾是經過binlog或者redo log實現的。

Spring Bean的生命週期?

Servlet的生命週期:實例化,初始init,接收請求service,銷燬destroy;

Bean生命週期也相似,以下:

  1. 實例化Bean:

    對於BeanFactory容器,當客戶向容器請求一個還沒有初始化的bean時,或初始化bean的時候須要注入另外一個還沒有初始化的依賴時,容器就會調用createBean進行實例化。對於ApplicationContext容器,當容器啓動結束後,經過獲取BeanDefinition對象中的信息,實例化全部的bean。

  2. 設置對象屬性(依賴注入):

    實例化後的對象被封裝在BeanWrapper對象中,緊接着,Spring根據BeanDefinition中的信息 以及 經過BeanWrapper提供的設置屬性的接口完成依賴注入。

  3. 處理Aware接口:

    接着,Spring會檢測該對象是否實現了xxxAware接口,並將相關的xxxAware實例注入給Bean:

    1. 若是這個Bean已經實現了BeanNameAware接口,會調用它實現的setBeanName(String beanId)方法,此處傳遞的就是Spring配置文件中Bean的id值;

    2. 若是這個Bean已經實現了BeanFactoryAware接口,會調用它實現的setBeanFactory()方法,傳遞的是Spring工廠自身。

    3. 若是這個Bean已經實現了ApplicationContextAware接口,會調用setApplicationContext(ApplicationContext)方法,傳入Spring上下文;

  4. BeanPostProcessor:

    若是想對Bean進行一些自定義的處理,那麼可讓Bean實現了BeanPostProcessor接口,那將會調用postProcessBeforeInitialization(Object obj, String s)方法。

  5. InitializingBean 與 init-method:

    若是Bean在Spring配置文件中配置了 init-method 屬性,則會自動調用其配置的初始化方法。

  6. 若是這個Bean實現了BeanPostProcessor接口,將會調用postProcessAfterInitialization(Object obj, String s)方法;因爲這個方法是在Bean初始化結束時調用的,因此能夠被應用於內存或緩存技術;

    以上幾個步驟完成後,Bean就已經被正確建立了,以後就可使用這個Bean了。

  7. DisposableBean:

    當Bean再也不須要時,會通過清理階段,若是Bean實現了DisposableBean這個接口,會調用其實現的destroy()方法;

  8. destroy-method:

    最後,若是這個Bean的Spring配置中配置了destroy-method屬性,會自動調用其配置的銷燬方法。

  1. 實例化bean對象

  2. 注入bean的全部屬性

  3. 設置bean的id

    調用BeanNameAware接口的setBeanName(String)方法

  4. 設置bean工廠

    調用BeanFactoryAware接口的setBeanFactory()方法

  5. 設置實例所在的上下文空間

    調用ApplicationContextAware接口的setApplicationContext()方法,傳入Spring上下文

  6. 調用後置處理器的預初始化方法

    調用BeanPostProcessor接口的postProcessorBeforeInitialization()方法

  7. 執行InitializingBean的afterPropertiesSet()

  8. 調用使用init-method配置的自定義初始化方法

  9. 調用後置處理器的後初始化方法

    調用BeanPostProcessor接口的postProcessorAfterInitialization()方法

  10. 調用DisPosableBean接口的destory()方法

  11. 調用使用destroy-method配置的自定義銷燬由方法

@Component 和 @Bean 的區別

  • 做用對象不一樣: @Component 註解做用於類,而@Bean註解做用於方法。
  • @Component一般是經過類路徑掃描來自動偵測以及自動裝配到Spring容器中(咱們可使用 @ComponentScan 註解定義要掃描的路徑從中找出標識了須要裝配的類自動裝配到 Spring 的 bean 容器中)。@Bean 註解一般是咱們在標有該註解的方法中定義產生這個 bean,@Bean告訴了Spring這是某個類的示例,當我須要用它的時候還給我。
  • @Bean 註解比 Component 註解的自定義性更強,並且不少地方咱們只能經過 @Bean 註解來註冊bean。好比當咱們引用第三方庫中的類須要裝配到 Spring容器時,則只能經過 @Bean來實現。

Spring中的核心類有那些,各有什麼做用?

  • BeanFactory:產生一個新的實例,能夠實現單例模式
  • BeanWrapper:提供統一的get及set方法
  • ApplicationContext:提供框架的實現,包括BeanFactory的全部功能

Bean的調用方式

  • 使用BeanWrapper

    HelloWorld hw=new HelloWorld();
      BeanWrapper bw=new BeanWrapperImpl(hw);
      bw.setPropertyvalue("msg","HelloWorld");
      system.out.println(bw.getPropertyCalue("msg"));
  • 使用BeanFactory

    InputStream is=new FileInputStream("config.xml");
      XmlBeanFactory factory=new XmlBeanFactory(is);
      HelloWorld hw=(HelloWorld) factory.getBean("HelloWorld");
      system.out.println(hw.getMsg());
  • 使用ApplicationConttext

    ApplicationContext actx=new FleSystemXmlApplicationContext("config.xml");
      HelloWorld hw=(HelloWorld) actx.getBean("HelloWorld");
      System.out.println(hw.getMsg());
相關文章
相關標籤/搜索