1.Spring
寫在前面:歡迎來到「發奮的小張」的博客。我是小張,一名普通的在校大學生。在學習之餘,用博客來記錄我學習過程中的點點滴滴,也希望我的博客能夠更給同樣熱愛學習熱愛技術的你們帶來收穫!希望大家多多關照,我們一起成長一起進步。也希望大家多多支持我鴨,喜歡我就給我一個關注吧!
文章目錄
1.簡介
- Spring:春天---->給軟件行業帶來了春天
- 2002,首次退出了Spring框架的雛形:interface21框架!
- Spring框架即以interface21框架爲基礎,經過重新設計,並不斷豐富其內涵,於2004年3月24日,發佈了1.0正式版。
- Rod Johnson,Spring Framework創始人,著名作者。很難想象Rod Johnson的學歷,真的讓好多人大喫一驚,他是悉尼大學的博士,然而他的專業不是計算機,而是音樂學。
- Spring理念:使現有的技術更加容易使用,本身是一個複雜的綜合性框架。
- SSH:Struct2+Spring+Hibernate!
- SSM:SpringMVC+Spring+Mybatis!
官方文檔:https://docs.spring.io/spring/docs/5.2.0.RELEASE/spring-framework-reference/core.html#spring-core
官網: https://spring.io/projects/spring-framework#overview
官方下載地址: http://repo.spring.io/release/org/springframework/spring
GitHub: https://github.com/spring-projects/spring-framework
2.優點
- Spring是一個開源的免費的框架(容器)。
- Spring是一個輕量級的、非入侵式的框架!
- IOC控制反轉,AOP面向切面編程。
- 支持事務的處理,對框架的整合支持!
總結一句話:Spring就是一個輕量級的IOC(控制反轉),AOP(面向切面編程)的框架!
3.組成
4.拓展
-
Spring Boot
- 一個快速開發的腳手架
- 基於SpringBoot可以快速的開發單個微服務
- 約定大於配置!
-
Spring Cloud
- SpringCloud是基於SpringBoot實現的
因爲現在大多數公司都在使用SpringBoot進行開發,學習SpringBoot的前提,掌握Spring,及SpringMVC!承上啓下的作用!
弊端:發展太久,違背了原來的理念。配置十分繁瑣,人稱:“配置地獄”
2.IOC理論推導
- UserDao接口
- UserDaoImpl實現類
- UserService業務接口
- UserServiceImpl業務實現類
在我們之前的業務中,用戶的需求可能會影響原來代碼。我們需要根據用戶需求修改原代碼。如果程序代碼量十分大,修改一次的成本十分昂貴!
我們使用一個set接口實現。已經發生了革命性得變革!
private UserDao userDao;
//利用set實現動態值得注入
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public static void main(String[] args) {
UserService service = new UserServiceImpl();
((UserServiceImpl)service).setUserDao(new UserOracleImpl());
service.getUser();
}
- 之前程序是主動創建對象!控制權在程序員手上!
- 使用了set注入後,程序不再具有主動性,變成了被動接受對象!
這種思想從本質上解決了問題,我們不需要管理對象的創建,耦合性大大降低,可以專注在業務實現上!這就是IOC原型!
3.I0C本質
控制反轉loC(Inversion of Control),是-種設計思想,DI(依賴注入)是實現IoC的-種方法,也有人認爲DI只是IoC的另一種說法。沒有IoC的程序中,我們使用面向對象編程, 對象的創建與對象間的依賴關係完全硬編碼在程序中,對象的創建由程序自己控制,控制反轉後將對象的創建轉移給第三方,個人認爲所謂控制反轉就是:獲得依賴對象的方式反轉了。
採用XML方式配置Bean的時候,Bean的定義信息是和實現分離的,而採用註解的方式可以把兩者合爲一體,Bean的定義信息直接以註解的形式定義在實現類中,從而達到了零配置的目的。
控制反轉是一種通過描述(XML或註解)並通過第三方去生產或獲取特定對象的方式。在Spring中實現控制反
轉的是IoC容器,其實現方法是依賴注入(Dependency Injection,DI)。
4.第一個HelloSpring程序
環境:
- idea集成工具
- Maven倉庫
搭建步驟:
- 新建一個空白的Maven工程
接着自定義一個groupid和artifactid
點擊下一步就創建完成
此時的項目結構爲下圖:
-
Maven依賴文件
配置pom.xml:
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.2.0.RELEASE</version> </dependency> <!--https://mvnrepository.com/artifact/org. springframework/spring-webmvc--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.2.0.RELEASE</version> </dependency>
-
編寫實現類
package com.zhang.pojo; public class Hello { private String str; public String getStr() { return str; } public void setStr(String str) { this.str = str; } @Override public String toString() { return "Hello{" + "str='" + str + '\'' + '}'; } }
-
配置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" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd"> <!--使用Spring來創建對象,在Spring這些都稱爲Bean bean=對象 new Hello() 類型 變量名 = new 類型() id = 變量名 class = new 的對象 property 相當於給對象屬性設值 --> <bean id="hello" class="com.zhang.pojo.Hello"> <property name="str" value="Spring"/> </bean> </beans>
此時的項目結構爲下圖:
-
測試
public static void main(String[] args) { //獲取Spring的上下文對象 ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml"); //我們的對象現在都在Spring中管理,要使用,直接取出來 Hello hello = (Hello) context.getBean("hello"); System.out.println(hello); }
思考問題?
●Hello對象是誰創建的?
hello對象是由Spring創建的
●Hello 對象的屬性是怎麼設置的?
hello對象的屬性是由Spring容器設置的,
這個過程就叫控制反轉:
**控制:**誰來控制對象的創建,傳統應用程序的對象是由程序本身控制創建的,使用Spring後,對象是由Spring來創
建的.
**反轉:**程序本身不創建對象,而變成被動的接收對象.
**依賴注入:**就是利用set方法來進行注入的.
**I0C是一種編程思想,**由主動的編程變成被動的接收.可以通過newClassPathXmlApplicationContext去瀏覽一下底層源碼 .
OK ,到了現在,我們徹底不用再程序中去改動了,要實現不同的操作,只需要在xml配置文件中進行修改,所謂的
IoC,-句話搞定:對象由Spring來創建,管理, 裝配!
5.IOC創建對象的方式
在獲取容器的時候就已經將配置文件beans.xml中的bean註冊對象創建完畢
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
-
使用無參構造創建對象,默認實現
-
假設我們要是有有參構造實現
-
下標賦值
<!--有參構造方法 1.下標賦值 --> <bean id="user" class="com.zhang.pojo.User"> <constructor-arg index="0" value="這是一個姓名"/> </bean>
-
參數類型
<!--2.通過參數類型創建有參構造 不建議使用 --> <bean id="user" class="com.zhang.pojo.User"> <constructor-arg type="java.lang.String" value="這是一個名字"/> </bean>
-
參數名類型(掌握)
<!--3.通過參數名創建有參構造--> <bean id="user" class="com.zhang.pojo.User"> <constructor-arg name="name" value="ahah"/> </bean>
-
6.Spring配置
6.1別名
<!--別名,如果添加了別名,我們可以使用別名獲取這個對象
注意:原id仍然有效
-->
<alias name="user" alias="user2"/>
6.2Bean的配置
<!--
id : bean 的唯一標識,相當於對象名
class : bean 對象所對應的全限定名 : 包名 + 類名
name : 也是別名,而且name 可以同時取多個別名
-->
<bean id="user1" class="com.zhang.pojo.User" name="user3,u1">
<constructor-arg name="name" value="sss"/>
</bean>
6.3import
這個import,一般用於團隊開發使用,它可以將多個配置文件合併爲一個。
假設現在項目有多個人開發,這三個人負責不同的類開發。不同的類需要註冊在不同的beans中。我們可以用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/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<import resource="beans.xml"/>
<import resource="beans1.xml"/>
</beans>
此時的配置文件如下如:
7.DI依賴注入
7.1構造器注入
前面p5已經說了
###7.2Set方式注入【重點】
-
依賴注入:Set注入!
- 依賴:bean對象的創建依賴於容器
- 注入:bean對象中的所有屬性由容器來注入
【環境搭建】
1.複雜類型
public class Address {
private String address;
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
2.真實測試對象
```java
public class Student {
private String name;
private Address address;
private String[] book;
private List<String> hobbys;
private Map<String,String> card;
private Set<String> games;
private String wife;
private Properties info;
}
3.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/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="student" class="com.zhang.pojo.Student">
<!--方式一:普通值注入,value-->
<property name="name" value="晶瑩"/>
</bean>
</beans>
4.測試類
public class MyTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Student student = (Student) context.getBean("student");
System.out.println(student);
}
}
完善注入信息
<bean id="address" class="com.zhang.pojo.Address">
<property name="address" value="武漢"/>
</bean>
<bean id="student" class="com.zhang.pojo.Student">
<!--方式一:普通值注入,value-->
<property name="name" value="晶瑩"/>
<!-- 第二種: Bean注入,value -->
<property name="address" ref="address"/>
<!-- 數組注入 ref -->
<property name="book">
<array>
<value>紅樓夢</value>
<value>西遊記</value>
<value>水滸傳</value>
<value>三國演義</value>
</array>
</property>
<!-- list注入 ref -->
<property name="hobbys">
<list>
<value>聽歌</value>
<value>編程</value>
<value>看劇</value>
</list>
</property>
<!-- Map注入 ref -->
<property name="card">
<map>
<entry key="身份徵" value="123456789012345678"/>
<entry key="銀行卡" value="123456789012345678"/>
</map>
</property>
<!-- Set注入 -->
<property name="games">
<set>
<value>LOL</value>
<value>CF</value>
</set>
</property>
<!-- null值注入 -->
<property name="wife">
<null></null>
</property>
<!-- Properties注入 -->
<property name="info">
<props>
<prop key="driver">mysql</prop>
<prop key="url">http:/sss</prop>
<prop key="username">root</prop>
<prop key="password">root</prop>
</props>
</property>
</bean>
7.3拓展方式注入
我們可以使用p命名空間,或者是c命名空間進行注入
官方解釋如下圖:
使用c或者p命名空間,需要先導兩個標籤
p和c的命名空間標籤約束
xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
使用
<?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:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- p命名空間注入 可以直接注入屬性的值 -->
<bean id="user" class="com.zhang.pojo.User" p:name="哈哈" p:age="16"/>
<!-- c命名空間注入, 可以通過構造器注入 construct-args-->
<bean id="user2" class="com.zhang.pojo.User" c:age="18" c:name="弟弟"/>
</beans>
測試:
@Test
public void test2(){
ApplicationContext context = new ClassPathXmlApplicationContext("userbeans.xml");
User user = context.getBean("user2", User.class);
System.out.println(user);
}
注意點:p和c命名空間不能直接使用,需要導入xml約束
7.4bean的作用域
官方原文:
翻譯後:
1.單例模式(spring默認機制)
每次從容器中取出bean,都是同一個對象
<bean id="user2" class="com.zhang.pojo.User" c:age="18" c:name="弟弟" scope="singleton"/>
2.原型模式
每次從容器中取出bean,都是一個新的對象
<bean id="user2" class="com.zhang.pojo.User" c:age="18" c:name="弟弟" scope="prototype"/>
3.其餘request,session,application,只能在web開發中使用!
8.bean的自動裝配
- 自動裝配是Spring滿足bean依賴的一種方式!
- Spring會在上下文中自動尋找,並自動給bean裝配屬性!
在Spring中有三種自動裝配的方式
- 在xml中顯示配置
- 在Java中顯示配置
- 隱式 的自動裝配bean【重要】
8.1測試
ByName自動裝配
<!--
byName : 會自動在容器上下文中查找,有沒有和id對應的set方法
-->
<bean id="people" class="com.zhang.pojo.People" autowire="byName">
<property name="name" value="大俠"/>
</bean>
ByType自動裝配
<bean id="cat" class="com.zhang.pojo.Cat"/>
<bean id="dog11" class="com.zhang.pojo.Dog"/>
<!--
byName : 會自動在容器上下文中查找,有沒有和id對應方法的bean
byType : 會自動在容器上下文中查找,有沒有和class類型對應的bean
-->
<bean id="people" class="com.zhang.pojo.People" autowire="byType">
<property name="name" value="大俠"/>
</bean>
小結:byname的時候,需要保證所有的bean的id唯一,並且這個bean需要和自動注入的屬性的set方法一致!
bytype的時候,需要保證所有的bean的class唯一,並且這個bean需要和自動注入的屬性類型一致!
8.2使用註解自動裝配
jdk1.5支持註解,Spring2.5就支持註解!
要使用註解須知:
xmlns:context=“http://www.springframework.org/schema/context”
<context:annotation-config/>
<?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/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>
@Autowried
直接在屬性上使用即可!也可以在set方式上使用!
使用Autowried我們可以不用編寫set方法,前提是你這個自動裝配的屬性在IOC容器中存在且符合名字byname!
科普:
@Nullable 字段標記了這個註解,說明這個字段可以爲null
測試代碼:
//如果顯示定義了Autowried的required屬性爲false,說明這個對象可以爲null,否則不允許爲空
@Autowired(required = false)
private Cat cat;
@Autowired
private Dog dog;
如果@Autowired自動裝配的環境比較複雜,自動裝配無法通過一個註解【@Autowired】完成時,我們可以使用@Qualifier(value = “xxx”)p配合@Autowired使用,指定唯一的bean注入!
@Autowired
@Qualifier(value = "cat22")
private Cat cat;
@Autowired
@Qualifier(value = "dog22")
private Dog dog;
private String name;
<bean id="cat" class="com.zhang.pojo.Cat"/>
<bean id="cat22" class="com.zhang.pojo.Cat"/>
<bean id="dog" class="com.zhang.pojo.Dog"/>
<bean id="dog22" class="com.zhang.pojo.Dog"/>
<bean id="people" class="com.zhang.pojo.People"/>
@Resource註解
public class People {
@Resource(name = "cat22")
private Cat cat;
@Resource
private Dog dog;
小結:
@Autowried和**@Resource註解**的區別:
-
都是自動裝配使用
-
@Autowried通過bytype方式實現【常用】
-
@Resource默認通過byname方式,如果找不到就通過bytype,如果都找不到,就報錯!【常用】
9.使用註解開發
在Spring4之後,要使用註解開發,必須要保證aop包導入!
在idea右上角查看自己的maven倉庫,看看依賴是否導入!
使用註解需要導入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/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>
1.bean
2.屬性如何注入
//等價於 <bean id="user" class="com.zhang.pojo.User"/>
//@Component 組件 裝配的id爲類名小寫
@Component
public class User {
//相當於<property name = "name" value="哈哈哈哈"/>
@Value("哈哈哈哈")
public String name;
}
//等價於 <bean id="user" class="com.zhang.pojo.User"/>
//@Component 組件
@Component
public class User {
//相當於<property name = "name" value="哈哈哈哈"/>
// @Value("哈哈哈哈")
public String name;
//相當於<property name = "name" value="哈哈哈哈"/>
@Value("哈哈哈哈")
public void setName(String name) {
this.name = name;
}
}
測試:
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
User user = context.getBean("user", User.class);
System.out.println(user.name);
}
3.衍生的註解
@Component有幾個衍生註解(下面三個註解功能和@Component一樣),在web開發中,會按照mvc三層架構分層。
dao【@Repository】
service【@Service】
controller【@Controller】
@Component,@Repository,@Service,@Controller這四個註解功能一樣,都是將某個類註冊到spring,裝配到bean中
4.自動裝配
-@Autowired :自動裝配,通過類型,名字
如果Autowired不能唯一自動裝配,我們可以使用@Qualifier(value = "xxx")p配合@Autowired使用,指定唯一的bean注入!
-@Resource : 自動裝配,通過名字,類型
-@Nullable 字段標記了這個註解,說明這個字段可以爲null
5.作用域
單例
@Component
@Scope("singleton")//單例
public class User {
}
6.小結
xml與註解:
xml更萬能,使用任何場合
註解不是自己的類使用不了,維護相對複雜!
xml與註解的最佳實踐:
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"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
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
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 指定要掃描的包,這個包下的註解就會生效 -->
<context:component-scan base-package="com.zhang"/>
<!-- 開啓註解支持 -->
<context:annotation-config/>
</beans>
10.使用java的方式配置Spring
我們現在要完全不使用Spring的xml配置,全權交給java來做
JavaConfig是Spring的一個子項目,Spring4之後,他成爲了一個核心功能!
配置類
package com.zhang.config;
import com.zhang.pojo.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
//這是一個配置類,和beans.xml一樣
//他會被註冊到spring容器中,他本來也是一個Component
@Configuration
@ComponentScan("com.zhang.pojo")
@Import(ZhangConfig2.class)
public class ZhangConfig {
//註冊一個bean,就相當於之前寫的一個bean標籤
//這個方法的名字,就相當於bean標籤中的id
@Bean
public User user(){
return new User();//返回要注入的對象
}
}
實體類
package com.zhang.pojo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
//註解,說明這個類被spring註冊到容器中
@Component
public class User {
private String name;
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
'}';
}
public String getName() {
return name;
}
@Value("王老五")
public void setName(String name) {
this.name = name;
}
}
測試類
public class MyTest {
public static void main(String[] args) {
//如果完全使用了配置類方式,我們就只能通過AnnotationConfigApplicationContext上下文來獲取容器,通過class類加載
ApplicationContext context = new AnnotationConfigApplicationContext(ZhangConfig.class);
User user = (User) context.getBean("user");
System.out.println(user);
}
}
這種純java的配置方式,在SpringBoot中隨處可見!
11.代理模式
爲什麼要學代理模式?
因爲這就是springAOP的底層!【SpringAOP】【SpringMVC】
代理模式分類
- 靜態代理
- 動態代理
11.1靜態代理
角色分析:
- 抽象角色:一般會使用接口或着抽象類實現
- 真實角色:被代理的角色
- 代理角色:代理真實角色,代理後一般會做一些附屬操作
- 客戶:訪問代理對象的人
代碼步驟:
1.接口
//租房
public interface Rent {
public void rent();
}
2.真實角色
//房東
public class Host implements Rent {
@Override
public void rent() {
System.out.println("房東要出租房!");
}
}
3.代理角色
public class Proxy implements Rent {
private Host host;
public Proxy() {
}
public Proxy(Host host) {
this.host = host;
}
@Override
public void rent() {
setHouse();
host.rent();
hetong();
fare();
}
public void setHouse(){
System.out.println("中介帶你看房!");
}
public void fare(){
System.out.println("收中介費!");
}
public void hetong(){
System.out.println("籤租賃合同");
}
}
4.客戶端訪問代理角色
ic class Cilent {
public static void main(String[] args) {
Host host=new Host();
host.rent();
//代理,代理一半會有一些附屬操作
Proxy proxy = new Proxy(host);
proxy.rent();
}
代理模式好處:
- 可以是真實角色的操作更加存粹。不再關注公共的業務
- 公共業務就交給了代理,實現業務分工
- 公共業務發生擴展的時候。方便集中管理!
缺點:
一個真實角色產生一個代理角色,類爆炸!
聊聊aop:面向切面編程
11.2動態代理
動態代理和靜態代理角色一樣
動態代理的類是動態生成的,不是我們直接寫好的
動態代理分爲兩大類:基於接口的動態代理,基於類的動態代理
- 基於接口:JDK動態代理【我們在這裏使用這個】
- 基於類:cglib
- java字節碼實現:javasist
需要了解兩個類:Proxy:代理,InvocationHandler:調用處理
動態代理的模板:
package com.zhang.demo04;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
//我們用這個類生成代理
public class ProxyInvocationHandler implements InvocationHandler {
//被代理的接口
private Object target;
public void setTarget(Object target) {
this.target = target;
}
//生成得到代理類
public Object getProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
}
//處理代理實例並返回結果
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//動態代理的本質,就是使用反射
Object result = method.invoke(target, args);
return result;
}
}
測試:
public class Client {
public static void main(String[] args) {
//真實角色
UserServiceImpl service = new UserServiceImpl();
//代理角色,不存在
ProxyInvocationHandler pih = new ProxyInvocationHandler();
//設置代理對象
pih.setTarget(service);
//動態生成獲取代理角色
UserService proxy = (UserService) pih.getProxy();
proxy.add();
}
}
動態代理好處:
- 可以是真實角色的操作更加存粹。不再關注公共的業務
- 公共業務就交給了代理,實現業務分工
- 公共業務發生擴展的時候。方便集中管理!
- 一個動態代理類代理的是一個接口,一般對應一類業務!
- 一個動態代理類可以代理多個類,只要實現了接口!
12.AOP
12.1什麼是AOP
AOP (Aspect Oriented Programming)意爲:面向切面編程,通過預編譯方式和運行期動態代理實現程序功能
的統- -維護的一種技術。AOP是0OP的延續, 是軟件開發中的一個熱點,也是Spring框架中的一個重要內容,是
函數式編程的一種衍生範型。利用AOP可以對業務邏輯的各個部分進行隔離,從而使得業務邏輯各部分之間的耦合
度降低,提高程序的可重用性,同時提高了開發的效率。
12.2Aop在spring中的作用
提供聲明式事務;允許用戶自定義切面
●橫切關注點:跨越應用程序多個模塊的方法或功能。即是,與我們業務邏輯無關的,但是我們需要關注的部分,就是橫切關注點。如日誌,安全,緩存,事務等等…
●切面(ASPECT) :橫切關注點被模塊化的特殊對象。即,它是一一個類。
●通知(Advice) :切面必須要完成的工作。即,它是類中的一一個方法。
●目標(Target) :被通知對象。
●代理(Proxy) :向目標對象應用通知之後創建的對象。
●切入點(PointCut) :切面通知執行的“地點”的定義。
●連接點UointPoint) :與切入點匹配的執行點。
12.3使用Spring實現Aop
【重點】使用AOP織入,需要導入一個包到pom.xml中
<!-- https://mvnrepository.com/artifact/org. aspectj/aspectjweaver -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.4</version>
</dependency>
方式一:使用spring的api接口
配置:
<?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:aop="http://www.springframework.org/schema/aop"
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
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="userservice" class="com.zhang.service.UserServiceImpl"/>
<bean id="log1" class="com.zhang.log.AfterLog"/>
<bean id="log" class="com.zhang.log.Log"/>
<!--使用原生的spring api接口-->
<!-- 配置aop 需要導入約束-->
<aop:config>
<!-- 需要切入點 :expression表達式 execution要執行的位置-->
<aop:pointcut id="pointcut" expression="execution(* com.zhang.service.UserServiceImpl.*(..))"/>
<!--執行環繞增強-->
<aop:advisor advice-ref="log1" pointcut-ref="pointcut"/>
<aop:advisor advice-ref="log" pointcut-ref="pointcut"/>
</aop:config>
</beans>
測試類
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//動態代理的是接口
UserService userservice = (UserService) context.getBean("userservice");
userservice.add();
}
方法二:使用自定義類
public class DiyPointCut {
public void before(){
System.out.println("--------方法執行前-------");
}
public void after(){
System.out.println("-------方法執行後--------");
}
}
<!--方式二:自定義類-->
<bean id="diy" class="com.zhang.diy.DiyPointCut"/>
<aop:config>
<!--自定義切面 ref引用的類-->
<aop:aspect ref="diy">
<!--切入點-->
<aop:pointcut id="point" expression="execution(* com.zhang.service.UserServiceImpl.*(..))"/>
<!--通知-->
<aop:before method="before" pointcut-ref="point"/>
<aop:after method="after" pointcut-ref="point"/>
</aop:aspect>
</aop:config>
方式三:使用註解實現
配置
<!--方式三:使用註解-->
<bean id="annotationPointcut" class="com.zhang.diy.AnnotationPointcut"/>
<!--開啓註解支持-->
<aop:aspectj-autoproxy/>
java類
//使用註解方式實現aop
@Aspect//標註切面類
public class AnnotationPointcut {
@Before("execution(* com.zhang.service.UserServiceImpl.*(..))")
public void before(){
System.out.println("方法執行前-----------------");
}
@After("execution(* com.zhang.service.UserServiceImpl.*(..))")
public void after(){
System.out.println("方法執行後-------------");
}
/**
* 在環繞增強中,我們可以給定一個參數,代表我們要獲取處理的切入點
*/
@Around("execution(* com.zhang.service.UserServiceImpl.*(..))")
public void around(ProceedingJoinPoint jp) throws Throwable {
System.out.println("環繞前");
Object proceed = jp.proceed();
System.out.println("環繞後");
}
}
13.整合Mybatis
步驟:
1.導入相關jar包
- junit
- mybatis
- mysql數據庫
- spring相關
- aop織入
- mybatis-spring【新知識】
pom.xml依賴:
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.2</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.1.9.RELEASE</version>
</dependency>
<!--連接spring操作數據庫,還要一個spring-jdbc-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.1.9.RELEASE</version>
</dependency>
<!--aop織入-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.13</version>
</dependency>
<!--mybatis-spring整合包-->
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.2</version>
</dependency>
</dependencies>
2.編寫配置文件
3.測試
13.1回憶mybatis
1.編寫實體類
2.編寫核心配置文件
3.編寫接口
4.編寫Mapper.xml
5.測試
13.2Mybatis-spring
1.編寫數據源配置
2.sqlSessionFactory
3.sqlSessionTemplate
4.需要給接口加實現類
5.將自己寫的實現類,註冊到spring中
6.測試使用
結構:
spring-dao:
<?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:aop="http://www.springframework.org/schema/aop"
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
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://127.0.0.1:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</bean>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="configLocation" value="classpath:mybatis-config.xml"/>
<property name="mapperLocations" value="classpath:com/zhang/mapper/*.xml"/>
</bean>
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg index="0" ref="sqlSessionFactory"/>
</bean>
</beans>
mybatis-config.xml:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
<typeAliases>
<package name="com.zhang.pojo"/>
</typeAliases>
</configuration>
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"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
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
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<import resource="spring-dao.xml"/>
<bean id="userMapper" class="com.zhang.mapper.UserMapperImpl">
<property name="sqlSession" ref="sqlSession"/>
</bean>
</beans>
spring-dao.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:aop="http://www.springframework.org/schema/aop"
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
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<!--DateSource:使用Spring的數據源替換Mybatis的配置 c3p0 dbcp druid
我們這裏使用spring提供的JDBC: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://127.0.0.1:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</bean>
<!-- sqlSessionFactory-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<!--綁定mybtais配置文件-->
<property name="configLocation" value="classpath:mybatis-config.xml"/>
<!--註冊mapper-->
<property name="mapperLocations" value="classpath:com/zhang/mapper/*.xml"/>
</bean>
<!--SqlSessionTemplate就是我們使用的sqlsession-->
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<!--只能使用構造器注入sqlsessionFactory-->
<constructor-arg index="0" ref="sqlSessionFactory"/>
</bean>
<bean id="userMapper" class="com.zhang.mapper.UserMapperImpl">
<property name="sqlSession" ref="sqlSession"/>
</bean>
</beans>
注意:
使用此配置時,需要刪除中文註釋!!
14.聲明式事務
1.回顧事務
- 把一組業務當成一個業務來做;要麼都成功,要麼都失敗!
- 事務在項目開發中,十分重要,涉及到數據的一致性問題,不能馬虎!
- 確保完整性和一致性;
事物的ACID原則:
-
原子性
-
一致性
-
隔離性
多個業務可能操作同一個資源,防止數據損壞。
-
持久性
事務一旦提交我,無論系統發生什麼問題,結果都不會被影響,被持久化到存儲器中!
2.spring的事務管理
-
聲明式事務 : 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:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" 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 http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx https://www.springframework.org/schema/tx/spring-tx.xsd"> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://127.0.0.1:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC"/> <property name="username" value="root"/> <property name="password" value="root"/> </bean> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource"/> <property name="configLocation" value="classpath:mybatis-config.xml"/> <property name="mapperLocations" value="classpath:com/zhang/mapper/*.xml"/> </bean> <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate"> <constructor-arg index="0" ref="sqlSessionFactory"/> </bean> <!--配置聲明式事務--> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> <!--結合aop實現事務的織入--> <!--配置事務通知--> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <!--給那些方法配置事務--> <!--配置事務的傳播特性: new propagation--> <tx:attributes> <tx:method name="add" propagation="REQUIRED"/> <tx:method name="delete" propagation="REQUIRED"/> <tx:method name="update" propagation="REQUIRED"/> <tx:method name="query" read-only="true"/> <tx:method name="*" propagation="REQUIRED"/> </tx:attributes> </tx:advice> <!--配置事務切入--> <aop:config> <!--配置事務切入點--> <aop:pointcut id="txPointCut" expression="execution(* com.zhang.mapper.*.*(..))"/> <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/> </aop:config> </beans>
-
編程式事務 :需要在代碼中進行事務的管理
思考:
爲什麼需要事務?
- 如果不配置事務,可能存在數據提交不一致的情況!
- 如果我們不在spring中去聲明事務,我們需要在代碼中手動配置
- 事務再項目開發中十分重要,保證了數據的一致性和完整性!
rg.mybatis.spring.SqlSessionFactoryBean">
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg index="0" ref="sqlSessionFactory"/>
</bean>
<!--配置聲明式事務-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!--結合aop實現事務的織入-->
<!--配置事務通知-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<!--給那些方法配置事務-->
<!--配置事務的傳播特性: new propagation-->
<tx:attributes>
<tx:method name="add" propagation="REQUIRED"/>
<tx:method name="delete" propagation="REQUIRED"/>
<tx:method name="update" propagation="REQUIRED"/>
<tx:method name="query" read-only="true"/>
<tx:method name="*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<!--配置事務切入-->
<aop:config>
<!--配置事務切入點-->
<aop:pointcut id="txPointCut" expression="execution(* com.zhang.mapper.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/>
</aop:config>
```
- 編程式事務 :需要在代碼中進行事務的管理
思考:
爲什麼需要事務?
- 如果不配置事務,可能存在數據提交不一致的情況!
- 如果我們不在spring中去聲明事務,我們需要在代碼中手動配置
- 事務再項目開發中十分重要,保證了數據的一致性和完整性!
總結:
這是博主學習spring的大致學習流程,如需學習過程的源碼,可私信博主!另附上學習的資源視頻地址:lhttps://www.bilibili.com/video/BV1WE411d7Dv.
如果整理過程中博主有理解不對的地方,歡迎各位小夥伴留言指正,博主一定虛心接受並改正!
如果覺得博主的學習筆記對你有所幫助,可以給博主點一個贊👍