javascript
Spring学习--基于狂神说
Spring官方中文文檔:https://www.docs4dev.com/docs/zh/spring-framework/5.1.3.RELEASE/reference/
1,spring(一個抽象的概念)
1.1 spring的maven地址
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc --> <dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>5.3.22</version> </dependency> <!--下面這個包是用來和mybatis整合--> <dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>5.3.22</version> </dependency>maven倉庫地址:https://mvnrepository.com/
2,IOC思想
? 讓對象可以動態的變化,不寫死。
? 通過一個set方法去給接口賦值
3,Spring項目搭建步驟
第一步:maven項目導入jar包
<dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>test</scope></dependency><!-- spring項目第一步導包 --><!--導入webmvc的包,可以自動的將一些其他spring包導入--><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>5.3.22</version></dependency><!--下面這個包是用來和mybatis整合--><dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>5.3.22</version></dependency></dependencies>第二步;創建xml文件(用來實例化對象)(對象==bean)(這是一個存放對象的容器)
<?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/beanshttps://www.springframework.org/schema/beans/spring-beans.xsd"><!--上面部分不變--><!-- 使用Spring來創建對象,在spring這些都稱為Beanjava中 類型 變量名 = new 類型();Hello hello = new Hello();spring中id = 變量名class = new 的對象property相當于給對象中的屬性設置一個值!--><bean id="userbean" class="pojo.User"/> <bean id="hello" class="pojo.HelloSpring">//創建對象并實例化<property name="name" value="Spring"/>//給對象屬性賦值<!--如果屬性字段是復合型(對象)則不用value,用ref=“另一個對象的bean ID”--><!--ref:引用spring容器(這個xml文件)中創建好的對象 value: 基本數據類型的值 --> <property name="user" ref="userbean"/></bean> </beans>第三步:測試(運行)
//獲取Spring的上下文對象//這句話是固定的,可變的是變量名和參數名,參數名就是需要的(容器)xml文件,可以傳多個 ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");//我們的對象現在都在Spring中管理,我們要使用,直接去里面取出來就可以Hello hello = (Hello)applicationContext.getBean("hello"); //getBean(String str):這個方法是在beans.xml中取對象,參數為對象的id思考:
- Hello對象是誰創建的? hello對象是由Spring創建的
- Hello對象的屬性是怎么設置的? hello對象的屬性是由Spring容器設置的 【這個過程叫控制反轉】
? 控制: 誰來控制對象的創建 , 傳統應用程序的對象是由程序本身控制創建的 , 使用Spring 后 , 對象是由Spring來創建的
? 反轉:程序本身不創建對象 , 而變成被動的接收對象
4,ioc(Spring)創建對象的方式:
**1,spring核心:get/set中的set方法,沒有set方法無法注入 **
2,正常創建對象是使用的無參構造方法創建對象
<bean id="userbean" class="pojo.User"/> <!--如果類沒有無參構造方法,則無法創建對象和實例化(會報錯)-->3,使用有參構造方法創建對象的方式:
<!--方式一:下標賦值--> <bean id="user" class="com.kuang.pojo.User"><constructor-arg index="0" value="caishan"/> <!--index:有參構造方法中,參數的索引位置 value:給這個參數賦的值--> </bean> <!--方式二:類型賦值 不建議使用(因為如果多個參數類型一致,則賦值會出錯) --> <bean id="user" class="com.kuang.pojo.User"><constructor-arg type="java.lang.String" value="caishan"/><!--根據有參構造方法的參數類型去賦值,String類的type是java.lang.String,其他就正常 (類這些除外)--> </bean> <!--方式三:直接參數名賦值 和property一樣的用法,引用對象用ref。只是改了標簽名--><bean id="user" class="com.kuang.pojo.User"><constructor-arg name="name" value="caishan"/></bean>總結:
1,spring創建對象,是在配置文件中bean時就被初始化。
2,如果有有參構造方法,則屬性通過property標簽進行賦值即可。如果沒有有參構造方法(代碼中只有有參構造方法)賊需要通過constructor-arg標簽對屬性進行賦值。
5,spring配置
5.1 alias標簽(別名)
<!--通過別名獲取對象,id叫user的bean 可以用abc來代替--> <alias name="user" alias="abc"/>5.2 Bean標簽的配置
<!--id: bean的唯一標識,對象名class: bean對象所對應的全限類名: 包名+類名name: 也是別名,而且name同時可以取多個別名,中間用空格,逗號分開都可以(比alias更高級)--><bean id="user" class="com.kuang.pojo.User" name="ab abc"><constructor-arg name="name" value="ppj"/></bean>5.3 import標簽
一般用于團隊開發,可以將多個配置文件,導入合并為一個
多人開發,不同的類需要注冊到不同的bean中,可以利用import將所有的beans.xml合并
applicationContext.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/beanshttps://www.springframework.org/schema/beans/spring-beans.xsd"><import resource="beans.xml"/><import resource="beans2.xml"/><import resource="beans3.xml"/>//導入了三個beans.xml容器//使用時直接利用總的xml文件,就可以使用全部的 </beans>6,DI依賴注入
- 依賴注入: set注入(重點)
- 依賴: bean對象的創建依賴于容器
- 注入: bean對象中的所有屬性,由容器來注入
要求被注入的屬性 , 必須有set方法 , set方法的方法名由set + 屬性首字母大寫 , 如果屬性是boolean類型 , 沒有set方法 , 是 is 。。。。
不同數據類型的set注入方式:
<?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/beanshttps://www.springframework.org/schema/beans/spring-beans.xsd"><!--上面部分不變--><bean id="adderss" class="pojo.Address"><property name="address" value="重慶"/></bean><!----><bean id="Student01" class="pojo.Student"><!--普通數據類型,直接使用value注入--><property name="name" value="蔡閃"/><!--其他類數據類型,用ref注入--><property name="address" ref="adderss"/><!--數組類型,在property標簽體內使用array標簽注入--><property name="books"><array><value>aaa</value><value>bbb</value><value>ccc</value></array></property><!--list集合類型,在property標簽體內使用list標簽注入--><property name="hobbys"><list><value>111</value><value>222</value><value>333</value></list></property><!--map集合類型,在property標簽體內使用map標簽注入--><property name="card"><map><entry key="ID" value="11223344"/></map></property><!--set集合類型,在property標簽體內使用set標簽注入--><property name="games"><set><value>qqqq</value></set></property><!--null類型,在property標簽體內使用null標簽注入--><property name="wife"><null/></property><!--Properties類型,在property標簽體內使用props標簽注入(有點像結構體)--><property name="info"><props><prop key="姓名">111</prop><prop key="性別">男</prop></props></property></bean> </beans>幾個注意點:
1,如果數據類型是值,則用value 。如果是對象之類的用ref
2,不變的是 這個部分,基本上都可以放在標簽體內部,只是普通的用起來方便
3,除了基礎的直接在標簽內部賦值外,其他的基本上都有自己的標簽體。
4,注意map集合,和Properties類型注入的特點
p標簽,c標簽注入
1,使用前,需要在頭文件前加入兩句話
xmlns:p="http://www.springframework.org/schema/p"<!--使用p標簽時導入,等價于property -->xmlns:c="http://www.springframework.org/schema/c"<!--使用c標簽時導入,等價于constructor-arg -->2,用法
<!-- p命名空間注入,直接在標簽體內部進行賦值,就相當于格式化--> <!--p:name="caishan" 等價于 <property name="name" value="caishan "/> --> <bean id="user" class="com.kuang.pojo.User" p:name="ppj" p:age="18"/><!-- c命名空間注入--> <bean id="user2" class="com.kuang.pojo.User" c:name="牛天成" c:age="18"/>3,Bean的作用域
1,單例模式(Spring默認機制)(scope=“singleton”)(只有一個對象)
<bean id="user2" class="com.kuang.pojo.User" c:name="牛天成" c:age="18" scope="singleton"/>2,原型模式(每次從容器中get的時候,都會產生一個新對象)(scope=“prototype”)
<bean id="user2" class="com.kuang.pojo.User" c:name="牛天成" c:age="18" scope="prototype"/>3,其余的request,session,application這些個只能在web開發中使用到
7,Bean的自動裝配
意義:可以不需要手動的給屬性賦值(一般用于有引用型屬性)
autowire字段選擇裝配方式
主要用于屬性是對象類型的時候
7,1 使用byName自動裝配(autowire=“byName”)
<!--byName: 會自動在容器上下文中查找,和自己對象set方法后面的值對應的bean的id屬性例:在該類中有一個People類的屬性和setPeople的方法,那么xml中有一個id為people(忽略大小寫)的bean,那么這個屬性就自動和id為people的bean綁定。--> <bean id="people" class="com.kuang.pojo.People" autowire="byName"><property name="name" value="ppj"/> </bean> <!--byName的時候,需要保證所有bean的id唯一-->7,2 使用byType自動裝配(autowire=“byType”)
<!-- byType: 會自動在容器上下文中查找, 和自己對象屬性類型相同的bean 例:在該類中有一個People類的屬性,那么xml中有一個類型為People類的bean,那么這個屬性就自動和class為People的bean綁定。 --> <bean id="people" class="com.kuang.pojo.People" autowire="byType"><property name="name" value="ppj"/> </bean> <!--byType的時候,需要保證所有bean的class唯一,使用byType可以不用寫id-->7,3 使用注解自動裝配
使用注解裝配,需要先導入context約束,context依賴
<!--在頭文件加入-->xmlns:context="http://www.springframework.org/schema/context" <!--**-->http://www.springframework.org/schema/context <!--**-->https://www.springframework.org/schema/context/spring-context.xsd <!--**--><context:annotation-config/>//導入自動裝配的依賴 </beans> 提前也要在spring中注冊 除非自動裝配的類也用注解進行了注冊注解加入的位置:
//可以加在屬性的頭上(注意:每一個屬性都自己加自己的)@Autowired(required = false)//如果定義@Autowired(required = false),說明這個對象可以為null,否則不允許為空(默認是true)private Cat cat;@Autowired//也可以不加后面的約束private Cat cat;//也可以直接加在set方法頭上 //也可以忽略set方法,前提是你這個自動裝配的屬性在IOC(Spring)容器中存在,且符合名字byName默認是通過byType (就是說如果用注解自動裝配可以不寫set方法但是要在spring中配置,否則不用配置)如果有多個同類的對象,則無法進行自動的綁定需要使用**@Qualifier(value = “綁定對象的ID名字”)**注解進行配套使用
<!--這是另一個配置注解,可以從byName,byType兩種方式去匹配--> @Resourceprivate Cat cat;@Nullable 屬性標記了這個注解,說明這個字段可以為null小結:
@Resource和@Autowired的區別:
都是用來自動裝配的,都可以放在屬性字段上
@Autowired通過byType的方式實現,而且必須要求這個對象存在 【常用】
@Resource默認通過byName的方式實現,如果找不到名字,則通過byType實現!如果兩個都找不到,就會報錯
不同:@Autowired通過byType的方式實現 @Resource默認通過byName的方式實現
8,注解開發
使用注解開發的第一步還是需要先導入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/beanshttps://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/context <!--**-->https://www.springframework.org/schema/context/spring-context.xsd"> <!--**--><!-- 區別是指定要掃描的包,包下所以類的注解就會生效--><context:component-scan base-package="包的全路徑"/><掃描包>// <context:annotation-config/>//導入的依賴 </beans>2,需要在指定包的每一個類上加上這個注解**@Component** :意思是該包的對象就在spring容器中被創建了。
該對象的名字為類名的首字母小寫形式,也可以在里面寫上想要的名字
@Component("注冊名") //等價于 <bean id="user" class="pojo.User"> public class User {<!--需要給對象的屬性賦值,則使用@Value("值")注解-->//等價于 <property name="name" value="ppj"/>@Value("ppj")private String name;}3, 衍生的注解
@Componet有幾個衍生注解,我們在web開發中,會按照mvc三層架構分層
dao [@Repository]
service [@Service]
controller 【@Controller】
這4個注解的功能都是一樣的(都等價于@Componet),都是代表將某個類注冊到Spring中,裝配Bean
4,自動裝配注解
@Resource
@Autowired
5,作用域注解
@Scope(“prototype”) [代表該類是單例模式]
6,總結
xml與注解
- xml更加萬能,適用于任何場合維護簡單方便
- 注解不是自己類使用不了 ,維護相對復雜!
最佳實踐:
- xml用來管理bean
- 注解只負責完成屬性的注入
- 在使用的過程中,只需要注意一個問題:必須讓注解生效,就需要開啟注解的支持,開啟包掃描
9,使用java的方式配置spring
其中一個方法就是一個bean對象
//@Configuration代表這是一個配置類,就和我們之前看的beans.xml是一樣的 @Configuration @ComponentScan("包名")//掃描包。等價于 <context:component-scan base-package="包的全路徑"/> @Import(配置類名.class)//類似將多個xml文件導成一個 public class MyConfig {//注冊一個bean,就相當于我們之前寫的一個bean標簽//這個方法的名字,就相當于bean標簽中的id屬性(對象名)//這個方法的返回值,就相當于bean標簽中的class屬性(類名)@Bean //等價于<bean id="getUser" class="com.XXX.User"/>public User getUser(){return new User(); //就是返回要注入到bean的對象} } //第二個配置類 @Configuration public class MyConfig2 { }調用時:獲取池子的方法有所改變
如果完全使用了配置類方式去做,我們就只能通過AnnotationConfigApplicationContext來獲取容器,括號里面寫這個配置類的類名.class
public class MyTest {@Testpublic void test(){//如果完全使用了配置類方式去做,我們就只能通過AnnotationConfigApplicationContext來獲取容器,通過配置類的class對象加載ApplicationContext context = new AnnotationConfigApplicationContext(類名.class);User user = context.getBean("getUser", User.class);System.out.println(user);} }這種純java的配置方式,在springboot中隨處可見!
10,代理模式
注意:一個代理只能對應一個接口
10,1靜態代理模式:
代理模式的意義是:為了不改動原有代碼【滿足開放封閉-原則】
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-xQ18q3qK-1668096073684)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20220729125335472.png)]
角色分析:
- 抽象角色: 一般會使用接口或者抽象類類解決(房子)(接口類)
- 真實角色:被代理的角色(房東)(實現類)
- 代理角色: 代理真實角色,代理真實角色后,我們一般會做一些附屬操作(代理)(調實現類的方法)
- 客戶:訪問代理對象的人(租客)
代碼步驟:
? 抽象角色:
//房子 public interface Room {//租房public void Rent(); }? 真實角色:
//房東 public class Host implements Room {@Overridepublic void Rent() {System.out.println("我要出租房子");} }? 代理角色:(繼承接口)
//代理 public class Proxy {private Host host;public Proxy() {}//客戶找代理時,指定需要哪一個房東的房子public Proxy(Host host) {this.host = host;}public void Rent() {//租房host.Rent();Money();}//代理負責收租private void Money(){System.out.println("代理收租");} }? 租客:
//租客 public class Me {public static void main(String[] args) {Host host=new Host();//找到代理,告訴他我要租誰的房子Proxy proxy=new Proxy(host);//進行租房proxy.Rent();} }代理模式的好處:
缺點:
- 一個真實角色就會產生一個代理角色;代碼量會翻倍===開發效率變低(靜態代理只允許,一個房東一個代理)
10,2案例二
業務接口:(接口)
public interface UserService {/*需求: 在不修改原代碼的情況下,添加日志打印信息*/public void add();public void delete();public void update();public void query();}真實業務:(實現類)
public class UserServiceImpl implements UserService{@Overridepublic void add() {System.out.println("add方法");}@Overridepublic void delete() {System.out.println("delete方法");}@Overridepublic void update() {System.out.println("update方法");}@Overridepublic void query() {System.out.println("query方法");} }需求:在不改變原有代碼的基礎上,實現日志打印,借助代理
public class UserServiceProxy implements UserService{@Overridepublic void add() {log("add");System.out.println("add===");}@Overridepublic void delete() {log("delete");System.out.println("delete===");}@Overridepublic void update() {log("update");System.out.println("update=====");}@Overridepublic void query() {log("query");System.out.println("query=====");}public void log(String msg){System.out.println("[DEBUG]"+msg+"方法執行");} }測試:
public static void main(String[] args) {UserServiceProxy userServiceProxy = new UserServiceProxy();userServiceProxy.add();}直接用代理對象實現同樣的業務接口,打印日志信息,而不觸及到原代碼
10,3動態代理
動態代理和靜態代理角色一樣
動態代理的代理類是動態生成的,不是我們直接寫好的
動態代理分為兩大類:基于接口的動態代理,基于類的動態代理
基于接口----JDK動態代理
基于類: cglib
java字節碼實現: javassit
需要了解2個類:Proxy===代理, InvocationHandler:調用處理程序(接口)
InvocationHandler
Proxy
動態代理的好處:
可以使真實角色的操作更加純粹!不用去關注一些公共的業務
公共也就交給代理角色!實現業務的分工
公共業務發生擴展的時候,方便集中管理
一個動態代理類代理的是一個接口,一般就是對應的一類業務
一個動態代理類可以代理多個類,只要是實現了同一個接口即可
直接動態代理常用工具類(基于接口:JDK動態代理)
可以直接封裝,使用
public class ProxyInvocationHandler implements InvocationHandler{private Object target;//需要代理的接口(object可以是具體的接口名,target可以是任意名字)public void SetTarget(Object target){this.target=target;}//得到生成的代理類public Object getProxy(){return Proxy.newProxyInstance(this.getClass().getClassLoader(),target.getClass.getInterfaces,this);}//處理代理實例,返回結果(處理客戶端選擇執行的方法)//Method:方法 Object[]:應該是參數 Proxy:代理類public Object invoke(Object Proxy,Method method,Object[] args)throws Throwable{//其他代理類額外添加的方法,寫在這里面Object result =method.invoke(target,args);//執行選擇的方法return result;} }調用:
public Static void main(String[] args){ //創建真實角色(這一步沒變) UserServiceImpl userService=new UserServiceImpl(); //創建代理角色 ProxyInvocationHandLer pih =new ProxyInvocationHandLer();//調用之前的自動生成代理類方法 pih.setTarget(userService);//將需要代理的真實角色傳遞給他 UserService proxy=(UserService)pih.getProxy();//創建代理類(UserService:接口名) proxy.query();//利用該代理類調用方法 }11,AOP(動態代理)(核心還是反射)
提供聲明式事務;允許用戶自定義切面
橫切關注點:跨越應用程序多個模塊的方法或功能。即是,與我們業務邏輯無關的,但是我們需要關注的部分,就是橫切關注點。如日志 , 安全 , 緩存 , 事務等等 …(用AOP插入的情況)
切面(ASPECT):橫切關注點 被模塊化 的特殊對象。即,它是一個類。
通知(Advice):切面必須要完成的工作。即,它是類中的一個方法。
目標(Target):被通知對象。
代理(Proxy):向目標對象應用通知之后創建的對象。
切入點(PointCut):執行方法的位置
連接點(JointPoint):與切入點匹配的執行點。
SpringAOP中,通過Advice定義橫切邏輯,Spring中支持5種類型的Advice:
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-aiSxyMag-1668096073686)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20220729161213739.png)]
即AOP在不改變原有代碼的情況下,去增加新的功能
使用AOP置入,需要導入一個依賴包[重點]
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver --> <dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.9.8</version><scope>runtime</scope> </dependency>實現AOP的第一種方式:(API接口)
1,編寫業務接口和實現類
public interface UserService {public void add();public void delete();public void update();public void select(); }public class UserServiceImpl implements UserService{@Overridepublic void add() {System.out.println("add方法。。。");}@Overridepublic void delete() {System.out.println("delete方法。。。");}@Overridepublic void update() {System.out.println("update方法。。。");}@Overridepublic void select() {System.out.println("select方法。。。");} }2,編寫增強類,后置和前置增強(Advisor)[繼承不同的接口]
//MethodBeforeAdvice:前置增強 public class BeforeLog implements MethodBeforeAdvice {//method: 要執行目標對象的方法//args: 被調用方法的參數//target: 目標對象@Overridepublic void before(Method method, Object[] args, Object target) throws Throwable {System.out.println(target.getClass().getName()+"執行了"+method.getName()+"方法");} } //AfterReturningAdvice:后置增強 public class AfterLog implements AfterReturningAdvice {//returnValue 返回值@Overridepublic void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {System.out.println(target.getClass().getName()+"執行了"+method.getName()+"方法"+returnValue);} }3,將這些類注冊到Spring容器中,并實現aop切入,導入aop約束
<?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:aop="http://www.springframework.org/schema/aop"//導入的xsi:schemaLocation="http://www.springframework.org/schema/beanshttps://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/aop//導入的https://www.springframework.org/schema/aop/spring-aop.xsd//導入的 "><bean id="userService" class="com.kuang.service.UserServiceImpl"/><bean id="beforeLog" class="com.kuang.log.BeforeLog"/><bean id="afterLog" class="com.kuang.log.AfterLog"/><!-- AOP配置 --><aop:config><!-- 配置切入點 expression:是一個表達式--> <aop:pointcut id="pointcut" //這個名字可以隨便取 expression="execution(* com.kuang.service.UserServiceImpl.*(..))"/>//固定寫法execution(* 哪一個類.*全部方法(..)//代表多個參數)<!-- 執行環繞 advice-ref執行方法 . pointcut-ref切入點--><aop:advisor advice-ref="beforeLog" pointcut-ref="pointcut"/><aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/></aop:config>//aop:config 標簽的完整意思:在UserServiceImpl這個實現類的所有方法中配置切入點,然后在執行這些方法時執行advice-ref定義的方法 </beans>4.測試
public class MyTest {public static void main(String[] args) { ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");//動態代理的是接口,雖然綁定的對象是一個接口的實現類,但是返回值還是一個接口UserService userService = (UserService) context.getBean("userService");userService.delete();} }實現AOP的第二種方式:(自定義類)
1,將之前的增強類變為一個普通類,里面寫多個方法
public class MyAspect {//方法就是之前的各種增強類,名字隨便起public void before(){System.out.println("before通知=====");}public void after(){System.out.println("after通知=======");} }2,在spring中配置
<!-- 方式二: 自定義切面類 --><bean id="myAspect" class="com.kuang.def.MyAspect"/><aop:config><!--aspect:自定義切面 ref要引用的類 -->//自定義方法必須用aop:aspect這個標簽<aop:aspect ref="myAspect"><!-- 切入點 --> <aop:pointcut id="pointcut" expression="execution(* com.kuang.service.UserServiceImpl.*(..))"/><!-- 通知(要切入的方法) --><aop:before method="before" pointcut-ref="pointcut"/>//我要切入ref這個類中的before()方法,在pointcut指定的切入點切入,什么時候切入?aop:before的時候<aop:after method="after" pointcut-ref="pointcut"/></aop:aspect></aop:config>3,測試
public class MyTest {public static void main(String[] args) {ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");//動態代理的是接口UserService userService = (UserService) context.getBean("userService");userService.delete();} }實現AOP的第三種方式:(注解實現)
不需要導入注解的約束【因為不是用注解寫對象】
只需要導入aop相關約束即可
在xml中需要新增一個標簽
開啟注解支持 <aop:aspectj-autoproxy/> @Aspect //標注這個類是一個切面 public class AnnotationAspect {//前置通知 @Before("execution(* com.kuang.service.UserServiceImpl.*(..))") public void before(){System.out.println("執行方法前===="); }//后置通知 @After("execution(* com.kuang.service.UserServiceImpl.*(..))") public void after(){System.out.println("執行方法后====="); }//環繞通知 @Around("execution(* com.kuang.service.UserServiceImpl.*(..))") public void around(ProceedingJoinPoint jp) throws Throwable {System.out.println("環繞前=====");jp.proceed(); //執行方法System.out.println("環繞后====="); } }12,整合mybatis
mybatis是寫接口,寫mapper.xml文件,寫SQL
Spring就是萬物皆對象,每一個類都是一個對象,在beans.xml中實例化之后才可以使用
步驟:
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-Y0VBwCly-1668096073686)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20220729180248262.png)]
導入相關jar包
-
junit
-
mybatis
-
mysql
-
spring
-
AOP
-
spring-jdbc【新的】
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-8PNVdPOm-1668096073687)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20220729180039423.png)]
-
mybatis-spring【新的】
-
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-4u8MewxF-1668096073687)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20220729180200901.png)]
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-KyK3Ymev-1668096073687)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20220729175925321.png)]
1,編寫配置文件
2,測試
12.1 回顧mybatis
12.2 整合mybatis方式一
利用SqlSessionTemplate。
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-MJKEh0Il-1668096073688)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20220730135529798.png)]
第一步:編寫數據源
在spring的配置文件中編寫以下代碼
<!-- DataSource:使用Spring的數據源替換mybatis的配置 c3p0 dbcp druid這里使用spring提供的jdbc: org.springframework.jdbc.datasource--><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?serverTimezone=UTC&useUnicode=true&characterEncoding=utf8&useSSL=false"/><property name="username" value="root"/><property name="password" value="123456"/></bean>第二步:創建SqlSessionFatory對象
<!-- 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/kuang/mapper/*.xml"/>//意思是:相當于綁定注冊,綁定com/kuang/mapper/*.xml這個路徑下的所有Mapper.xml</bean>第三步:創建sqlsession對象(在spring中叫sqlSessionTemplate)
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate"><!-- 只能用有參構造器注入sqlSessionFactory 因為它沒有set方法 --><constructor-arg ref="sqlSessionFactory"/> </bean> //第二,第三步相當于之前寫的mybatis工具類如何使用?
1,需要給接口加實現類
在原來mybatis的基礎上給mapper接口添加實現類(實現類去實現具體的調用步驟)
public class UserMapperImpl implements UserMapper {private SqlSessionTemplate sqlSession;//在實現類中定義一個SqlSessionTemplate對象public void setSqlSession(SqlSessionTemplate sqlSession) {//需要寫一個set方法,一會方便在beans.xml中進行注入this.sqlSession = sqlSession;}@Override//這就是類似指定調用的SQL語句public List<User> selectUser() {UserMapper mapper = sqlSession.getMapper(UserMapper.class);//還是需要映射一個接口的對象調用方法執行SQLList<User> userList = mapper.selectUser();//執行SQLreturn userList;} }2,將自己寫的實現類,注入到spring中(創建一個實現類的對象)
<!-- 總的spring配置文件 --> <bean id="UserMapperImpl" class="com.kuang.mapper.UserMapperImpl"><property name="sqlSession" ref="sqlSession"/>//將SQLsession對象注入 </bean>3,測試
public class MyTest {public static void main(String[] args) {ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");UserMapper userMapper = context.getBean("userMapper", UserMapper.class);for (User user : userMapper.selectUser()) {System.out.println(user);}} }遇見的錯誤
mybatis-config.xml里的mappers 要刪了, 這個和 spring-dao的 <property name="mapperLocations"value="classpath:com/lzh/mapper/*.xml"/> 只能二選一!!!!!!不然會報錯的,都是mapper的作用!12.3 整合mybatis方式二
利用繼承SqlSessionDaoSupport
兩個點:不用再配置sqlsession對象,實現類繼承
在實現類中寫:
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-8cxGvJ2s-1668096073688)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20220730162524102.png)]
在beans.xml中寫
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-4nTgsIUz-1668096073688)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20220730162708466.png)]
相當于省略了beans.xml中配置sqlsession的步驟
13,事務
spring中的事務管理分為
- 聲明式事務:AOP(不影響原有代碼)
- 編程式事務:需要在代碼中進行配置管理
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-XjhFgLkD-1668096073689)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20220730170603636.png)]
步驟:
1,配置聲明式事務(開啟事務管理器)
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> <!--這是死代碼 ,dataSource:數據源-->2,結合AOP實現事務的織入
<!--1, 導入事務的約束 (頭文件處)--> //注意aop的約束也要導入 <?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:tx="http://www.springframework.org/schema/tx"//導入的xsi:schemaLocation="http://www.springframework.org/schema/beanshttps://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/tx//導入的https://www.springframework.org/schema/tx/spring-tx.xsd //導入的 "><!--2, 配置事務通知(方法) --><!-- transactionManager步驟一所配置的bean --><tx:advice id="txAdvice" transaction-manager="transactionManager"><!-- 給哪些方法配置事務 --><!-- 配置事務的傳播特性: propagation=“required” spring默認事務 --><tx:attributes><tx:method name="add" propagation="REQUIRED"/>//所有add方法配置事務意思是:給所有的add方法配置REQUIRED類型的事務<tx:method name="delete" propagation="REQUIRED"/>//所有delete方法配置事務<tx:method name="query" read-only="true"/>//read-only表示query類的事務無法對數據庫進行增刪改<tx:method name="*"/>//所有方法配置事務</tx:attributes></tx:advice><!--3,配置事務切入(切入點) --><aop:config><aop:pointcut id="txPoint" expression="execution(* com.kuang.mapper.*.*(..))"/>切入點<aop:advisor advice-ref="txAdvice" pointcut-ref="txPoint"/>//切入的方法</aop:config>AOP:切面,通知,切入點
為什么需要事務?
- 如果不配置事務,可能存在數據提交不一致的情況下
- 如果我們不在spring中去配置聲明式事務,我們就需要在代碼中手動配置事務
- 事務在項目開發中重要,設計到數據的一致性和完整性問題,不容馬虎
總結
以上是生活随笔為你收集整理的Spring学习--基于狂神说的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 新版正方教务管理系统API(获取课程表,
- 下一篇: MacW资讯:微软确认没有启动Mac版O