面試官:你了解spring嗎?spring的兩大核心是什麼?

2020-12-14 java夢之旅

1. IOC(DI) - 控制反轉(依賴注入)

所謂的IOC稱之為控制反轉,簡單來說就是將對象的創建的權利及對象的生命周期的管理過程交由Spring框架來處理,從此在開發過程中不再需要關注對象的創建和生命周期的管理,而是在需要時由Spring框架提供,這個由spring框架管理對象創建和生命周期的機制稱之為控制反轉。而在 創建對象的過程中Spring可以依據配置對對象的屬性進行設置,這個過程之為依賴注入,也即DI。

2. IOC的入門案例

a. 創建一個java項目

spring並不是非要在javaweb環境下才可以使用,一個普通的java程序中也可以使用Spring。

b. 導入Spring的libs目錄下IOC相關的jar包

c. 創建Spring的配置文件

Spring採用xml文件作為配置文件,xml文件名字任意,但通常都取名為applicationContext.xml,通常將該文件放置在類加載的目錄裡下(src目錄),方便後續使用。

<?xml version="1.0" encoding="UTF-8"?><beansxmlns="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"></beans>

d. 創建bean類,並在spring中進行配置交由spring來管理

1 <?xml version="1.0" encoding="UTF-8"?> 2 <beansxmlns="http://www.springframework.org/schema/beans"3xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"4xsi:schemaLocation="http://www.springframework.org/schema/beans 5 http://www.springframework.org/schema/beans/spring-beans-3.2.xsd"> 6 7 <beanid="person"class="cn.tedu.beans.Person"></bean> 8 9 </beans>

e. 在程序中通過Spring容器獲取對象並使用

/*** SpringIOC方式創建並管理bean */ @Testpublicvoidtest02(){//1.初始化Spring容器 ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); //2.通過Spring容器獲取bean Person p = (Person) context.getBean("person"); p.eat(); p.say(); //3.關閉Spring容器 ((ClassPathXmlApplicationContext)context).close(); }

3. IOC的實現原理

在初始化一個Spring容器時,Spring會去解析指定的xml文件,當解析到其中的<bean>標籤時,會根據該標籤中的class屬性指定的類的全路徑名,通過反射創建該類的對象,並將該對象存入內置的Map中管理。其中鍵就是該標籤的id值,值就是該對象。

之後,當通過getBean方法來從容器中獲取對象時,其實就是根據傳入的條件在內置的Map中尋找是否有匹配的鍵值,如果有則將該鍵值對中保存的對象返回,如果沒有匹配到則拋出異常。

由此可以推測而知:

默認情況下,多次獲取同一個id的bean,得到的將是同一個對象。

不可以配置多個id相同的bean

可以配置多個id不同但class相同的bean

4. IOC獲取對象的方式

通過context.getBean()方法獲取bean時,可以通過如下兩種方式獲取:

傳入id值

傳入class類型

通過class方式獲取bean時,如果同一個類配置過多個bean,則在獲取時因為無法確定到底要獲取哪個bean會拋出異常。

而id是唯一的,不存在這樣的問題,所以建議大家儘量使用id獲取bean。

/*** 獲取對象的方式 * 通過id獲取bean * 如果找不到,拋異常NoSuchBeanDefinitionException * 如果找到唯一的,返回對象 * 因為id不重複,不可能找到多個 * 通過class獲取bean * 如果找不到,拋出異常NoSuchBeanDefinitionException * 如果找到唯一,返回對象 * 如果找到多個,拋出異常NoUniqueBeanDefinitionException */ @Testpublicvoidtest04(){ ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");//獲取對象方式1:通過id獲取 //Person p = (Person)context.getBean("person"); //p.eat(); //p.say(); //獲取對象方式2:通過class獲取 Person p = context.getBean(Person.class); p.eat(); p.say(); ((ClassPathXmlApplicationContext)context).close(); }

SpringIOC在通過class獲取bean時,如果找不到該類型的bean還會去檢查是否存在該類型的子孫類型的bean,如果有則返回,如果找不到或找到多個則拋出異常。這符合java面向對象思想中的多態的特性。

@Test public void test02() {//1.初始化spring容器 ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");//2.獲取Bean JavaTeacher jt = (JavaTeacher) context.getBean(Teacher.class); System.out.println(jt); }

5. 別名標籤

在 Spring中提供了別名標籤<alias>可以為配置的<bean>起一個別名,要注意的是這僅僅是對指定的<bean>起的一個額外的名字,並不會額外的創建對象存入map。

<alias name="要起別名的bean的id" alias="要指定的別名"/>/** * 別名標籤 * 可以通過別名標籤為bean的id起一個別名,此後除了可以通過別名指代id * <alias name="person"alias="pers"></alias> */ @Test public void test05(){ ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");//Person p = (Person) context.getBean("person"); Person p = (Person) context.getBean("pers"); System.out.println(p); ((ClassPathXmlApplicationContext)context).close(); }

6. Spring創建對象的方式

a. 通過類的無法構造方法創建對象

在入門案例中使用的就是這種方式。

當用最普通方式配置一個<bean>時,默認就是採用類的無參構造創建對象。

在Spring容器初始化時,通過<bean>上配置的class屬性反射得到字節碼對象,通過newInstance()創建對象

1 Class c = Class .forName("類的全路徑名稱")

2 Object obj = c.newInstance()

這種方式下spring創建對象,要求類必須有無參的構造,否則無法通過反射創建對象,會拋出異常。

publicclassPerson {publicPerson(){System.out.println("Person被創建了.."); } }/** * SpringIOC創建對象方式1 - 反射創建對象 * bean必須有無參構造才可以 */ @Testpublicvoidtest01() throws Exception { ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); Person p = (Person) context.getBean("person"); System.out.println(p); ((ClassPathXmlApplicationContext)context).close(); }

b. 通過靜態工廠創建對象

很多的時候,我們面對的類是無法通過無參構造去創建的,例如該類沒有無參構造、是一抽象類 等等情況 ,此時無法要求spring通過無參構造創建對象,此時可以使用靜態工廠 方式創建對象。

publicclassPerson{publicPerson(String name){System.out.println("Person被創建了.."); } }/** * 靜態工廠 */publicclassPersonStaticFactory {privatePersonStaticFactory(){}publicstatic Person getInstance(){returnnew Person("zs"); } } <bean id="person"class="cn.tedu.factory.PersonStaticFactory" factory-method="getInstance"></bean> @Testpublicvoidtest02(){ ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); Person p = (Person) context.getBean("person"); System.out.println(p); ((ClassPathXmlApplicationContext)context).close(); }

c. 實例工廠創建對象

實例工廠也可以解決類是無法通過無參構造創建的問題,解決的思路和靜態工廠類似,只不過實例工廠提供的方法不是靜態的。

spring需要先創建出實例工廠的對象,在調用實例工廠對象上指定的普通方法來創建對象。所以實例工廠也需要配置到Spring中管理。

publicclassPerson{public Person(String name){System.out.println("Person被創建了.."); } }/** * 實例工廠 */publicclassPersonInstanceFactory{public Person getInstance(){return new Person("ls"); } } <beanid="personInstanceFactory"class="cn.tedu.factory.PersonInstanceFactory"></bean> <beanid="person"factory-bean="personInstanceFactory"factory-method="getInstance"></bean>@Testpublicvoidtest03(){ ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); Person p = (Person) context.getBean("person"); System.out.println(p); ((ClassPathXmlApplicationContext)context).close(); }

d. Spring工廠創建對象 Spring內置了工廠接口,也可以通過實現這個接口來開發Spring工廠,通過這個工廠創建對象。

publicclassPerson{public Person(String name){System.out.println("Person被創建了.."); } }package cn.tedu.factory;import cn.tedu.domain.Person;import org.springframework.beans.factory.FactoryBean;/** * Spring工廠 */publicclassPersonSpringFactoryimplementsFactoryBean<Person> {/** * 生產bean對象方法 */@Overridepublic Person getObject() throws Exception {return new Person("ww"); }/** * 獲取bean類型方法 */@Overridepublic Class<?> getObjectType() {return Person.class; } /** * 告知當前bean是否要採用單例模式 */@OverridepublicbooleanisSingleton() {returntrue; } } <bean id="person"class="cn.tedu.factory.PersonSpringFactory"></bean>@Testpublicvoidtest04(){ ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); Person p = (Person) context.getBean("person"); System.out.println(p); ((ClassPathXmlApplicationContext)context).close(); }

7. 單例和多例

Spring容器管理的bean在默認情況下是單例的,也即,一個bean只會創建一個對象,存在內置 map中,之後無論獲取多少次該bean,都返回同一個對象。

Spring默認採用單例方式,減少了對象的創建,從而減少了內存的消耗。

但是在實際開發中是存在多例的需求的,Spring也提供了選項可以將bean設置為多例模式。

1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xsi:schemaLocation="http://www.springframework.org/schema/beans 5 http://www.springframework.org/schema/beans/spring-beans-3.2.xsd"> 6 7 <!-- 8 scope屬性控制當前bean的創建模式: 9 singleton:則當前bean處在單例模式中,默認就是此模式 10 prototype:則當前bean處在多例模式中 11 --> 12 <bean id="cart" scope="prototype"></bean> 13 14 </beans>

bean在單例模式下的生命周期:

bean在單例模式下,spring容器啟動時解析xml發現該bean標籤後,直接創建該bean的對象存入內部map中保存,此後無論調用多少次getBean()獲取該bean都是從map中獲取該對象返回,一直是一個對象。此對象一直被Spring容器持有,直到容器退出時,隨著容器的退出對象被銷毀。

bean在多例模式下的生命周期:

bean在多例模式下,spring容器啟動時解析xml發現該bean標籤後,只是將該bean進行管理,並不會創建對象,此後每次使用 getBean()獲取該bean時,spring都會重新創建該對象返回,每次都是一個新的對象。這個對象spring容器並不會持有,什麼銷毀取決於使用該對象的用戶自己什麼時候銷毀該對象。

8. 懶加載機制

Spring默認會在容器初始化的過程中,解析xml,並將單例的bean創建並保存到map中,這樣的機制在bean比較少時問題不大,但一旦bean非常多時,spring需要在啟動的過程中花費大量的時間來創建bean 花費大量的空間存儲bean,但這些bean可能很久都用不上,這種在啟動時在時間和空間上的浪費顯得非常的不值得。

所以Spring提供了懶加載機制。所謂的懶加載機制就是可以規定指定的bean不在啟動時立即創建,而是在後續第一次用到時才創建,從而減輕在啟動過程中對時間和內存的消耗。

懶加載機制只對單例bean有作用,對於多例bean設置懶加載沒有意義。

懶加載的配置方式:

為指定bean配置懶加載

1 <?xml version="1.0" encoding="UTF-8"?> 2 <beansxmlns="http://www.springframework.org/schema/beans"3xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"4xsi:schemaLocation="http://www.springframework.org/schema/beans 5 http://www.springframework.org/schema/beans/spring-beans-3.2.xsd"6 > 7 8 <beanid="cart"class="cn.tedu.beans.Cart"lazy-init="true"></bean> 9 10 </beans>

為全局配置懶加載

1 <?xml version="1.0" encoding="UTF-8"?> 2 <beansxmlns="http://www.springframework.org/schema/beans"3xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"4xsi:schemaLocation="http://www.springframework.org/schema/beans 5 http://www.springframework.org/schema/beans/spring-beans-3.2.xsd"6default-lazy-init="true"7 > 8 9 <beanid="cart"class="cn.tedu.beans.Cart"></bean> 10 11 </beans>

如果同時設定全局和指定bean的懶加載機制,且配置不相同,則對於該bean局部配置覆蓋全局配置。

實驗:通過斷點調試,驗證懶加載機制的執行過程

1packagecn.tedu.beans;23publicclassCart{4publicCart(){5System.out.println("Cartinit...");6}7}1<?xmlversion="1.0"encoding="UTF-8"?>2<beansxmlns="http://www.springframework.org/schema/beans"3xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"4xsi:schemaLocation="http://www.springframework.org/schema/beans5http://www.springframework.org/schema/beans/spring-beans-3.2.xsd"6>78<beanid="cart"class="cn.tedu.beans.Cart"lazy-init="true"></bean>910</beans>1@Test2/**3*SpringIOC懶加載機制4*/5publicvoidtest10(){6ApplicationContextcontext=newClassPathXmlApplicationContext("applicationContext.xml");7Cartcart1=(Cart)context.getBean("cart");8Cartcart2=(Cart)context.getBean("cart");9System.out.println(cart1==cart2);10}

9. 配置初始化和銷毀的方法

在Spring中如果某個bean在初始化之後 或 銷毀之前要做一些 額外操作可以為該bean配置初始化和銷毀的方法 ,在這些方法中完成要功能。

實驗:通過斷點調試模式,測試初始化方法 和 銷毀方法的執行

1 package cn.tedu.beans;23publicclassProdDao {45publicProdDao() {6 System.out.println("ProdDao 被創建。。。");7 }89publicvoidinit(){10 System.out.println("init。。連接資料庫。。。。。");11 }121314publicvoiddestory(){15 System.out.println("destory。。斷開資料庫。。。。。");16 }1718publicvoidaddProd(){19 System.out.println("增加商品。。");20 }21publicvoidupdateProd(){22 System.out.println("修改商品。。");23 }24publicvoiddelProd(){25 System.out.println("刪除商品。。");26 }27publicvoidqueryProd(){28 System.out.println("查詢商品。。");29 }30 }1 <?xml version="1.0" encoding="UTF-8"?>2 <beans xmlns="http://www.springframework.org/schema/beans"3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"4 xsi:schemaLocation="http://www.springframework.org/schema/beans 5 http://www.springframework.org/schema/beans/spring-beans-3.2.xsd"6 >78 <bean id="prodDao"class="cn.tedu.beans.ProdDao"9 init-method="init" destroy-method="destory"></bean>1011 </beans>1 @Test2/** 3 * SpringIOC 初始化和 銷毀方法 4 */5publicvoidtest11(){6 ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");7 ProdDao prodDao = (ProdDao) context.getBean("prodDao");8 prodDao.addProd();9 context.close();10 }

Spring中關鍵方法的執行順序:

在Spring創建bean對象時,先創建對象(通過無參構造或工廠),之後立即調用init方法來執行初始化操作,之後此bean就可以拿來調用其它普通方法,而在對象銷毀之前,spring容器調用其destory方法來執行銷毀操作。

#Java#

相關焦點

  • Java經典面試題Spring是什麼 Spring框架入門詳解
    SpringLOGOSpring是什麼,談談你對Spring的理解。這是初級開發人員必然被問道的問題,如果你不懂Spring你就無法從事這一行業,此處僅限技術人員,公司的繼承人等其他個例不受此限制。以上的就是Spring被外行廣為流傳的,傳說中的IOC的使用,什麼是IOC中文意思就是控制反轉,什麼意思?我們平時創建對象需要自己手動創建,現在對象都是通過spring容器ApplicationContext創建,這就是所謂的IOC控制反轉,如果有了解工廠設計模式的朋友會更容易理解,ApplicationContext此處就相當於一個工廠類。
  • 繼「劉強東」之後京東的第二位程式設計師「呂科」spring面試題講解
    京東IT資源服務部的負責人-呂科作為京東集團IT資源服務部的負責人,呂科打造了一支聚集了國際型優秀人才充滿激情的「鐵軍」,今年,京東發布最新的面試分為四個面試部分,相信大部分程式設計師對此是了解的,但是具體面試內容是什麼,2020年7月1日,京東的第二位程式設計師「呂科」講解最新面試信息:一面:也就是基礎面試二面:資料庫基礎面試三面:綜合面試四面:HR面試今天講解的是京東spring
  • 面試刷題:Spring Bean的生命周期?
    spring是Java軟體開發的事實標準。今天的問題是:springBean的生命周期是怎樣的?答:spring最基礎的能力是IOC(依賴注入),AOP(面向切面編程),ioc改善了模塊之間的耦合問題,依賴注入的方式:set方法,構造方法,成員變量+ @Autowire ;Bean的管理是IOC的主要功能。
  • spring+微服務+jvm+性能調優,前美團架構師直接跪了!這就很nice
    上半年過去了,聽得最多的就是:Java 面試太TM難了。僧多粥少基本是現在 Java 人面臨的最大難題,去稍大一點的公司面試,競爭對手至少幾十人。想從人群中脫穎而出,有些時候靠的未必是技術能力。因為大家的能力,其實都差不多(除去大神級別的 Java 程式設計師)。
  • 學渣,你真的知道spring的意思嗎?
    今天以春天spring這個單詞為例,讓你了解一點英語的演變規則。Spring作為春天的意思,我們小學的時候就有學過,這不足為奇。下面我們由作為春天的意思去推理出spring其他的意思。1.Spring泉水、小溪我們知道,春天到了,雨水會增多,那麼山上的樹木、土壤就會變的溼潤,越積越多,最後從山腳下滲出來,滲出來的水就叫泉水,所以,spring衍生出泉水的意思。泉水匯聚到溝渠裡,慢慢的形成了小溪,所以,spring衍生出小溪的意思。
  • Spring面試題:SpringBoot開發自定義starter
    SpringBoot開發自定義starter什麼是starterStarter可以理解為一個可拔插式的插件,提供一系列便利的依賴描述符,您可以獲得所需的所有Spring boot的AutoConfiguration機制標記一個應用為Springboot應用,需要一個SpringBootApplication註解,下面是一個標準的spring boot啟動程序。
  • 一分鐘說英語:英語Spring是什麼意思?
    一分鐘說英語:英語Spring是什麼意思?我知道你一開口就「說」錯了,因為你「說」肯定是中文「春天」了。這不叫「說英語」。見到英語spring你要「說」的還是英語:Well,spring is the first season of the year.見到英語spring時,把你學過的英語the first season of the year用起來,既複習舊英語,又練習英語口語。不要「說」中文:春天。同樣:1.
  • springcloud五大組件
    首先我們來看springcloud是什麼?它是微服務架構集大成者,基於springboot構建,可以將一系列優秀組件進行完美整合。對熟悉的程式設計師來說,上手不麻煩,對新手來說,就需要了解springcloud架構再去學習。
  • 初識Spring Cloud Stream,什麼是消息驅動微服務框架
    它為一些供應商的消息中間件產品提供了個性化的自動化配置實現,並且引入了發布-訂閱、消費組以及分區這三個核心概念。Spirng Cloud Stream 本質上就是整合了 Spring Boot 和 Spring Integration,實現一套輕量級的消息驅動的微服務框架。
  • spring框架之註解的使用
    感謝你的觀看,謝謝你。學習內容安排如下:Spring註解的使用。JavaWeb項目的搭建。Spring的Web集成。其實無論是spring註解也好,還是配置xml也罷,都是省略new對象這個步驟。將dao層和service層對象關聯起來了,沒有new對象實例化,也能調用dao層代碼。當然spring肯定不止這麼簡單,只不過目前來說還沒有學到其它的知識點。
  • springboot+springsecurity實現前後端分離簡單實現!
    那就用國內的gitee吧,gitee上的開源項目都是結合實戰項目的,代碼邏輯也比較複雜,我對項目的業務邏輯沒什麼了解,感覺不適合我。我這一次選擇比較反人性的方式去學習,就是手撕源碼和看官方文檔。老實講,剛開始看源碼和官方文檔特別難受,並且看不進去,那些springsecurity的類還有接口名字又臭又長,這時我就下載源碼,源碼的注釋多的就像一本書,非常詳細且權威。
  • 阿里面試總結:69道必問的spring面試題(附加答案)
    什麼是spring?2. 使用Spring框架的好處是什麼?3. Spring由哪些模塊組成?4. 核心容器(應用上下文) 模塊。5. BeanFactory – BeanFactory 實現舉例。一個Spring的應用看起來象什麼?18. 什麼是Spring的依賴注入?19. 有哪些不同類型的IOC(依賴注入)方式?20. 哪種依賴注入方式你建議使用,構造器注入,還是 Setter方法注入?21.什麼是Spring beans?
  • 深入淺出Spring 5,使用Spring 5的反應式WebSocket
    Maven依賴我們將使用開箱即用的spring-boot-starters依賴項來進行spring-boot-integration和spring-boot-starter-webflux(目前可在Spring Milestone Repository中獲得)。
  • Spring Boot與Shiro整合實現用戶認證
    分析Shiro的核心APISubject: 用戶主體(把操作交給SecurityManager)SecurityManager:安全管理器(關聯Realm)Realm:Shiro連接數據的橋梁1.2.導入shiro與spring整合依賴修改pom.xml<!
  • 什麼是Spring Cloud項目,我把它講清楚了
    01微服務講起springcloud之前,我們需要了解一下什麼是微服務。其實就是給你用的,基本部署到一個雲伺服器。沒有任何的實用,企業的客戶會越來越多, 流量越來越大, 單單一臺伺服器對外提供服務, 哪裡撐得住啊, 不分分鐘被搞掛掉才怪。遇到並發和大流量,基本就Over了。
  • 春暖花開時,春天的英文表達不能只知道spring
    spring春天的英文表達,作名詞,意為"春天""春季"。經典的名言:If winter comes, can spring be far behind? "冬天來了,春天還會遠嗎?"除了表達春天,spring 還可以用來表達"泉;泉水 "。如hot spring溫泉。與春天相關的英文詞彙一說到春天,除了spring這一英文表達,還會想到很多詞彙,如萬物復甦、溫暖、花兒盛開、微風徐徐、綠色、希望等。
  • Spring集成RabbitMQ簡單實現RPC
    /tx"xmlns:aop="http://www.springframework.org/schema/aop" xmlns:p="http://www.springframework.org/schema/p"xmlns:context="http://www.springframework.org/schema/context
  • 使用Spring 框架的好處
    Spring 框架的主要優點具體如下:1.方便解耦,便於開發,spring支持aop編程,Spring就是一個大工廠,可以將所有對象的創建和依賴關係維護都交給spring管理,Spring 不會讓你白費力氣做重複工作,它真正的利用了一些現有的技術,像ORM 框架、日誌框架、JEE、Quartz 和 JDK 計時器,其他視圖技術。
  • 從零搭建 Spring Cloud 服務(超詳細)
    直接看第二章不會有什麼影響,可以先學會開車再學習車的構造的,看個人習慣來。1.什麼是SpringCloud?出來之後 選擇quickstart ->下一步名字自己想 想好後,複製一下你想好的 ArtifactId點擊Next,groupId為組織名 也是自己想一個,一般為公司網址反寫。
  • Spring Boot 啟動事件和監聽器,太強大了!
    大家都知道,在 Spring 框架中事件和監聽無處不在,打通了 Spring 框架的任督二脈,事件和監聽也是 Spring 框架必學的核心知識之一。Spring Boot 基礎的構建這裡就不介紹了,如果你對 Spring Boot 還不是很熟悉,或者只是會簡單的使用,那還是建議你深入學習下吧,推薦這個 Spring Boot 學習倉庫,歡迎 Star 關注:https://github.com/javastacks/spring-boot-best-practice1、新建監聽器