Spring
本筆記是在學(xué)習(xí)狂神說java的B站視頻記錄的。
簡介
歷史
2002 —— 雛形interface21框架
作者 —— Rod Johnson,Spring Framework創(chuàng)始人
spring 理念 ——使現(xiàn)有技術(shù)更加容易使用,本身是一個(gè)大雜燴,整合了現(xiàn)有的技術(shù)框架
官網(wǎng)地址:https://spring.io/projects/spring-framework#overview
下載Github:https://github.com/spring-projects/spring-framework
優(yōu)點(diǎn)
- 開源的免費(fèi)的框架(容器)
- 輕量級(jí)的、非入侵式的框架
- 控制反轉(zhuǎn)(IOC),面向切面編程(AOP)
- 支持事務(wù)的處理,對(duì)框架整合的支持
總結(jié)一句話:Spring就是一個(gè)輕量級(jí)的控制反轉(zhuǎn)(IOC)和面向切面編程(AOP)的框架!
組成

擴(kuò)展
現(xiàn)代化的java開發(fā)就是基于spring的開發(fā)

- Spring Boot
- 一個(gè)快速開發(fā)的腳手架
- 基于SpringBoot可以快速的開發(fā)單個(gè)微服務(wù)
- 約定大于配置
- SpringCloud
- SpringCloud是基于SpringBoot實(shí)現(xiàn)的。
弊端
? 發(fā)展了太久之后,違背了原來的理念!配置十分繁瑣,人稱“配置地獄!”
IOC理論推導(dǎo)
- UserDao接口
- UserDaoImpl實(shí)現(xiàn)類
- UserService業(yè)務(wù)接口
- UserServiceImpl業(yè)務(wù)實(shí)現(xiàn)接口
之前,程序是主動(dòng)創(chuàng)建對(duì)象
使用set()注入,程序由主動(dòng)變被動(dòng)接收對(duì)象
IOC是一種設(shè)計(jì)思想,依賴注入DI是IOC的一種實(shí)現(xiàn)

HelloSpring
xml里配置<bean class="xxx"></bean>
對(duì)象由spring創(chuàng)建、管理、裝配
new 是走無參構(gòu)造創(chuàng)建對(duì)象
ApplicationContext context = new ClassPathXmlApplication(beans.xml);
context.getBean();
IOC創(chuàng)建對(duì)象方式
1.使用默認(rèn)的無參構(gòu)造
2.假設(shè)要使用有參構(gòu)造創(chuàng)建對(duì)象
-
下標(biāo)賦值
<constructor-arg index="0" value="24"></constructor-arg> <constructor-arg index="1" value="zhaoyt"></constructor-arg> -
通過類型
- 參數(shù)名(name="屬性名")
spring容器相當(dāng)于"婚介所"
Spring配置
別名
<alias name="user" alias="userNew"></alias>
bean的配置
id 唯一標(biāo)識(shí) 相當(dāng)于對(duì)象名
class:bean對(duì)象所對(duì)應(yīng)的全限定名:包名+類名
name:也是別名,同時(shí)可以取多個(gè)
<bean id="user" class="com.zyt.pojo.User" name="user2"></bean>
import
一般用于團(tuán)隊(duì)開發(fā),配置多個(gè)文件,合并為一個(gè)總的。
applicationContext.xml
<import resource="bean1.xml"/>
<import resource="bean2.xml"/>
依賴注入
1.構(gòu)造器注入
2.set方式注入(重點(diǎn))
- 依賴:bean對(duì)象的創(chuàng)建依賴于容器
- 注入:bean對(duì)象中的所有屬性,由容器來注入!
3.拓展方式注入
- p命名空間
xmlns:p="http://www.springframework.org/schema/p"
<!--p命名空間注入,可以直接注入屬性的值-->
<bean id="user" class="com.zyt.pojo.User" p:name="zyt" p:age="24"/>
- c命名空間
xmlns:c="http://www.springframework.org/schema/c"
<!--c命名空間-->
<bean id="user2" class="com.zyt.pojo.User" c:age="18" c:name="zhaoyt"/>
bean作用域
1.單例模式(Spring默認(rèn)機(jī)制)
<bean id="user2" class="com.zyt.pojo.User" c:age="18" c:name="zhaoyt" scope="singleton"/>
2.原型模式:每次從容器中g(shù)et的時(shí)候,都會(huì)產(chǎn)生一個(gè)新的對(duì)象
<bean id="user1" class="com.zyt.pojo.User" p:name="zyt" p:age="24" scope="prototype"/>
3.其余的request、session、application這些只能在web開發(fā)中使用到。
Bean自動(dòng)裝配
- 自動(dòng)裝配是Spring滿足bean依賴的一種方式
- Spring會(huì)再上下文中自動(dòng)尋找,并自動(dòng)給bean裝配屬性
在Spring中有三種裝配方式
? 1.在xml中顯示的配置
? 2.在java中顯示的配置
? 3.隱式的自動(dòng)裝配
1.byName
<!--byName:會(huì)自動(dòng)在容器上下文查找,和自己對(duì)象set方法后面對(duì)應(yīng)的值beanid-->
<bean id="people" class="com.zyt.pojo.People" autowire="byName">
<property name="name" value="zyt" />
</bean>
2.byType
<!--byType:會(huì)自動(dòng)在容器上下文查找,和自己對(duì)象屬性類型相同的bean-->
<bean id="people" class="com.zyt.pojo.People" autowire="byType">
<property name="name" value="zyt" />
</bean>
小結(jié):
- byName的時(shí)候,需要保證所有bean的id唯一,并且這個(gè)bean需要和自動(dòng)注入的屬性的set方法的值一致!
- byType的時(shí)候,需要保證所有bean的class唯一,并且這個(gè)bean需要和自動(dòng)注入的屬性的類型一致!
使用注解實(shí)現(xiàn)自動(dòng)裝配
要使用注解須知:
? 1.導(dǎo)入約束,context約束
? 2.配置注解的支持:<context:annotation-config/>
<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 https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config/>
</beans>
@Autowired
直接在屬性上使用即可,也可以set方式上使用!
使用Autowired我們可以不用在寫set方法,前提是你這個(gè)自動(dòng)裝配的屬性在IOC(Spring)容器中存在,且符合名字byName!
@Resource和@Autowired的區(qū)別
- 都是用來自動(dòng)裝配的,都可以放在屬性字段上
- @Autowired 通過byType方式實(shí)現(xiàn),而且必須要求這個(gè)對(duì)象存在【常用】
- @Resource默認(rèn)通過byName的方式實(shí)現(xiàn),如果找不到名字,則通過byType實(shí)現(xiàn)!如果兩個(gè)都找不到的情況下,就報(bào)錯(cuò)!【常用】
- 執(zhí)行順序不同:@Autowired 通過byType的方式實(shí)現(xiàn)。@Resource默認(rèn)通過byName的方式實(shí)現(xiàn)。
使用注解開發(fā)
spring4之后,要使用注解開發(fā),必須保證aop的包導(dǎo)入了

使用注解需要導(dǎo)入約束,增加約束的支持
1.bean
2.屬性如何注入
-
@Componet:組件,放在類上,說明這個(gè)類被Spring管理了,就是bean!
等價(jià)于
<bean id="people" class="com.zyt.pojo.People"/>
<context:component-scan base-package="com.zyt.pojo"/>
- @Value("xxx"):相當(dāng)于
<property name="name" value="zyt"/>
3.衍生的注解
? @Component有幾個(gè)衍生注解,在web開發(fā)中,會(huì)按照mvc三層架構(gòu)分層!
-
dao層【@Repository】
service層【@Service】
-
controller層【@Controller】
這四個(gè)注解功能都是一樣的,都是將某個(gè)類注冊到spring中,bean裝配
4.自動(dòng)裝配
@Nullable //可以使字段為null
@Autowired(required = false)//required屬性用作說明這個(gè)對(duì)象可以為null,否則為空
@Qualifier(value = "cat222")//與Autowired配合使用,指定一個(gè)唯一的bean對(duì)象注入
@Resource(name="dog")//加name指定bean,功能強(qiáng)大一些
5.作用域
@Scope("singleton")
6.小結(jié)
- xml更加萬能,適用于任何場合!維護(hù)簡單方便
- 注解 不是自己類使用不了,維護(hù)相對(duì)復(fù)雜!
xml與注解的最佳實(shí)踐
xml用來管理bean;
注解只負(fù)責(zé)完成屬性的注入;
-
必須要讓注解生效,就需要開啟注解支持【重點(diǎn)】
<!--開啟注解的支持--> <context:annotation-config/> <!--指定要掃描的包,這個(gè)包下的注解就會(huì)生效--> <context:component-scan base-package="com.zyt"/>
使用java的方式配置spring

@Configuration 代表是一個(gè)配置類,相當(dāng)于beans.xml
@Bean,注冊一個(gè)bean,相當(dāng)于bean標(biāo)簽,方法名字相當(dāng)于id屬性,返回類型相當(dāng)于class屬性
@Import也相當(dāng)于import標(biāo)簽
ApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class);
這種純java的配置方式,在springboot中隨處可見
代理模式
為什么要學(xué)習(xí)代理模式?因?yàn)檫@就是SpringAOP的底層!
中介:

代理模式分類:
靜態(tài)代理
動(dòng)態(tài)代理
靜態(tài)代理
角色分析:
- 抽象角色:一般會(huì)使用接口或者抽象類來解決
- 真實(shí)角色:被代理的角色
- 代理角色:代理真實(shí)角色,代理后一般會(huì)做一些附屬操作
- 客戶:訪問代理對(duì)象的人
代理模式的好處:
可以使真實(shí)角色的操作更加純粹,不用去關(guān)注一些公共的業(yè)務(wù)。
公共也就交給代理角色,實(shí)現(xiàn)了業(yè)務(wù)的分工。
公共業(yè)務(wù)發(fā)生擴(kuò)展的時(shí)候,方便集中管理
缺點(diǎn):
- 一個(gè)真實(shí)角色就會(huì)產(chǎn)生一個(gè)代理角色,代碼量會(huì)翻倍,開發(fā)效率變低!
加深印象

動(dòng)態(tài)代理
動(dòng)態(tài)代理和靜態(tài)代理角色一樣
動(dòng)態(tài)代理的代理類是動(dòng)態(tài)生成的,不是我們直接寫好的!
-
動(dòng)態(tài)代理分為兩大類:基于接口的動(dòng)態(tài)代理,基于類的動(dòng)態(tài)代理
- 基于接口——JDK動(dòng)態(tài)代理【我們在這里使用】
- 基于類——cglib
- java字節(jié)碼——Javassist
需要了解兩個(gè)類:Proxy 代理、InvocationHandler:調(diào)用處理程序
動(dòng)態(tài)代理的好處:
- 靜態(tài)的好處都有
- 一個(gè)動(dòng)態(tài)代理類代理的是一個(gè)接口,一般就是對(duì)應(yīng)一類業(yè)務(wù)
- 一個(gè)動(dòng)態(tài)代理類可以代理多個(gè)類,只要是實(shí)現(xiàn)了同一個(gè)接口即可
AOP
什么是AOP
Aspect Oriented Programming 面向切面編程,通過預(yù)編譯方法和運(yùn)行期動(dòng)態(tài)代理實(shí)現(xiàn)程序功能的統(tǒng)一維護(hù)的一種技術(shù)。

AOP在spring中的作用
提供聲明式事務(wù);允許用戶自定義切面
- 橫切關(guān)注點(diǎn):跨越應(yīng)用程序多個(gè)模塊的方法或功能
- 切面(Aspect):類
- 通知(Advice):類中的方法
- 目標(biāo)(Target):被通知對(duì)象
- 代理(Proxy):向目標(biāo)對(duì)象應(yīng)用通知之后創(chuàng)建的對(duì)象
- 切入點(diǎn)(PointCut):切面通知執(zhí)行的“地點(diǎn)”的定義
- 連接點(diǎn)(JointPoint):與切入點(diǎn)匹配的執(zhí)行點(diǎn)

SpringAOP中,通過Advice定義橫切邏輯,Spring中支持5種類型的Advice:
前置通知、后置通知、環(huán)繞通知、異常拋出通知、引介通知

使用Spring實(shí)現(xiàn)AOP
【重點(diǎn)】使用AOP織入,需要導(dǎo)入一個(gè)依賴包
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.2</version>
</dependency>
方式一:使用Spring API接口【主要是springAPI接口實(shí)現(xiàn)】
<aop:config>
<!--切入點(diǎn):expression表達(dá)式,execution(要執(zhí)行的位置?。?->
<aop:pointcut id="pointcut" expression="execution(* com.zyt.service.UserServiceImpl.*(..))"/>
<!--執(zhí)行環(huán)繞增加!-->
<aop:advisor advice-ref="log" pointcut-ref="pointcut"/>
<aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/>
</aop:config>
方式二:自定義來實(shí)現(xiàn)AOP【主要是切面定義】
<bean id="diy" class="com.zyt.diy.DiyPointcut"/>
<aop:config>
<!--自定義切面,ref要引用的類-->
<aop:aspect ref="diy">
<!--切入點(diǎn)-->
<aop:pointcut id="point" expression="execution(* com.zyt.service.UserServiceImpl.*(..))"/>
<!--通知-->
<aop:before method="before" pointcut-ref="point"/>
<aop:after method="after" pointcut-ref="point"/>
</aop:aspect>
</aop:config>
方式三:使用注解實(shí)現(xiàn)!
@Aspect //標(biāo)注這個(gè)類是一個(gè)切面
@Before //前置通知
@After //后置通知
@Around //環(huán)繞通知
//運(yùn)行結(jié)果:
/* 環(huán)繞前
signaturevoid com.zyt.service.UserService.add()
===========方法執(zhí)行前===========
增加一個(gè)用戶
環(huán)繞后
null
===========方法執(zhí)行后===========
*/
整合Mybatis
步驟:
- 導(dǎo)入相關(guān)jar包
- junit
- mybatis
- mysql數(shù)據(jù)庫
- spring相關(guān)
- aop織入
- mybatis-spring【new】
- 編寫配置文件
- 測試
回憶mybatis
-
編寫實(shí)體類
User
-
編寫核心配置文件
mybatis-config.xml
-
編寫接口
UserMapper
-
編寫xml文件
UserMapper.xml
-
測試
MyTest
【遇到問題——映射綁定報(bào)錯(cuò)】org.apache.ibatis.binding.BindingException: Invalid bound statement (not found)
用maven的build將xml文件加載進(jìn)來
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
<filtering>true</filtering>
</resource>
</resources>
</build>
Mybatis-Spring
- 編寫數(shù)據(jù)源
- sqlSessionFactory
- sqlSessionTemplate(核心)
- 需要給接口加實(shí)現(xiàn)類
- 將自己寫的實(shí)現(xiàn)類注入到spring中
聲明式事務(wù)
- 回顧事務(wù)
- 把一組業(yè)務(wù)當(dāng)成一個(gè)業(yè)務(wù)來做;要么都成功,要么都失?。?/li>
- 事務(wù)在項(xiàng)目開發(fā)中,十分重要,涉及到數(shù)據(jù)的一致性問題,不能馬虎!
- 確保完整性和一致性
事務(wù)ACID原則
- 原子性
- 一致性
- 隔離性
- 多個(gè)業(yè)務(wù)可能操作同一個(gè)資源,防止數(shù)據(jù)損壞
- 持久性
- 事務(wù)一旦提交,無論系統(tǒng)發(fā)生什么問題,結(jié)果都不會(huì)再被影響,被持久化的寫到存儲(chǔ)器中!
2.spring中的事務(wù)
- 聲明式事務(wù):AOP
- 編程式事務(wù),需要在代碼中,進(jìn)行事務(wù)的管理
思考:
為什么需要事務(wù)?
- 如果不配置事務(wù),可能存在數(shù)據(jù)提交不一致的情況下;
- 如果我們不在spring去配置聲明式事務(wù),我們就需要在代碼中手動(dòng)配置事務(wù)!
- 事務(wù)在項(xiàng)目的開發(fā)中十分重要,設(shè)計(jì)到數(shù)據(jù)的一致性和完整性問題,不容馬虎!