常用網(wǎng)站推薦公司優(yōu)化是什么意思?
一、Spring
- IoC(Inversion of Control)中文名稱:控制反轉(zhuǎn)(對(duì)象的創(chuàng)建交給Spring管理)。
- DI(dependency injection )依賴注入。
- 容器(Container):放置所有被管理的對(duì)象。
- beans:容器中所有被管理的對(duì)象稱為beans。
一.Spring IOC
1.?介紹
控制反轉(zhuǎn),對(duì)象的創(chuàng)建交給Spring管理。
2.?Bean實(shí)例化的兩種方式(面試題)
2.1.BeanFactory(spring創(chuàng)建對(duì)象)
通過構(gòu)造方法進(jìn)行實(shí)例化。默認(rèn)使用無參構(gòu)造。
?創(chuàng)建方式:
- <bean> 標(biāo)簽配置。在Spring.xml配置中進(jìn)行bean對(duì)象的創(chuàng)建。
<bean id="peo" class="com.bjsxt.pojo.People"></bean>
- @Component及子注解管理對(duì)象,配合 ComponentScan的掃描。
@Service
public class UserServiceImpl implements UserService{}
<!-- 掃描service中的注解(Component及子注解) --><context:component-scan base-package="com.lyx.service"/>
- @Bean修飾的方法,方法的返回值交由spring管理,方法名為key。
- @Import 指定的類由spring管理。
2.2.FactoryBean(使用自定義的工廠類創(chuàng)建對(duì)象)
分為靜態(tài)工廠和實(shí)例工廠兩種方式。靜態(tài)工廠和實(shí)例工廠類最主要的區(qū)別是,創(chuàng)建bean的方法是static修飾的。
1.自定對(duì)象工廠類。
public class PeopleFactory {People peo = new People();public People getInstance(){return peo;}
}
2.工廠交由spring管理,從工廠方法中獲取對(duì)象交由spring管理。
<!-- 創(chuàng)建工廠實(shí)例 -->
<!-- 工廠bean-->
<bean id="factory" class="com.bjsxt.factory.PeopleFactory"></bean><!--- factory-bean:工廠bean的id屬性值。- factory-method:工廠中創(chuàng)建bean的方法。-->
<bean id="peo2" factory-bean="factory" factory-method="getInstance"></bean><!-- 靜態(tài)工廠的配置 --><bean id="peo3" class="com.bjsxt.factory.PeopleStaticFactory" factory-method="newInstance"></bean>
?2.3.bean標(biāo)簽的scope屬性(面試題)
Spring中
<bean>
的scope控制的是Bean的有效范圍。一共有6個(gè)可取值。
<!--singleton:默認(rèn)值。bean是單例的,每次獲取Bean都是同一個(gè)對(duì)象。prototype:bean時(shí)原型的,每次獲取bean都重新實(shí)例化。request:每次請(qǐng)求重新實(shí)例化對(duì)象,同一個(gè)請(qǐng)求中多次獲取時(shí)單例的。session:每個(gè)會(huì)話內(nèi)bean是單例的。application:整個(gè)應(yīng)用程序?qū)ο髢?nèi)bean是單例的。websocket:同一個(gè)websocket對(duì)象內(nèi)對(duì)象是單例的。
里面的singleton和prototype在Spring最基本的環(huán)境中就可以使用,不需要web環(huán)境。
但是里面的request、session、application、websocket都只有在web環(huán)境才能使用。
-->
<bean id="people" class="com.bjsxt.pojo.People" scope="singleton"></bean>
二.Spring DI(依賴注入)
1.手動(dòng)注入(spring.xml中進(jìn)行配置)
?? 1.構(gòu)造注入(依賴于構(gòu)造方法完成屬性賦值)
<bean id="peo4" class="com.bjsxt.pojo.People"> <constructor-arg type="int" value="1"></constructor-arg> <constructor-arg type="java.lang.String" value="張三"></constructor-arg>
</bean>
? ?2.設(shè)置注入(依賴于set方法完成屬性賦值)
<bean id="peo5" class="com.bjsxt.pojo.People"><property name="id" value="2"></property><property name="name" value="李四"></property>
</bean>
2.自動(dòng)注入(使用注解)
自動(dòng)注入指的都是bean之間的自動(dòng)注入。能夠自動(dòng)注入必須保證Spring 容器中包含能被自動(dòng)注入的bean。
1.兩種方式進(jìn)行配置:
- 在根標(biāo)簽
<beans>
中配置default-autowire屬性?。- 在
<bean>
標(biāo)簽中配置autowire屬性,和default-autowire取值相同。2.屬性取值?
- byName:根據(jù)bean的名字自動(dòng)注入,依賴于set方法。
- byType:通過類的類型自動(dòng)注入。
- constructor:通過構(gòu)造方法進(jìn)行注入。調(diào)用有參構(gòu)造方法完成對(duì)象創(chuàng)建及屬性自動(dòng)注入。
?3.@Autowired注解(自動(dòng)注入)
用在類上的注解,先根據(jù)類型找,類型出現(xiàn)多個(gè),再根據(jù)名字找。
1.特殊用法
- 用在屬性上,使用反射進(jìn)行注入。
- 用在set方法上,使用set方法注入。
- 用在有參構(gòu)造方法上,使用有參構(gòu)造進(jìn)行注入。
?2.特點(diǎn)
? ? 注解所在的bean和注入的bean都為spring容器管理的bean。
@Resouce(非spring注解)?:先根據(jù)名字找,沒有找到,再根據(jù)類型找。
三.單例設(shè)計(jì)模式(面試中筆試題)
只創(chuàng)建一個(gè)對(duì)象的設(shè)計(jì)模式。
1. 餓漢式
/*單例:希望類只有一個(gè)核心思想:1. 構(gòu)造方法私有2. 對(duì)外提供一個(gè)能夠獲取對(duì)象的方法。餓漢式:優(yōu)點(diǎn):實(shí)現(xiàn)簡(jiǎn)單缺點(diǎn):無論是否使用當(dāng)前類對(duì)象,加載類時(shí)一定會(huì)實(shí)例化。*/
public class Singleton {// 之所以叫做餓漢式:因?yàn)轭惣虞d時(shí)就創(chuàng)建了對(duì)象private static Singleton singleton = new Singleton();private Singleton(){}public static Singleton getInstance(){return singleton;}
}
2. 懶漢式
/*** 核心思想:* 1. 構(gòu)造方法私有。* 2. 對(duì)外提供一個(gè)能夠獲取對(duì)象的方法。** 懶漢式優(yōu)點(diǎn)和缺點(diǎn):* 優(yōu)點(diǎn):* 按需創(chuàng)建對(duì)象。不會(huì)在加載類時(shí)直接實(shí)例化對(duì)象。* 缺點(diǎn):* 寫法相對(duì)復(fù)雜。* 多線程環(huán)境下,第一次實(shí)例化對(duì)象效率低。*/
public class Singleton2 {//懶漢式:不會(huì)立即實(shí)例化private static Singleton2 singleton2;private Singleton2() {}public static Singleton2 getInstance() {if (singleton2 == null) {// 不是第一次訪問的線程,直接通過if判斷條件不成立。直接returnsynchronized (Singleton2.class) {if(singleton2==null) {// 防止多個(gè)線程已經(jīng)執(zhí)行到synchronizedsingleton2 = new Singleton2();}}}return singleton2;}
}
四.循環(huán)依賴問題(重要面試題)
1.介紹
循環(huán)注入即多個(gè)類相互依賴,產(chǎn)生了一個(gè)閉環(huán)。
2. 解決循環(huán)依賴 (三級(jí)緩存)
- 一級(jí)緩存(singletonObjects):存放? 實(shí)例化、屬性注入和初始化完成的對(duì)象。
- 二級(jí)緩存(earlySingletonObjects):存放早期暴露出來的Bean對(duì)象,實(shí)例化和屬性注入完成的對(duì)象。
- 三級(jí)緩存(singletonFactories):存放實(shí)例化完成的對(duì)象。存放bean創(chuàng)建工廠,以便于后面擴(kuò)展有機(jī)會(huì)創(chuàng)建代理對(duì)象。
單例模式創(chuàng)建對(duì)象的步驟?:
實(shí)例化:調(diào)用對(duì)象的構(gòu)造方法實(shí)例化對(duì)象。
屬性注入:填充屬性,這一步主要是對(duì)bean的依賴屬性進(jìn)行填充。
初始化:屬性注入后,執(zhí)行自定義初始化操作。
五.BeanFactory和ApplicationContext(經(jīng)典面試題)?
1. BeanFactory接口(懶漢式)
- BeanFactory是Spring中的頂級(jí)接口,接口中定了Spring容器最基本功能。是Spring IoC的最核心接口。
- ApplicationContext的getBean方法其實(shí)就是BeanFactory的方法。
- BeanFactory是在調(diào)用getBean方法的時(shí)候才實(shí)例化Bean。(懶漢式)
BeanFactory最常用實(shí)現(xiàn)類是XmlBeanFactory。但是從Spring 3.1 版本開始,使用DefaultListableBeanFactory和XMLBeanDefinitionReader替代。
?2. ApplicationContext接口(餓漢式)
BeanFactory的子接口。比BeanFactory的功能更加強(qiáng)大,除了BeanFactory的功能,還包含了:
- AOP 功能
- 國(guó)際化(MessageSource)
- 訪問資源,如URL和文件(ResourceLoader)
- 消息發(fā)送機(jī)制(ApplicationEventPublisher)
- Spring集成Web時(shí)的WebApplicationContext
ApplicationContext是在加載配置文件后立即實(shí)例化Bean。(餓漢式)
在使用時(shí)ApplicationContext時(shí)多使用ClassPathXmlApplicationContext。
六.動(dòng)態(tài)代理設(shè)計(jì)模式
動(dòng)態(tài)創(chuàng)建代理對(duì)象。
1.JDk動(dòng)態(tài)代理
JDK動(dòng)態(tài)代理是基于接口。先創(chuàng)建接口,然后創(chuàng)建被代理對(duì)象類。
//JDK動(dòng)態(tài)代理/*功能:JDK動(dòng)態(tài)代理為類創(chuàng)建代理對(duì)象,實(shí)現(xiàn)目標(biāo)對(duì)象功能的增強(qiáng)JDK動(dòng)態(tài)代理為接口創(chuàng)建實(shí)現(xiàn)類*//*Proxy.newProxyInstance中的參數(shù) 參數(shù)一:類加載參數(shù)二:接口的類對(duì)象(JDK動(dòng)態(tài)代理基于接口實(shí)現(xiàn))參數(shù)三:運(yùn)行時(shí)底層實(shí)現(xiàn)select()方法【該過程看不到】,實(shí)現(xiàn)的方法中調(diào)用了 invoke()*/@Testpublic void test01() {//創(chuàng)建被代理對(duì)象UserServicesImpl userServicesImpl = new UserServicesImpl();UserService userService = (UserService) Proxy.newProxyInstance(Test2.class.getClassLoader(),//UserServicesImpl.class.getInterfaces(),//必須為接口的類對(duì)象new InvocationHandler() {//@Override/*invoke方法中的參數(shù):參數(shù)一:代理對(duì)象參數(shù)二:目標(biāo)方法(被代理方法)參數(shù)三:目標(biāo)方法參數(shù)* */public Object invoke(Object o, Method method, Object[] objects) throws Throwable {Object invoke = method.invoke(userServicesImpl, objects);return invoke;}});//代理對(duì)象調(diào)用方法userService.select();}
2.Cglib動(dòng)態(tài)代理?
Cglig動(dòng)態(tài)是第三方提供的技術(shù),需要導(dǎo)入jar包,并且可以是基于類繼承,也可以是基于接口實(shí)現(xiàn)。
使用:先創(chuàng)建接口或類,然后創(chuàng)建被代理的對(duì)象類(繼承或?qū)崿F(xiàn))。
<dependency><groupId>cglib</groupId><artifactId>cglib</artifactId><version>3.3.0</version>
</dependency>
@Test//2.為類創(chuàng)建代理對(duì)象,實(shí)現(xiàn)目標(biāo)方法的功能增強(qiáng)(基于接口實(shí)現(xiàn))public void test04(){//創(chuàng)建目標(biāo)對(duì)象(被代理對(duì)象)UserServicesImpl userServicesImpl = new UserServicesImpl();Enhancer enhancer = new Enhancer();enhancer.setInterfaces(UserServicesImpl.class.getInterfaces());enhancer.setCallback(new MethodInterceptor() {@Overridepublic Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {System.out.println("前置 增強(qiáng)");//調(diào)用 目標(biāo)方法Object invoke = method.invoke(userServicesImpl, objects);System.out.println("后置 增強(qiáng)");return invoke;}});//獲取代理對(duì)象并調(diào)用方法UserService userService = (UserService) enhancer.create();userService.select();}@Test// 3.為類創(chuàng)建代理對(duì)象,實(shí)現(xiàn)目標(biāo)方法的功能增強(qiáng)(基于繼承實(shí)現(xiàn))public void test05(){Enhancer enhancer = new Enhancer();//增強(qiáng)器enhancer.setSuperclass(Aaa.class);enhancer.setCallback(new MethodInterceptor() {@Overridepublic Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {System.out.println("前置 增強(qiáng)");Object invoke = methodProxy.invokeSuper(o, objects);System.out.println("后置 增強(qiáng)");return invoke;}});//獲取代理對(duì)象調(diào)用方法UserServicesImpl2 userServices = (UserServicesImpl2) enhancer.create();userServices.querry(1,2);}
}
3.總結(jié)
JDK動(dòng)態(tài)代理機(jī)制是委托機(jī)制,只能對(duì)實(shí)現(xiàn)了接口的類生成代理,底層通過反射機(jī)制實(shí)現(xiàn)。(重點(diǎn))
CGLIB動(dòng)態(tài)代理機(jī)制是接口或繼承機(jī)制,針對(duì)類生成代理,被代理類和代理類是繼承關(guān)系,底層通過字節(jié)碼處理框架asm,修改字節(jié)碼生成子類
七.AOP?
?1. SpringAOP介紹(常見面試題)
面向切面編程是對(duì)面向?qū)ο缶幊痰难a(bǔ)充。?AOP 中模塊化的單位是切面。
AOP中的專業(yè)術(shù)語(yǔ):
Aspect:? ? ? 切面。為方法添加增強(qiáng)功能的過程。
join point:? ?切入點(diǎn)。就是被代理的方法,也叫目標(biāo)方法。
Advice:? ? ? 通知。就是增強(qiáng)內(nèi)容。前置、后置、環(huán)繞、異常等通知。
Pointcut:? ? 切點(diǎn)。就是表達(dá)式,通過切點(diǎn)表達(dá)式可以找到目標(biāo)方法(join point)。
Weaving:? ? 織入??椚刖褪前?通知 添加到 切入點(diǎn) 的過程。
AOP Proxy:代理。Spring支持JDK動(dòng)態(tài)代理和cglib動(dòng)態(tài)代理兩種方式,可以通過proxy-? ? ? ? ? ? ? ? ? ? ? ? ? ? ? target-?class=true把默認(rèn)的JDK動(dòng)態(tài)代理修改為Cglib動(dòng)態(tài)代理。
2. 實(shí)現(xiàn)AOP的兩種方式
1.實(shí)現(xiàn)AOP需要引入依賴:
<!--支持切點(diǎn)表達(dá)式等-->
<dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.9.9.1</version>
</dependency>
<dependency><groupId>aopalliance</groupId><artifactId>aopalliance</artifactId><version>1.0</version>
</dependency>
2.實(shí)現(xiàn)AOP的兩種方式:?
-
Schema-based:所有的通知都需要實(shí)現(xiàn)特定類型的接口實(shí)現(xiàn)通知。
在Schema-based方式中通知的分類(面試題):
- 前置通知,通知需要實(shí)現(xiàn)MethodBeforeAdvice接口。
- 后置通知,通知需要實(shí)現(xiàn)AfterReturningAdvice接口。
- 環(huán)繞通知,通知需要實(shí)現(xiàn)MethodInterceptor接口。
- 異常通知,通知需要實(shí)現(xiàn)ThrowsAdvice接口。
<!-- 配置異常通知對(duì)象 --><bean id="mythrow" class="com.bjsxt.advice.MyThrow"/><aop:config><aop:pointcut id="mypoint" expression="execution(* com.bjsxt.service.impl.PeopleServiceImpl.test())"/><!-- 織入異常通知 --><aop:advisor advice-ref="mythrow" pointcut-ref="mypoint"/></aop:config>
</beans>
-
AspectJ:可以使用普通Java類結(jié)合特定的配置實(shí)現(xiàn)通知。
在AspectJ方式中通知的分類(面試題):
前置通知:before。
后置通知:after。
after是否出現(xiàn)異常都執(zhí)行的后置通知。
after-returning切入點(diǎn)不出現(xiàn)異常時(shí)才執(zhí)行的后置通知。
環(huán)繞通知:around。
異常通知:after-throwing。
<!-- 配置通知對(duì)象 --><bean id="myadvice2" class="com.bjsxt.advice.MyAdvice2"></bean><aop:config><!-- 基于Aspectj方式配置 --><aop:aspect ref="myadvice2"><!--切點(diǎn)配置args():編寫參數(shù)名,參數(shù)名稱和目標(biāo)方法中參數(shù)名稱一致。--><aop:pointcut id="mypoint" expression="execution(* com.bjsxt.service.impl.PeopleServiceImpl.test(int,boolean)) and args(id1,bool1)"/><aop:before method="mybefore" pointcut-ref="mypoint" arg-names="id1,bool1"/><aop:after-returning method="myafter" pointcut-ref="mypoint" arg-names="id1,bool1"/><aop:after method="myafter2" pointcut-ref="mypoint" arg-names="id1,bool1"/><!-- pjp由Spring自動(dòng)注入 --><aop:around method="myaround" pointcut-ref="mypoint" arg-names="pjp,id1,bool1"/><aop:after-throwing method="mythrow" pointcut-ref="mypoint" arg-names="ex,id1,bool1" throwing="ex"/></aop:aspect></aop:config>
Schema-based和Aspectj的區(qū)別:
- Schema-based:基于接口實(shí)現(xiàn)的。 AspectJ方式:是基于配置實(shí)現(xiàn)的。
- Schame-based是運(yùn)行時(shí)增強(qiáng),AspectJ是編譯時(shí)增強(qiáng)。
- 切面比較多時(shí),最好選擇AspectJ方式,因?yàn)锳spectJ方式要快很多。
3.注解方式實(shí)現(xiàn)AOP
<!--配置注解掃描路徑--><context:component-scan base-package="com.bjsxt"/><!--配置AOP注解生效--><aop:aspectj-autoproxy expose-proxy="true"/>autoproxy expose-proxy="true"/>
注意:
配置Spring容器注解掃描的路徑。
配置AOP注解生效。
@Component | 相當(dāng)于配置文件的bean標(biāo)簽,將某個(gè)類的對(duì)象掃描到Spring容器中。 |
@Aspect | 聲明該類為通知類。結(jié)合@Component在通知類上使用。 |
@pointcut | 聲明切點(diǎn),方法上使用。 |
@Before | 聲明方法為前置通知方法。 |
@After | 聲明方法為后置通知方法。 |
@Around | 聲明方法為環(huán)繞通知方法。 |
@AfterThrowing | 聲明方法為異常通知方法。 |
AOP工作流程:
? ? ? ? 1.通過切點(diǎn)表達(dá)式獲取切入點(diǎn)(目標(biāo)對(duì)象和目標(biāo)方法)
? ? ? ? 2.為目標(biāo)對(duì)象創(chuàng)建代理對(duì)象
? ? ? ? 3.在代理對(duì)象中織入通知,執(zhí)行的目標(biāo)方法
?八.Sping聲明式事務(wù)
聲明式事務(wù)是基于AOP實(shí)現(xiàn)的。把開啟事務(wù)的代碼放在前置通知中,把事務(wù)回滾和事務(wù)提交的代碼放在了后置通知中。
1.配置聲明式事務(wù)
需要在配置文件中引入xmlns:tx命名空間。
<!--1. 配置聲明式事務(wù)(事務(wù)開啟,事務(wù)提交,事務(wù)回滾都進(jìn)行了封裝,配合AOP完成事務(wù)的控制 --><!--前置通知:開啟事務(wù)后置通知:事務(wù)提交異常通知:事務(wù)回滾-->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><!-- 事務(wù)管理必須連接數(shù)據(jù)庫(kù),需要注入數(shù)據(jù)源對(duì)象 --><property name="dataSource" ref="dataSource"></property></bean><!-- 2. 配置事務(wù)通知 配置哪些方法織入事務(wù)的通知 --><!-- 相當(dāng)于通知類,只有方法出現(xiàn)了異常觸發(fā)異常通知,實(shí)現(xiàn)事務(wù)回滾,所以絕對(duì)不能在service里面try...catch--><tx:advice id="txAdvice" transaction-manager="txManager"><!-- 配置的方法才會(huì)織入事務(wù)的通知 --><tx:attributes><!-- --><tx:method name="alertAccountt"/><!-- <tx:method name="select*"/>--><!-- 所有的方法都需要進(jìn)行事務(wù)管理。在配置方法名稱是支持*作為通配符 --><tx:method name="*"/></tx:attributes></tx:advice> <!-- 3. 設(shè)定哪個(gè)方法需要被聲明式事務(wù)管理,使用AOP完成,根據(jù)切點(diǎn)表達(dá)式獲取切入點(diǎn)(目標(biāo)對(duì)象中的目標(biāo)方法),為目標(biāo)對(duì)象創(chuàng)建代理對(duì)象,將通知和目標(biāo)方法完成織入。
--><aop:config><aop:pointcut id="mypoint" expression="execution(* com.bjsxt.service.impl.*.*(..))"/><aop:advisor advice-ref="txAdvice" pointcut-ref="mypoint"></aop:advisor></aop:config>
2.注解配置聲明式事務(wù)(主要使用)
Spring 注解配置事務(wù)時(shí),只需要在需要有事務(wù)管理的方法上添加@Transactional注解。
必須保證配置注解的方法所在的類已經(jīng)放入到Spring容器中。
- 配置注解掃描
<context:component-scan base-package="com.bjsxt.service.impl"></context:component-scan>
- 開啟事務(wù)注解的支持
<tx:annotation-driven></tx:annotation-driven>
- 必須配置事務(wù)管理器類
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource" ref="dataSource"></property>
</bean>
- @Transactional的使用
@Transactional用在類上,整個(gè)類中方法都生效。
@Transactional用在方法上,該方法生效。用在方法上優(yōu)先級(jí)更高。
3.聲明式事務(wù)四個(gè)基礎(chǔ)屬性
?<tx:method>
標(biāo)簽有下面屬性的配置,@Transaction注解也支持部分屬性(如果有則含義相同,如果沒有則表示在注解中不需要配置)。
1. name屬性
配置哪些方法需要有事務(wù)控制,支持*通配符。
2. readonly屬性
是否為只讀事務(wù),有true和false兩種。
3. rollback-for屬性
異常類型全限定路徑,表示出現(xiàn)什么類型的異常進(jìn)行數(shù)據(jù)回滾。 默認(rèn)運(yùn)行時(shí)異常及子類異?;貪L,檢查時(shí)異常不回滾。
4. no-rollback-for屬性
異常類型全限定路徑,當(dāng)出現(xiàn)什么異常的時(shí)候不進(jìn)行數(shù)據(jù)回滾。
5. timeout屬性
執(zhí)行超過了設(shè)置的超時(shí)時(shí)間,回滾操作。(超時(shí)拋出異常)
?
4.事務(wù)傳播行為(面試題)
4.1.介紹
事務(wù)傳播行為:當(dāng)出現(xiàn)service方法調(diào)用另一個(gè)service方法時(shí)(這些方法都被聲明式事務(wù)管理)這些方法如何進(jìn)行事務(wù)管理。?
可以通過進(jìn)行配置tx:method或@Transactional中的propagation屬性來進(jìn)行傳播行為的設(shè)置 。
?@Transactional(propagation = Propagation.MANDATORY)?
- 默認(rèn)情況下都認(rèn)為每個(gè)方法都是沒有事務(wù)的(事務(wù)自動(dòng)提交)。
- ?整個(gè)調(diào)用最終都是在調(diào)用者里面統(tǒng)一提交回滾。
- 在聲明式事務(wù)中,如果是同一個(gè)類的多個(gè)方法相互調(diào)用,屬于同一個(gè)事務(wù)。
因?yàn)槁暶魇绞聞?wù)是基于AOP實(shí)現(xiàn)的,AOP是基于動(dòng)態(tài)代理實(shí)現(xiàn)的,為同一個(gè)對(duì)象創(chuàng)建一個(gè)代理對(duì)象,所以實(shí)現(xiàn)出來的效果只有對(duì)第一個(gè)調(diào)用的方法添加上了聲明式事務(wù)管理,其他方法都是普通的方法調(diào)用。
4.2?propagation屬性的可選值
Propagation.REQUIRED(默認(rèn)) | 當(dāng)前有事務(wù),使用當(dāng)前事務(wù)。當(dāng)前沒有事務(wù),開啟新的事務(wù)。 |
Propagation.NEVER | 必須在非事務(wù)狀態(tài)下執(zhí)行。沒有事務(wù),正常運(yùn)行。有事務(wù),拋出異常。 |
Propagation.NESTED | 必須在事務(wù)狀態(tài)下執(zhí)行。沒有事務(wù),創(chuàng)建事務(wù)。有事務(wù),創(chuàng)建嵌套事務(wù)。 |
Propagation.REQUIRES_NEW | 沒有事務(wù),創(chuàng)建事務(wù)。有事務(wù),掛起當(dāng)前事務(wù),創(chuàng)建新的事務(wù)。最后統(tǒng)一操作。 |
SUPPORTS | 沒有事務(wù),非事務(wù)執(zhí)行。有事務(wù),使用當(dāng)前事務(wù)。 |
Propagation.NOT_SUPPORTED | 非事務(wù)下執(zhí)行。有事務(wù),掛起事務(wù),以非事務(wù)執(zhí)行,執(zhí)行后,恢復(fù)掛起的事務(wù)。 |
propagation = Propagation.MANDATORY | 事務(wù)下執(zhí)行。沒有事務(wù),拋出異常。 |
九、Bean的生命周期(非常重要)
Spring中Bean的生命周期就是指Bean從初始化到銷毀的過程。Bean最簡(jiǎn)單的實(shí)現(xiàn)就是直接使用<bean>
標(biāo)簽定義這個(gè)Bean。
Bean生命周期流程:
- 編寫bean的定義信息(xml,注解)。
- 通過BeanDefinitionReader 讀取bean的定義信息。
- 解析出bean的定義信息。
- 可以通過BeanFactoryPostProcessor接口實(shí)現(xiàn)類,操作bean的定義信息。
- 實(shí)例化bean對(duì)象。
- 屬性注入。
- 可以使用相關(guān)的Aware接口,獲取bean的相關(guān)信息,容器信息...。
- 可以使用BeanPostProcessor接口中before方法操作對(duì)象。
- 可以使用init-method調(diào)用自定義的初始化方法。
- 可以使用BeanPostProcessor接口中after方法操作對(duì)象。
- 存儲(chǔ)到單例池(一級(jí)緩存中)。
二、Sping MVC
一. Spring MVC介紹
- Spring MVC本質(zhì)為Spring 框架的一個(gè)擴(kuò)展 ,屬于Spring Framework的二級(jí)子項(xiàng)目。
- Spring MVC是基于Front設(shè)計(jì)模式。
- Spring MVC中有前端入口DispatcherServlet,里面編寫了請(qǐng)求分發(fā)功能。
- EmpController在Spring MVC稱為控制器類(Handler),里面的方法稱為:控制單元(HandlerMethod)。
MVC三層中都有自己的功能。例如:
- M:在模型層包含:數(shù)據(jù)校驗(yàn)。
- V:在視圖層包含:國(guó)際化、標(biāo)簽庫(kù)。
- C:在控制層包含的功能就更多了:轉(zhuǎn)發(fā)重定向、參數(shù)、攔截器、作用域等。
Spring中的父子容器問題:
二.Spring MVC環(huán)境搭建
導(dǎo)入依賴:
<!-- 依賴了Spring框架核心功能的5個(gè)依賴以及Spring整合Web的依賴spring-web --><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>5.3.16</version></dependency>
?配置springMVC.xml:
<context:component-scan base-package="com.bjsxt.controller"></context:component-scan><!-- 讓Spring MVC的注解生效 不要引錯(cuò)xsd--><mvc:annotation-driven></mvc:annotation-driven>
編寫web.xml內(nèi)容:
<servlet><servlet-name>springmvc</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><init-param><!-- 參數(shù)名稱必須叫做:contextConfigLocation。單詞和大小寫錯(cuò)誤都導(dǎo)致配置文件無法正確加載 --><param-name>contextConfigLocation</param-name><!-- springmvc.xml 名稱自定義,只要和后面創(chuàng)建的文件名稱對(duì)應(yīng)就可以了。 --><param-value>classpath:springmvc.xml</param-value></init-param><!-- Tomcat啟動(dòng)立即加載Servlet,而不是等到訪問Servlet才去實(shí)例化DispatcherServlet --><!-- 配置上的效果:Tomcat啟動(dòng)立即加載Spring MVC框架的配置文件--><load-on-startup>1</load-on-startup></servlet><servlet-mapping><servlet-name>springmvc</servlet-name><!-- /表示除了.jsp結(jié)尾的uri,其他的uri都會(huì)觸發(fā)DispatcherServlet。此處前往不要寫成 /* --><url-pattern>/</url-pattern></servlet-mapping>
創(chuàng)建控制器類:
@Controller// 放入到Spring MVC容器中
public class FirstController {/** 官方標(biāo)準(zhǔn)寫法:* 返回值是ModelAndView,對(duì)象中存儲(chǔ)跳轉(zhuǎn)資源路徑及作用域值*/// 當(dāng)前方法的映射路徑@RequestMapping("/first")public ModelAndView test1(){ModelAndView modelAndView = new ModelAndView("first.jsp");return modelAndView;}/** 簡(jiǎn)化寫法(平時(shí)使用的方式)* 返回值是String,表示跳轉(zhuǎn)的資源路徑*/@RequestMapping("/first2")public String test2(){return "first.jsp";}
}
三.@RequestMapping注解
1.使用
- @RequestMapping注解可以寫在控制器類上,也可以寫在控制單元方法上。
- 如果寫在類上,表示當(dāng)前類所有控制單元的映射路徑,都以指定路徑開頭。
- 如果寫在方法上,表示當(dāng)前方法的映射路徑。
2.注解的屬性
? 1.path:映射的路徑。
? ? ? ? ? ?映射一個(gè)訪問路徑:path = {"aa"} ?省略{} ? path = "aa"
? ? ? ? ? ?映射多個(gè)訪問路徑:path = {"aa,bb"}。
??2.value:和path作用相同,只有一個(gè)value屬性時(shí),value可以省略。
? 3.name:添加描述信息。
? 4.method:允許的請(qǐng)求方式。
? ? ? ? ? ? ? ?RequestMethod.POST
? ? ? ? ? ? ? ?RequestMethod.GET
? ? ? ? ? ? ? ...
? ? ? ? ? ? 簡(jiǎn)化:
? ? ? ? ? ? ? ?@GetMapping? 為? @RequestMapping(method = RequestMethod.GET)
? ? ? ? ? ? ? ?@PostMapping? 為? @RequestMapping(method = RequestMethod.POST)
? ? ? ? ? ? ? ?...
? ?5.params: ?指定請(qǐng)求中必須攜帶的請(qǐng)求參數(shù)。
? ?6.headers: 指定請(qǐng)求中必須攜帶的請(qǐng)求頭。? ?7.consumes:表示處理請(qǐng)求內(nèi)容(Content-Type)的類型。
? ?8.produces:配合@ResponseBody注解使用,指定響應(yīng)內(nèi)容的類型。單獨(dú)使用沒有意? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 義。
四.轉(zhuǎn)發(fā)和重定向(重要)
- 在Spring MVC框架中,默認(rèn)情況下都使用轉(zhuǎn)發(fā)進(jìn)行尋找資源。
- 在資源路徑前面添加 forward:? ?,?表示轉(zhuǎn)發(fā)。
- 在資源路徑前面添加?redirect:?,表示重定向。
五.靜態(tài)資源放行
<!--配置靜態(tài)資源放行--><!--mapping:當(dāng)URI是什么樣格式時(shí),不再執(zhí)行控制器,而是尋找靜態(tài)資源。 ** 是通配符,表示任意層路徑 --><!--location:去哪個(gè)目錄中尋找靜態(tài)資源。mapping中**的值是什么,就去location目錄中找對(duì)應(yīng)資源--><!--例如URL是http://localhost:8080/bjsxt/js/jquery.js 其中mapping的**就是jquery.js,就會(huì)去location的/js/目錄中尋找jquery.js -->
<mvc:resources mapping="/js/**" location="/js/"></mvc:resources>
<mvc:resources mapping="/css/**" location="/css/"></mvc:resources>
<mvc:resources mapping="/images/**" location="/images/"></mvc:resources><!-- 靜態(tài)資源沒有在WEB-IBF中可以使用該方式 --><mvc:default-servlet-handler/>
六.控制單元的參數(shù)(接收請(qǐng)求參數(shù))
@Controller
@RequestMapping("emp")
public class EmpController {
/* 解耦合方式:獲取請(qǐng)求數(shù)據(jù),springmvc封裝好的 */
/*
* DispatcherServlet 會(huì)接收請(qǐng)求數(shù)據(jù),可以將請(qǐng)求數(shù)據(jù)進(jìn)行相關(guān)處理,然后傳遞給控制單元。
* *///1、接收普通參數(shù)//建議:盡量使用封裝類型,請(qǐng)求參數(shù)中沒有攜帶該參數(shù),自動(dòng)賦值為null//@RequestParam():請(qǐng)求參數(shù)中的名字 和 接收參數(shù)名不一致時(shí),使用該注解指定為請(qǐng)求參數(shù)名的名字@RequestMapping("a1")public String a1(@RequestParam("name") String uname, Integer age){System.out.println(uname);System.out.println(age);return "/index.jsp";}//2、使用JavaBean對(duì)象接收請(qǐng)求參數(shù)//注意:即使請(qǐng)求參數(shù)中沒有Emp的屬性,創(chuàng)建emp對(duì)象,傳遞到控制單元中// 使用JavaBean接收請(qǐng)求參數(shù)需要依賴于set方法@RequestMapping("a2")public String a2(Emp emp){System.out.println(emp);return "/index.jsp";}@RequestMapping("a3")public String a3(Emp emp, String name, String age){System.out.println(emp);System.out.println(name);System.out.println(age);return "/index.jsp";}//3、接收多個(gè)同名參數(shù)//數(shù)組:請(qǐng)求參數(shù)名和控制單元參數(shù)名相同即可直接接收//集合(List集合為例):必須通過@RequestParam執(zhí)行請(qǐng)求參數(shù)名// 如果為JavaBean中的屬性為L(zhǎng)ist集合接收同名多個(gè)屬性,不需要進(jìn)行額外處理。@RequestMapping("a4")public String a4(String[] strs){System.out.println(Arrays.toString(strs));return "/index.jsp";}@RequestMapping("a5")public String a5(@RequestParam("strs") List<String> strs){System.out.println(strs);return "/index.jsp";}@RequestMapping("a6")public String a6(Emp emp){System.out.println(emp);return "/index.jsp";}@RequestMapping("a7")//注意:默認(rèn)支持 yyyy/MM/dd 的日期格式//手動(dòng)指定接收的日期格式(@DateTimeFormat),一定手動(dòng)指定了接收的日期格式,默認(rèn)的日期格式不再生效public String a7(@DateTimeFormat(pattern = "yyyy-MM-dd") Date bir){System.out.println(bir);return "/index.jsp";}@RequestMapping("a8")public String a8(Emp emp){System.out.println(emp);return "/index.jsp";}/* 接收請(qǐng)求頭中的數(shù)據(jù) */@RequestMapping("a9")public String a9(@RequestHeader String accept){System.out.println(accept);return "/index.jsp";}@RequestMapping("a10")public String a10(@RequestHeader(value = "Accept-Language") String str){System.out.println(str);return "/index.jsp";}/* 向作用域?qū)ο笾写嬷?#xff08;request作用域) *///方式一:@RequestMapping("a11")public ModelAndView a11(){ModelAndView modelAndView = new ModelAndView();modelAndView.setViewName("/index.jsp");modelAndView.addObject("uname", "zs");return modelAndView;}//方式二:@RequestMapping("a12")public String a12(Map<String, Object> map){map.put("uname", "lsssss");return "/index.jsp";}//方式三:@RequestMapping("a13")public String a13(Model model){model.addAttribute("uname", "wwwwww");return "/index.jsp";}
}
七.@ResponseBody和@RequestBody注解
1.@ResponseBody
@ResponseBody:控制單元添加了該注解,不會(huì)執(zhí)行視圖解析器,將控制單元的返回值放入到響應(yīng)流直接響應(yīng)回到客戶端。
使用:
- ????????默認(rèn):
????????????????1.控制單元只能返回String類型的數(shù)據(jù)。返回其他數(shù)據(jù)類型出現(xiàn)406狀態(tài)碼。
????????????????2.配合@RequestMapping(produces = "text/plain;charset=utf-8")設(shè)置響應(yīng)內(nèi)容類? ? ? ? ? ? ? ? ? ? ? ?型及編碼格式。
- ????????引入了Jackson的依賴:
????????????????1.控制單元可以返回,JavaBean,數(shù)組[JavaBean], List<JavaBean>, Map,? ? ? ? ? ? ? ? ? ? ? ? ? ? ? List<Map> 等類型數(shù)據(jù)。
? ? ? ? ? ? ? ? ? 2.springmvc默認(rèn)使用jack將控制單元的返回值變?yōu)閖son格式的字符串,設(shè)置響應(yīng)? ? ? ? ? ? ? ? ? ? ? ?內(nèi)容類型為application/json;charset=utf-8。
@RestController注解:效果和控制器中所有的方法都包含@ResponseBody注解一樣。
2.@RequestBody注解
將格式為?json ,xml 的客戶端請(qǐng)求參數(shù)轉(zhuǎn)換為 javabean。需要引入相依賴(Jackson)。
$.ajax({url:"testContentType",contentType:"application/json",// 修改請(qǐng)求內(nèi)容類型為JSONdata:'{"id":1,"name":"張三"}',// json格式傳多個(gè)數(shù)據(jù)必須有單引號(hào),沒有單引號(hào)無效type:"post",// 不能是GET類型請(qǐng)求success:function (data) {console.log(data);},dataType:"json"
});
@RequestMapping("/testContentType")
@ResponseBody
public People testContentType(@RequestBody People peo) {System.out.println(peo);return peo;
}
八.Spring MVC文件上傳和下載
1. 文件上傳
導(dǎo)入依賴:
<dependency><groupId>commons-fileupload</groupId><artifactId>commons-fileupload</artifactId><version>1.4</version>
</dependency>
在頁(yè)面中編寫文件上傳代碼:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>Title</title>
</head>
<body><form action="/upload" method="post" enctype="multipart/form-data">姓名:<input type="text" name="name"/><br/>頭像:<input type="file" name="photo"/><br/>地址:<input type="text" name="address"/><br/><input type="submit" value="提交"/><br/></form>
</body>
</html>
配置上傳文件解析器:
<!-- 文件上傳時(shí),必須配置文件解析器 -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"></bean><!-- 限制上傳文件大小 -->
bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"><property name="maxUploadSize" value="1024"></property>
</bean>
編寫單元方法處理上傳請(qǐng)求:
/*** 文件上傳控制單元方法實(shí)現(xiàn)* @param name 也可以使用JavaBean接收name的值* @param address 也可以使用JavaBean接收address的值* @param photo 名字必須和表單中文件域的name屬性值相同* @return* @throws IOException transferTo拋出的異常,可以使用try...catch處理異常。示例中為了讓代碼看起來簡(jiǎn)潔直接拋出了。*/@RequestMapping("/upload")
public String upload(String name, String address, MultipartFile photo,HttpServletRequest request) throws IOException {if(!photo.isEmpty()) {long timeMillis = System.currentTimeMillis();Random random = new Random();String fileName = timeMillis + "" + random.nextInt(1000);String oldName = photo.getOriginalFilename();String suffix = oldName.substring(oldName.lastIndexOf("."));// 獲取到當(dāng)前項(xiàng)目images目錄,發(fā)布到Tomcat后的絕對(duì)路徑。String realPath = request.getServletContext().getRealPath("/images");System.out.println(realPath);// 保存到當(dāng)前項(xiàng)目的images目錄中。photo.transferTo(new File(realPath,fileName + suffix));}return "/upload.jsp";
}
2. 文件下載
@RequestMapping("/download")
public void download(HttpServletRequest req, HttpServletResponse response, String filename) {try {// 因?yàn)槭荊ET請(qǐng)求,所以要解決請(qǐng)求參數(shù)中文亂碼問題String fileNameUtf8 = new String(filename.getBytes("iso-8859-1"), "utf-8");// 圖片名稱滿足固定格式String newFilenameUtf8 = "來自尚學(xué)堂的"+fileNameUtf8;String newFilenameISO = new String(newFilenameUtf8.getBytes("utf-8"),"iso-8859-1");// 此處是ISO-8859-1編碼的內(nèi)容response.setHeader("Content-Disposition", "attachment;filename=" + newFilenameISO);// 此處必須是UTF-8解決參數(shù)亂碼問題的名稱File file = new File(req.getServletContext().getRealPath("/images"), fileNameUtf8);FileInputStream fis = new FileInputStream(file);ServletOutputStream os = response.getOutputStream();IOUtils.copy(fis, os);} catch (IOException e) {e.printStackTrace();}
}
九.攔截器(重點(diǎn))
只有URL匹配到了控制單元,攔截器才能生效。
1. 使用攔截器
- 創(chuàng)建攔截器:
public class MyInterceptor implements HandlerInterceptor {@Override
//執(zhí)行時(shí)機(jī):單元方法執(zhí)行之前。返回false表示攔截此次請(qǐng)求,返回true表示放行。public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {System.out.println("MyInterceptor.preHandle");return fasle;}
//執(zhí)行時(shí)機(jī):單元方法執(zhí)行之后,視圖解析器解析渲染視圖之前。@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {System.out.println("MyInterceptor.postHandle");}//執(zhí)行時(shí)機(jī):視圖解析器解析渲染視圖完成之后。@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {System.out.println("MyInterceptor.afterCompletion");}
}
- 配置攔截器:
<!--配置攔截器作用:讓聲明的攔截器類生效完成單元方法請(qǐng)求的攔截使用:在springmvc.xml文件中使用<mvc:interceptors>標(biāo)簽聲明攔截的配置信息在<mvc:interceptors>標(biāo)簽下使用子標(biāo)簽完成攔截器的配置全局?jǐn)r截在<mvc:interceptors>直接聲明bean標(biāo)簽配置攔截器的bean,攔截所有的單元方法請(qǐng)求。局部攔截在<mvc:interceptors>標(biāo)簽下使用子標(biāo)簽<mvc:interceptor>來聲明局部攔截在<mvc:interceptor>標(biāo)簽下使用子標(biāo)簽配置攔截返回以及攔截器的bean<mvc:mapping path="/demo"/> 要攔截的范圍,可以聲明多個(gè)<bean id="mm" class="com.bjsxt.inter.MyInter"></bean> 攔截器
-->
<!--配置攔截器-->
<mvc:interceptors><!--配置攔截器的bean對(duì)象,攔截所有的單元方法--><bean class="com.bjsxt.interceptor.MyInterceptor2"></bean><!--配置具體的攔截器的bean極其攔截范圍,可以配置多個(gè)--><mvc:interceptor><mvc:mapping path="/myController/demo"/><!--配置攔截的單元方法的訪問路徑,第一個(gè)/表示項(xiàng)目根目錄,可以多個(gè)--><mvc:mapping path="/myController/kk/*"/><!--支持*通配符表示任意個(gè)數(shù)的任意字符,**表示路徑及子路徑--><bean class="com.bjsxt.interceptor.MyInterceptor"></bean><!--配置攔截器的bean對(duì)象,只在當(dāng)前mvc:interceptor內(nèi)有效--></mvc:interceptor>
</mvc:interceptors>
攔截器執(zhí)行順序總結(jié):
攔截器棧執(zhí)行順序:
2.攔截器和過濾器的區(qū)別(面試題)
- 過濾器(Filter):由JavaEE提供的過濾器. 請(qǐng)求到達(dá)資源(servlet,頁(yè)面,css,js,img,...)之前都要經(jīng)過過濾器,資源響應(yīng)回到客戶端之前經(jīng)過過 濾器。
- 攔截器(Interceptor):由SpringMVC提供的攔截器. 請(qǐng)求到到控制單元之前經(jīng)過攔截器(preHandle),控制單元執(zhí)行完成后經(jīng)過攔截器(postHandle),向頁(yè)面響應(yīng)完成,經(jīng)過攔截器(afterCompletion)。
區(qū)別:
來源不同
攔截器是SpringMVC中的技術(shù),過濾器是Java EE中的技術(shù)。
生效位置不同
攔截器是進(jìn)入DispatcherServlet后才能執(zhí)行,過濾器是進(jìn)入到Servlet容器前就可以觸發(fā)。
目標(biāo)不同
攔截器攔截的目標(biāo)是HandlerMethod(控制單元,控制器方法),過濾器可以過濾所有的URL。
運(yùn)行機(jī)制不同
攔截器是在HandlerMethod執(zhí)行前后和視圖處理完成后執(zhí)行,分為三部分。過濾器只能在目標(biāo)資源前后執(zhí)行。
接口中方法類型不同
攔截器中的方法都是default方法,可以重寫也可以不重寫。過濾器中的方法都是abstract方法,如果當(dāng)前類不是抽象類,必須重寫。
上下文不同
攔截器被Spring MVC管理,可以獲取到Spring容器中內(nèi)容。Filter被Tomcat管理,所以無法獲取Spring容器內(nèi)容。
十.視圖解析器(重點(diǎn))
1.ModelAndView:模型數(shù)據(jù)(存儲(chǔ)業(yè)務(wù)數(shù)據(jù))和視圖
? ? ? ? ? ? ? ?Model:模型數(shù)據(jù)(存儲(chǔ)模型層中查詢到的數(shù)據(jù))
? ? ? ? ? ? ? ?View: 視圖(頁(yè)面屬于視圖中的一種)
?2.控制單元執(zhí)行完成后,將控制單元返回的結(jié)果固定封裝為ModelAndView對(duì)象。? ? Model中存儲(chǔ)了業(yè)務(wù)數(shù)據(jù),View通常存儲(chǔ)視圖名。最終目的:將Model中的業(yè)務(wù)數(shù)據(jù)通過? ? ? ??視圖 渲染 到客戶端。
? ? ? ? ? ?底層源碼:
? ? ? ? ? ? ? ?ModelAndView mv;
? ? ? ? ? ? ???mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
? ? ? ? ? ? ? 執(zhí)行控制單元,控制單元返回結(jié)果封裝為ModelAndView。?3. 視圖解析器:ViewResolver(接口),根據(jù)ModelAndView對(duì)象中解析出的視圖名找到? ? ? ? ?對(duì)應(yīng)的視圖對(duì)象,并返回。
以.jsp視圖為例:
? ??1.控制單元執(zhí)行后,執(zhí)行handle(processedRequest, response,? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ???mappedHandler.getHandler()),返回ModelAndView對(duì)象 (viewname為index.jsp)
? ? 2.獲取到ModelAndView后,執(zhí)行render(mv, request, response);?
? ? 3.在render方法中調(diào)用了view = resolveViewName(viewName, mv.getModelInternal(),? ? ? ? ? ? ? ?locale, request),獲取到視圖名。
? ??4.在resolveViewName(String viewName,Locale locale)方法中, 視圖解析器 根據(jù)視圖? ? ? ? ? 名找到對(duì)應(yīng)的視圖對(duì)象,并返回。
? ? ? ? ?(1)默認(rèn)的使用的視圖解析器:InternalResourceViewResourceView。
? ? ? ? ?(2)?.jsp的視圖對(duì)象為:InternalResourceView。
????5.返回視圖對(duì)象后,調(diào)用view.render(mv.getModelInternal(), request, response)。實(shí)際完? ? ? ? ?成Model中的數(shù)據(jù)通過視圖響應(yīng)回到客戶端。
? ? 6. .jsp的InternalResourceView的視圖對(duì)象渲染時(shí):
? ? ? ? ? (1)將Model中的數(shù)據(jù)存儲(chǔ)到請(qǐng)求域?qū)ο笾小?/p>
? ? ? ? ? (2)將請(qǐng)求轉(zhuǎn)發(fā)到.jsp -> .java(獲取請(qǐng)求去對(duì)象中的數(shù)據(jù))-> .class -> 將結(jié)果輸出? ? ? ? ? ? ? ? ? ? ? ? 到客戶端。
十一.Spring MVC中組件
1. 組件介紹
DispatcherServlet被初始化的時(shí)候其底層內(nèi)部也會(huì)完成第2到第10個(gè)組件的初始化,調(diào)用其initStrategies方法來完成。
protected void initStrategies(ApplicationContext context) {this.initMultipartResolver(context);this.initLocaleResolver(context);this.initThemeResolver(context);this.initHandlerMappings(context);this.initHandlerAdapters(context);this.initHandlerExceptionResolvers(context);this.initRequestToViewNameTranslator(context);this.initViewResolvers(context);this.initFlashMapManager(context);
}
2.常用組件說明
- DispatcherServlet:前端控制器。Spring MVC的入口,也是整個(gè)流程控制中心。其他組件 由DispatcherServlet統(tǒng)一調(diào)度,降低了組件和組件之間的耦合度。
- MultipartResovler:多部分處理器。文件上傳時(shí)需要使用。
- LocaleResolver:解決客戶端的區(qū)域和時(shí)區(qū)問題。
- ThemeResolver:主題解析器。提供自定義布局。
- HandlerMapping: 映射處理器。主要負(fù)責(zé)處理URL,并找到對(duì)應(yīng)的HandlerMethod(只是找到控制單元)。簡(jiǎn)單說就是找@RequestMapping注解中映射路徑是否有和URL匹配的。
- HandlerAdapter:適配器。負(fù)責(zé)調(diào)用具體的HandlerMethod(調(diào)用并運(yùn)行)。
- HandlerExceptionResovler:異常處理器。異常處理,根據(jù)不同異常返回視圖。
- RequestToViewNameTranslator:從請(qǐng)求中獲取到視圖名稱。
- ViewResovler:視圖解析器,負(fù)責(zé)解析字符串視圖名和物理視圖文件的。
- FlashMapManager:主要用于存儲(chǔ)屬性的,本質(zhì)是一個(gè)Map。多用在重定向時(shí)。FlashMap在重定向之前存儲(chǔ),重定向之后刪除。
- ModelAndView:模型和視圖。Spring MVC中提供的模型和視圖接口。
- HandlerInterceptor:攔截器。攔截控制器資源的。
十二.SpringMVC運(yùn)行原理(常見面試題)
SpringMVC執(zhí)行流程:
?Tomcat啟動(dòng):
- 監(jiān)聽到了ServletContext對(duì)象創(chuàng)建,加載Spring配置文件,創(chuàng)建Spring容器。
- Tomcat啟動(dòng)后創(chuàng)建DispatcherServlet,DispatcherServlet初始化時(shí):
1.加載Springmvc配置文件,創(chuàng)建Springmvc容器。
2.初始化SpringMVC相關(guān)組件:MultipartResovler、HandlerMapping、? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?HandlerAdapterHandler、ExceptionResovler、ModelAndView、ViewResovler、? ? ? ? ? ? ? ? ? ?HandlerInterceptor。
客戶端向服務(wù)端發(fā)起請(qǐng)求,Spring MVC總體入口中央調(diào)度器DispatcherServlet進(jìn)行請(qǐng)求分發(fā)。
中央調(diào)度器DispatcherServlet把URL交給映射處理器HandlerMapping進(jìn)行解析URL。
映射處理器HandlerMapping將請(qǐng)求映射為HandlerExecutionChain處理器執(zhí)行鏈
可以為多個(gè)處理器攔截器HandlerInterceptor
處理器Handler對(duì)象(處理Controller)。
將處理器執(zhí)行鏈HandlerExecutionChain返回到中央調(diào)度器DispatcherServlet。
DispatcherServlet根據(jù)返回的處理器執(zhí)行鏈HandlerExecutionChain獲得的處理器Handler,根據(jù)處理器Handler選擇處理器適配器HandlerAdapter。
執(zhí)行攔截器的preHandle()方法。
調(diào)用具體的Handler處理器(處理Controller),在填充Handler的入?yún)⑦^程中會(huì)執(zhí)行數(shù)據(jù)轉(zhuǎn)換、數(shù)據(jù)格式化、數(shù)據(jù)驗(yàn)證,調(diào)用具體的Controller完成處理功能,并創(chuàng)建ModelAndView對(duì)象。
執(zhí)行攔截器的postHandle()方法。
將ModelAndView對(duì)象返回到處理器適配器HandlerAdapter。
處理器適配器HandlerAdapter將ModelAndView對(duì)象返回到中央調(diào)度器DispatcherServlet。
中央調(diào)度器DispatcherServlet調(diào)用視圖解析器ViewResolver解析視圖。
將解析的視圖View對(duì)象返回到中央調(diào)度器DispatcherServlet。
渲染視圖,將視圖返回到中央調(diào)度器DispatcherServlet。
執(zhí)行攔截器afterCompletion()方法。
中央調(diào)度器DispatcherServlet響應(yīng)回到瀏覽器。