框架:spring总结
struts 是 web 框架 (jsp/action/actionfrom)?
hibernate 是 orm框架,處于持久層.
那么,什么是Spring?
spring 是容器框架,用于配置bean,并維護bean之間關系的框架 。
spring中非常重要的概念:bean,ioc,di
一個簡單的spring入門項目.
spring實際上是一個容器框架,可以配置各種bean(action/service/domain/dao),并且可以維護bean與bean的關系,當我們需要使用某個bean的時候,我們可以getBean(id),使用即可.
什么是bean?
Bean在Spring和SpringMVC中無所不在,將這個概念內(nèi)化很重要,下面分享一下我的想法:
一、Bean是啥
1、Java面向?qū)ο?#xff0c;對象有方法和屬性,那么就需要對象實例來調(diào)用方法和屬性(即實例化);
2、凡是有方法或?qū)傩缘念惗夹枰獙嵗?/span>,這樣才能具象化去使用這些方法和屬性;
3、規(guī)律:凡是子類及帶有方法或?qū)傩缘念惗家由?注冊Bean到Spring IoC的注解;
(@Component , @Repository , @ Controller , @Service , @Configration)
4、把Bean理解為類的代理或代言人(實際上確實是通過反射、代理來實現(xiàn)的),這樣它就能代表類擁有該擁有的東西了
5、我們都在微博上@過某某,對方會優(yōu)先看到這條信息,并給你反饋,那么在Spring中,你標識一個@符號,那么Spring就會來看看,并且從這里拿到一個Bean(注冊)或者給出一個Bean(使用)
二、注解分為兩類:
1、一類是使用Bean,即是把已經(jīng)在xml文件中配置好的Bean拿來用,完成屬性、方法的組裝;
比如@Autowired , @Resource,可以通過byTYPE(@Autowired)、byNAME(@Resource)的方式獲取Bean;
?
2、一類是注冊Bean,@Component , @Repository , @ Controller , @Service , @Configration這些注解都是把你要實例化的對象轉(zhuǎn)化成一個Bean,放在IoC容器中,等你要用的時候,它會和上面的@Autowired , @Resource配合到一起,把對象、屬性、方法完美組裝。
?
三、@Bean是啥?
?
1、原理是什么?先看下源碼中的部分內(nèi)容:
?
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | Indicates that a method produces a bean to be managed?by?the Spring container. ? ?<h3>Overview</h3> ? ?<p>The names and semantics of the attributes to?this?annotation are intentionally ?similar to those of the {@code <bean/>} element?in?the Spring XML schema. For ?example: ? ?<pre?class="code"> ?????@Bean ?????public?MyBean myBean() { ?????????// instantiate and configure MyBean obj ?????????return?obj; ????}</pre> |
意思是@Bean明確地指示了一種方法,什么方法呢——產(chǎn)生一個bean的方法,并且交給Spring容器管理;從這我們就明白了為啥@Bean是放在方法的注釋上了,因為它很明確地告訴被注釋的方法,你給我產(chǎn)生一個Bean,然后交給Spring容器,剩下的你就別管了。
?2、記住,@Bean就放在方法上,就是產(chǎn)生一個Bean,那你是不是又糊涂了,因為已經(jīng)在你定義的類上加了@Configration等注冊Bean的注解了,為啥還要用@Bean呢?這個我也不知道,下面我給個例子,一起探討一下吧:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 3 | package?com.edu.fruit; ??//定義一個接口 ????public?interface?Fruit<T>{ ????????//沒有方法 } ? /* *定義兩個子類 */ package?com.edu.fruit; ?????@Configuration ?????public?class?Apple?implements?Fruit<Integer>{//將Apple類約束為Integer類型 ? } ? package?com.edu.fruit; ?????@Configuration ?????public?class?GinSeng?implements?Fruit<String>{//將GinSeng 類約束為String類型 ? } /* *業(yè)務邏輯類 */ package?com.edu.service; ???????@Configuration ???????public?class?FruitService { ??????????@Autowired ??????????private?Apple apple; ??????????@Autowired ??????????private?GinSeng ginseng; ????//定義一個產(chǎn)生Bean的方法 ???????@Bean(name="getApple") ???????public?Fruit<?> getApple(){ ???????System.out.println(apple.getClass().getName().hashCode()); ?????????System.out.println(ginseng.getClass().getName().hashCode()); ???????return?new?Apple(); } } /* *測試類 */ @RunWith(BlockJUnit4ClassRunner.class) public?class?Config { ????public?Config(){ ????????super("classpath:spring-fruit.xml"); ????} ????@Test ????public?void?test(){ ????????super.getBean("getApple");//這個Bean從哪來,從上面的@Bean下面的方法中來,返回 ??????????????????????????????????????????????????????????的是一個Apple類實例對象 ????????? ????} } |
從上面的例子也印證了我上面的總結的內(nèi)容:
1、凡是子類及帶屬性、方法的類都注冊Bean到Spring中,交給它管理;
2、@Bean 用在方法上,告訴Spring容器,你可以從下面這個方法中拿到一個Bean
什么是IOC?
IOC,控制反轉(zhuǎn);所謂控制反轉(zhuǎn)就是把創(chuàng)建對象和維護對象關系的權利轉(zhuǎn)移到Spring容器(applicationContext.xml)中,而程序本身不在維護!
什么是DI?
依賴注入,容易維護好對象之間的依賴關系(引用等),就是當程序需要對象的時候,容器將對象注入到程序中,程序此時也依賴容器的對象注入。實際上di和ioc是同一個概念,spring設計者認為di更準確表示spring核心技術。
1.bean容器中獲取bean對象的方法。
1)從ApplicationContext應用上下文容器中獲取
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(".xml文件");? 三種獲取上下文的方法:
??? 1.ClassPathXmlApplicationContext?從類路徑加載
??? 2.FileSystemXmlApplicationContext? 從文件系統(tǒng)中加載
??? 3.XmlWebApplicationContext?? 從web系統(tǒng)中加載?
2)從bean工廠中獲取(BeanFactory)?
BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource(".xml文件"));兩種方式的比較:
1)加載XML時,ApplicationContext實例化容器的時候,實例化所有對象。當我們要使用的時候,直接獲取。即方便快捷,提前加載,但是浪費內(nèi)存。(餓漢)
2)加載XML時,BeanFactory實例化容器,但不會實例化所配置的bean對象,只有當我們getBean的時候,才會創(chuàng)建。(懶漢)
在沒有特殊要求的時候,一般使用ApplicationContext
Spring底層對象實例的創(chuàng)建是基于反射和HashMap機制
?
2.bean的scope
默認的生命周期是singleton 單例模式
3.配置bean ?如何給集合類型注入值.?
java中主要的集合有幾種: map set list / 數(shù)組
Department類:
package com.hsp.collection;import java.util.List; import java.util.Map; import java.util.Set;public class Department {private String name;private String[] empName;private List<Employee> empList;private Set<Employee> empsets;private Map<String,Employee> empMaps;private properties pp;public Set<Employee> getEmpsets() {return empsets;}public void setEmpsets(Set<Employee> empsets) {this.empsets = empsets;}public String[] getEmpName() {return empName;}public void setEmpName(String[] empName) {this.empName = empName;}public String getName() {return name;}public void setName(String name) {this.name = name;}public List<Employee> getEmpList() {return empList;}public void setEmpList(List<Employee> empList) {this.empList = empList;}public Map<String, Employee> getEmpMaps() {return empMaps;}public void setEmpMaps(Map<String, Employee> empMaps) {this.empMaps = empMaps;}}Employeel類
package com.hsp.collection; public class Employee {private String name;private int id;public int getId() {return id;}public void setId(int id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;} }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"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.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsdhttp://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd"><bean id="department" class="com.hsp.collection.Department"> <property name="name" value="財務部"/><!-- 給數(shù)組注入值 --> <property name="empName"><list><value>小明</value><value>小明小明</value><value>小明小明小明小明</value></list> </property><!-- 給list注入值 list 中可以有相當?shù)膶ο?--> <property name="empList"><list><ref bean="emp2" /><ref bean="emp1"/><ref bean="emp1"/><ref bean="emp1"/><ref bean="emp1"/><ref bean="emp1"/><ref bean="emp1"/></list> </property><!-- 給set注入值 set不能有相同的對象 --> <property name="empsets"><set><ref bean="emp1" /><ref bean="emp2"/><ref bean="emp2"/><ref bean="emp2"/><ref bean="emp2"/></set> </property><!-- 給map注入值 map只有key不一樣,就可以裝配value --> <property name="empMaps"><map><entry key="11" value-ref="emp1" /> <entry key="22" value-ref="emp2"/><entry key="33" value-ref="emp1"/></map> </property><!-- 給屬性集合配置 【點http協(xié)議 referer 】--> <property name="pp"><props><prop key="pp1">abcd</prop><prop key="pp2">hello</prop></props> </property> </bean><bean id="emp1" class="com.hsp.collection.Employee"> <property name="name" value="北京"/> <property name="id" value="1"/> </bean><bean id="emp2" class="com.hsp.collection.Employee"> <property name="name" value="天津"/> <property name="id" value="2"/> </bean></beans>4.內(nèi)部bean,也就是bean的嵌套
<bean id=”foo” class=”....Foo”><property name=”屬性”><!—第一方法引用--><ref bean=’bean對象名’/><!—內(nèi)部bean--><bean> <properyt></property> </bean> </property> </bean>5.繼承配置
public class Student
public class Gradate extends Student
在beans.xml文件中體現(xiàn)配置
<!-- 配置一個學生對象 --> <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,則會替換從父對象繼承的數(shù)據(jù) --><property name="name" value="小明"/><property name="degree" value="學士"/> </bean>6.通過properties取數(shù)據(jù)(接上面的例子)
properties pp = department.getPp(); for(Entry<Object,Object>entry:pp.entrySet()){System.out.println(entry.getKey().toString()+" "+entry.getValue());}7.按照構造函數(shù)方法注入bean?? (類中必須要有構造函數(shù))
beans.xml 關鍵代碼:
<!-- 配置一個雇員對象 --> <bean id="employee" class="com.hsp.constructor.Employee"> <!-- 通過構造函數(shù)來注入屬性值 --> <constructor-arg index="0" type="java.lang.String" value="大明" /> </bean>8.自動裝配
1.byName
<!-- 配置一個master對象 --> <bean id="master" class="com.hsp.autowire.Master" autowire="byName"> <property name="name"> <value>順平</value> </property> </bean> <!-- 配置dog對象 --> <bean id="dog" class="com.hsp.autowire.Dog"> <property name="name" value="小黃"/> <property name="age" value="3"/> </bean>2.byType: byType:尋找和屬性類型相同的bean,找不到,裝不上,找到多個拋異常。
3.constructor: autowire="constructor"?? 查找和bean的構造參數(shù)一致的一個或多個bean,若找不到或找到多個,拋異常。
按照參數(shù)的類型裝配? 。
4.?autodetect?? (3)和(2)之間選一個方式。不確定性的處理與(3)和(2)一致。 (construct優(yōu)先級要高)
5.default
這個需要在<beans defualt-autorwire=“指定”?/>
當你在<beans >指定了 default-atuowrite后, 所有的bean的 默認的autowire就是 指定的裝配方法;
如果沒有在<beans defualt-autorwire=“指定”?/> 沒有 ?defualt-autorwire=“指定”?,則默認是
defualt-autorwire=”no”
6.no? 不自動裝配
9.使用spring的特殊bean,完成分散配置
??? 創(chuàng)建properties文件,將所有的屬性值按照key-value的形式放入文件中。
<context:property-placeholder location=".properties文件路徑"/> <!-- 配置一DBUtil對象 $占位符號 --> <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><!-- 配置一DBUtil對象 --> <bean id="dbutil2" class="com.hsp.dispatch.DBUtil"> <property name="name" value="${db2.name}" /> <property name="drivername" value="${db2.drivername}" /> <property name="url" value="${db2.url}" /> <property name="pwd" value="${db2.pwd}" /> </bean>db.properties:
name=scott drivername=oracle:jdbc:driver:OracleDirver url=jdbc:oracle:thin:@127.0.0.1:1521:hsp pwd=tiger啟用類中的注解
<context:annotation-config/>
Bean的作用域
?Spring3中為Bean定義了5中作用域,
分別為singleton(單例)、prototype(原型)、request、session和global session,5種作用域說明如下:
1.??? singleton:單例模式,Spring IoC容器中只會存在一個共享的Bean實例,無論有多少個Bean引用它,始終指向同一對象。Singleton作用域是Spring中的缺省作用域,也可以顯示的將Bean定義為singleton模式,配置為:
·????????<bean id="userDao"class="com.ioc.UserDaoImpl" scope="singleton"/>
2.??? prototype:原型模式,每次通過Spring容器獲取prototype定義的bean時,容器都將創(chuàng)建一個新的Bean實例,每個Bean實例都有自己的屬性和狀態(tài),而singleton全局只有一個對象。
根據(jù)經(jīng)驗,對有狀態(tài)的bean使用prototype作用域,而對無狀態(tài)的bean使用singleton作用域。
3.??? request:在一次Http請求中,容器會返回該Bean的同一實例。而對不同的Http請求則會產(chǎn)生新的Bean,而且該bean僅在當前Http Request內(nèi)有效。
·????????<bean id="loginAction" class="com.cnblogs.Login "scope="request"/>,針對每一次Http請求,Spring容器根據(jù)該bean的定義創(chuàng)建一個全新的實例,且該實例僅在當前Http請求內(nèi)有效,而其它請求無法看到當前請求中狀態(tài)的變化,當當前Http請求結束,該bean實例也將會被銷毀。
4.??? session:在一次Http Session中,容器會返回該Bean的同一實例。而對不同的Session請求則會創(chuàng)建新的實例,該bean實例僅在當前Session內(nèi)有效。
·????????<beanid="userPreference" class="com.ioc.UserPreference"scope="session"/>,同Http請求相同,每一次session請求創(chuàng)建新的實例,而不同的實例之間不共享屬性,且實例僅在自己的session請求內(nèi)有效,請求結束,則實例將被銷毀。
5.??? global Session:在一個全局的Http Session中,容器會返回該Bean的同一個實例,僅在使用portlet context時有效。
?Bean的生命周期
經(jīng)過如上對Bean作用域的介紹,接下來將在Bean作用域的基礎上講解Bean的生命周期。
Spring容器可以管理singleton作用域下Bean的生命周期,在此作用域下,Spring能夠精確地知道Bean何時被創(chuàng)建,何時初始化完成,以及何時被銷毀。而對于prototype作用域的Bean,Spring只負責創(chuàng)建,當容器創(chuàng)建了Bean的實例后,Bean的實例就交給了客戶端的代碼管理,Spring容器將不再跟蹤其生命周期,并且不會管理那些被配置成prototype作用域的Bean的生命周期。Spring中Bean的生命周期的執(zhí)行是一個很復雜的過程,讀者可以利用Spring提供的方法來定制Bean的創(chuàng)建過程。Spring容器在保證一個bean實例能夠使用之前會做很多工作:
1.Spring對Bean進行實例化(相當于程序中的new Xx())
2.Spring將值和Bean的引用注入進Bean對應的屬性中,也就是IOC注入
3.如果Bean實現(xiàn)了BeanNameAware接口,Spring將Bean的ID傳遞給setBeanName()方法
(實現(xiàn)BeanNameAware主要是為了通過Bean的引用來獲得Bean的ID,一般業(yè)務中是很少有用到Bean的ID的)
4.如果Bean實現(xiàn)了BeanFactoryAware接口,Spring將調(diào)用setBeanDactory(BeanFactory)方法并把BeanFactory容器實例作為參數(shù)傳入。
(實現(xiàn)BeanFactoryAware 主要目的是為了獲取Spring容器(為了獲得容器,從而調(diào)用容器里的東西),如Bean通過Spring容器發(fā)布事件等)傳遞的是Spring工廠本身(可以用這個方法獲取到其他Bean)
取得所有的事件處理的classbean做進一步的消費者事件處理2),不同的是Spring容器在調(diào)用setApplicationContext方法時會把它自己作為setApplicationContext 的參數(shù)傳入,而Spring容器在調(diào)用setBeanDactory前需要程序員自己指定(注入)setBeanDactory里的參數(shù)BeanFactory )傳入Spring上下文,該方式同樣可以實現(xiàn)步驟4,但比4更好,因為ApplicationContext是BeanFactory的子接口,有更多的實現(xiàn)方法.(如果應用Spring的工廠也就是BeanFactory的話去掉這一步就Ok了
?)
?
6.如果Bean實現(xiàn)了BeanPostProcess接口,Spring將調(diào)用它們的postProcessBeforeInitialization(預初始化)方法
(作用是在Bean實例創(chuàng)建成功后對進行增強處理,如對Bean進行修改,增加某個功能)
7.如果Bean實現(xiàn)了InitializingBean接口,Spring將調(diào)用它們的afterPropertiesSet方法,作用與在配置文件中對Bean使用init-method聲明初始化的作用一樣,都是在Bean的全部屬性設置成功后執(zhí)行的初始化方法。
8.如果Bean實現(xiàn)了BeanPostProcess接口,Spring將調(diào)用它們的postProcessAfterInitialization(后初始化)方法
(作用與6的一樣,只不過6是在Bean初始化前執(zhí)行的,而這個是在Bean初始化后執(zhí)行的,時機不同 )
9.經(jīng)過以上的工作后,Bean準備就緒,將一直駐留在應用上下文中給應用使用,直到應用上下文被銷毀.
?
當Bean不再需要時,會經(jīng)過清理階段。
10.如果Bean實現(xiàn)了DispostbleBean接口,Spring將調(diào)用它的destory方法,
11.如果在配置文件中對Bean使用destory-method屬性,作用跟10是都一樣,都是在Bean實例銷毀前執(zhí)行的方法。
1. 實例化Bean
對于BeanFactory容器,當客戶向容器請求一個尚未初始化的bean時,或初始化bean的時候需要注入另一個尚未初始化的依賴時,容器就會調(diào)用createBean進行實例化。
對于ApplicationContext容器,當容器啟動結束后,便實例化所有的bean。
容器通過獲取BeanDefinition對象中的信息進行實例化。并且這一步僅僅是簡單的實例化,并未進行依賴注入。
實例化對象被包裝在BeanWrapper對象中,BeanWrapper提供了設置對象屬性的接口,從而避免了使用反射機制設置屬性。
2. 設置對象屬性(依賴注入)
實例化后的對象被封裝在BeanWrapper對象中,并且此時對象仍然是一個原生的狀態(tài),并沒有進行依賴注入。
緊接著,Spring根據(jù)BeanDefinition中的信息進行依賴注入。
并且通過BeanWrapper提供的設置屬性的接口完成依賴注入。
3. 注入Aware接口
緊接著,Spring會檢測該對象是否實現(xiàn)了xxxAware接口,并將相關的xxxAware實例注入給bean。(自動裝配過程)
4. BeanPostProcessor
當經(jīng)過上述幾個步驟后,bean對象已經(jīng)被正確構造,但如果你想要對象被使用前再進行一些自定義的處理,就可以通過BeanPostProcessor接口實現(xiàn)。
該接口提供了兩個函數(shù):
- postProcessBeforeInitialzation( Object bean, String beanName )
當前正在初始化的bean對象會被傳遞進來,我們就可以對這個bean作任何處理。
這個函數(shù)會先于InitialzationBean執(zhí)行,因此稱為前置處理。
所有Aware接口的注入就是在這一步完成的。 - postProcessAfterInitialzation( Object bean, String beanName )
當前正在初始化的bean對象會被傳遞進來,我們就可以對這個bean作任何處理。
這個函數(shù)會在InitialzationBean完成后執(zhí)行,因此稱為后置處理。
5. InitializingBean與init-method
當BeanPostProcessor的前置處理完成后就會進入本階段。
InitializingBean接口只有一個函數(shù):
- afterPropertiesSet()//項目中用到這個。則在注冊bean時,同時執(zhí)行
這一階段也可以在bean正式構造完成前增加我們自定義的邏輯,但它與前置處理不同,由于該函數(shù)并不會把當前bean對象傳進來,因此在這一步?jīng)]辦法處理對象本身,只能增加一些額外的邏輯。
若要使用它,我們需要讓bean實現(xiàn)該接口,并把要增加的邏輯寫在該函數(shù)中。然后Spring會在前置處理完成后檢測當前bean是否實現(xiàn)了該接口,并執(zhí)行afterPropertiesSet函數(shù)。
當然,Spring為了降低對客戶代碼的侵入性,給bean的配置提供了init-method屬性,該屬性指定了在這一階段需要執(zhí)行的函數(shù)名。Spring便會在初始化階段執(zhí)行我們設置的函數(shù)。init-method本質(zhì)上仍然使用了InitializingBean接口(執(zhí)行的初始化方法)。
6. DisposableBean和destroy-method
和init-method一樣,通過給destroy-method指定函數(shù),就可以在bean銷毀前執(zhí)行指定的邏輯。
Spring的單例實現(xiàn)
下面我們來看看Spring中的單例實現(xiàn),當我們試圖從Spring容器中取得某個類的實例時,默認情況下,Spring會才用單例模式進行創(chuàng)建。
| <bean id="date" class="java.util.Date"/> |
| <bean id="date" class="java.util.Date"?scope="singleton"/> (僅為Spring2.0支持) |
| <bean id="date" class="java.util.Date"?singleton="true"/> |
以上三種創(chuàng)建對象的方式是完全相同的,容器都會向客戶返回Date類的單例引用。那么如果我不想使用默認的單例模式,每次請求我都希望獲得一個新的對象怎么辦呢?很簡單,將scope屬性值設置為prototype(原型)就可以了
| <bean id="date" class="java.util.Date"?scope="prototype"/> |
通過以上配置信息,Spring就會每次給客戶端返回一個新的對象實例。
那么Spring對單例的底層實現(xiàn),到底是餓漢式單例還是懶漢式單例呢?
Spring框架對單例的支持是采用單例注冊表的方式進行實現(xiàn)的,源碼如下:
1.? public?abstract?class?AbstractBeanFactory?implements?ConfigurableBeanFactory{????
2.? ???/**??
3.? ????*?充當了Bean實例的緩存,實現(xiàn)方式和單例注冊表相同??
4.? ????*/????
5.? ???private?final?Map?singletonCache=new?HashMap();????
6.? ???public?Object?getBean(String?name)throws?BeansException{????
7.? ???????return?getBean(name,null,null);????
8.? ???}????
9.? ...????
10. ???public?Object?getBean(String?name,Class?requiredType,Object[]?args)throws?BeansException{????
11. ??????//對傳入的Bean?name稍做處理,防止傳入的Bean?name名有非法字符(或則做轉(zhuǎn)碼)????
12. ??????String?beanName=transformedBeanName(name);????
13. ??????Object?bean=null;????
14. ??????//手工檢測單例注冊表????
15. ??????Object?sharedInstance=null;????
16. ??????//使用了代碼鎖定同步塊,原理和同步方法相似,但是這種寫法效率更高????
17. ??????synchronized(this.singletonCache){????
18. ?????????sharedInstance=this.singletonCache.get(beanName);????
19. ???????}????
20. ??????if(sharedInstance!=null){????
21. ?????????...????
22. ?????????//返回合適的緩存Bean實例????
23. ?????????bean=getObjectForSharedInstance(name,sharedInstance);????
24. ??????}else{????
25. ????????...????
26. ????????//取得Bean的定義????
27. ????????RootBeanDefinition?mergedBeanDefinition=getMergedBeanDefinition(beanName,false);????
28. ?????????...????
29. ????????//根據(jù)Bean定義判斷,此判斷依據(jù)通常來自于組件配置文件的單例屬性開關????
30. ????????//<bean?id="date"?class="java.util.Date"?scope="singleton"/>????
31. ????????//如果是單例,做如下處理????
32. ????????if(mergedBeanDefinition.isSingleton()){????
33. ???????????synchronized(this.singletonCache){????
34. ????????????//再次檢測單例注冊表????
35. ?????????????sharedInstance=this.singletonCache.get(beanName);????
36. ?????????????if(sharedInstance==null){????
37. ????????????????...????
38. ???????????????try?{????
39. ??????????????????//真正創(chuàng)建Bean實例????
40. ??????????????????sharedInstance=createBean(beanName,mergedBeanDefinition,args);????
41. ??????????????????//向單例注冊表注冊Bean實例????
42. ???????????????????addSingleton(beanName,sharedInstance);????
43. ???????????????}catch?(Exception?ex)?{????
44. ??????????????????...????
45. ???????????????}finally{????
46. ??????????????????...????
47. ??????????????}????
48. ?????????????}????
49. ???????????}????
50. ??????????bean=getObjectForSharedInstance(name,sharedInstance);????
51. ????????}????
52. ???????//如果是非單例,即prototpye,每次都要新創(chuàng)建一個Bean實例????
53. ???????//<bean?id="date"?class="java.util.Date"?scope="prototype"/>????
54. ???????else{????
55. ??????????bean=createBean(beanName,mergedBeanDefinition,args);????
56. ???????}????
57. }????
58. ...????
59. ???return?bean;????
60. }????
61. }?????
剛才的源碼中,大家真正要記住的是Spring對bean實例的創(chuàng)建是采用單例注冊表的方式進行實現(xiàn)的,而這個注冊表的緩存是HashMap對象,如果配置文件中的配置信息不要求使用單例,Spring會采用新建實例的方式返回對象實例.
后面一段是判定是否為socpe為singleton,是的話執(zhí)行單例模式的過程,只創(chuàng)建一個新的對象,否的話則可以創(chuàng)建多個對象。
?
總結
以上是生活随笔為你收集整理的框架:spring总结的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: struts2框架入门
- 下一篇: JAVA多线程:线程创建过程以及生命周期