中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當(dāng)前位置: 首頁(yè) > news >正文

網(wǎng)站建設(shè)論文 網(wǎng)站建設(shè)論文單頁(yè)網(wǎng)站排名優(yōu)化

網(wǎng)站建設(shè)論文 網(wǎng)站建設(shè)論文,單頁(yè)網(wǎng)站排名優(yōu)化,淮北住房和城鄉(xiāng)建設(shè)局門(mén)戶(hù)網(wǎng)站,怎么做網(wǎng)站首頁(yè)文章目錄 一、引言1.1 原生web開(kāi)發(fā)中存在哪些問(wèn)題? 二、Spring框架2.1 概念2.2 訪問(wèn)與下載 三、Spring架構(gòu)組成四、山寨版的Spring容器4.1準(zhǔn)備工作4.2 山寨IOC容器4.3 配置文件告訴容器 管理哪些bean4.4 相關(guān)類(lèi)4.5 測(cè)試 容器 五、構(gòu)建Maven項(xiàng)目5.1 新建項(xiàng)目5.2 選擇…

image-20220430125953747

文章目錄

      • 一、引言
        • 1.1 原生web開(kāi)發(fā)中存在哪些問(wèn)題?
      • 二、Spring框架
        • 2.1 概念
        • 2.2 訪問(wèn)與下載
      • 三、Spring架構(gòu)組成
      • 四、山寨版的Spring容器
        • 4.1準(zhǔn)備工作
        • 4.2 山寨IOC容器
        • 4.3 配置文件告訴容器 管理哪些bean
        • 4.4 相關(guān)類(lèi)
        • 4.5 測(cè)試 容器
      • 五、構(gòu)建Maven項(xiàng)目
        • 5.1 新建項(xiàng)目
        • 5.2 選擇Maven目錄
        • 5.3 GAV坐標(biāo)
      • 六、Spring環(huán)境搭建
        • 6.1 pom.xml中引入Spring常用依賴(lài)
        • 6.2 創(chuàng)建Spring配置文件
      • 七、Spring工廠編碼
      • 八、依賴(lài)與配置文件詳解
        • 8.1 Spring依賴(lài)關(guān)系
        • 8.2 schema
      • 九、IoC(Inversion of Control )控制反轉(zhuǎn)【`重點(diǎn)`】
        • 9.1 項(xiàng)目中強(qiáng)耦合問(wèn)題
        • 9.2 解決方案
        • 9.3 IOC 接口
      • 十、DI(Dependency Injection)依賴(lài)注入【`重點(diǎn)`】
        • 10.1 概念
        • 10.2 Set注入
          • 10.2.1 定義目標(biāo)Bean類(lèi)型
          • 10.2.2 基本類(lèi)型 + 字符串類(lèi)型 + 日期類(lèi)型
          • 10.2.3 容器類(lèi)型
          • 10.2.4 自建類(lèi)型
        • 10.3 構(gòu)造注入【了解】
          • 10.3.1 定義目標(biāo)Bean類(lèi)型
          • 10.3.2 注入
        • 10.4 自動(dòng)注入
      • 十一、Bean細(xì)節(jié)
        • 11.1 控·制簡(jiǎn)單對(duì)象的單例、多例模式 ----- bean的作用域
        • 11.2 FactoryBean創(chuàng)建復(fù)雜對(duì)象
          • 11.2.1 實(shí)現(xiàn)FactoryBean接口
          • 11.2.2 配置spring-context.xml
          • 11.2.3 特例
      • 十二、Spring工廠特性
        • 12.1 餓漢式創(chuàng)建優(yōu)勢(shì) --- 面試題 為什么spring bean 默認(rèn)是單例
        • 12.2 生命周期方法 ---- 面試題 spring bean 的聲明周期是什么 非常重要
        • 12.3 生命周期注解
        • 12.4 生命周期階段
      • 十三、代理設(shè)計(jì)模式
        • 13.1 概念
        • 13.2 靜態(tài)代理設(shè)計(jì)模式
        • 13.3 動(dòng)態(tài)代理設(shè)計(jì)模式
          • 13.3.1 JDK動(dòng)態(tài)代理實(shí)現(xiàn)(基于接口) 代理對(duì)象和真實(shí)對(duì)象的關(guān)系 像是兄弟 代理對(duì)象 對(duì)真實(shí)對(duì)象進(jìn)行增強(qiáng)
          • 13.3.2 CGlib動(dòng)態(tài)代理實(shí)現(xiàn)(基于繼承) 代理對(duì)象和真實(shí)對(duì)象的關(guān)系 就像是 父子
      • 十四、面向切面編程【`重點(diǎn)`】
        • 14.1 概念
        • 14.2 AOP開(kāi)發(fā)術(shù)語(yǔ)
        • 14.3 作用
        • 14.4 環(huán)境搭建
        • 14.5 開(kāi)發(fā)流程
        • 14.6 AOP小結(jié)
        • 14.7 通知類(lèi)【可選】
        • 14.8 通配切入點(diǎn)
        • 14.9 JDK和CGLIB選擇
        • 14.10 后處理器
          • 14.10.1 后處理器定義
          • 14.10.2 配置后處理器
          • 14.10.3 bean生命周期
          • 14.10.4 動(dòng)態(tài)代理源碼(了解)
      • 十五、Spring + MyBatis【`重點(diǎn)`】
        • 15.1 配置數(shù)據(jù)源
          • 15.1.1 引入jdbc.properties配置文件
          • 15.1.2 整合Spring配置文件和properties配置文件
          • 15.1.3 Druid連接池可選參數(shù)
          • 15.1.4 Druid監(jiān)控中心
          • 15.1.5 測(cè)試監(jiān)控中心
        • 15.2 整合MyBatis
          • 15.2.1 導(dǎo)入依賴(lài)
          • 15.2.2 配置SqlSessionFactory
          • 15.2.3 配置MapperScannerConfigurer
          • 15.2.4 配置Service
        • 15.3 我的整合步驟 看我的這個(gè)步驟 上面的可以不看
      • 十六、事務(wù)【`重點(diǎn)`】
        • 16.1 配置DataSourceTransactionManager
        • 16.3 事務(wù)屬性
          • 16.3.1 隔離級(jí)別
            • 16.3.1.1 概念
            • 16.3.1.2 特性
            • 16.3.1.3 并發(fā)問(wèn)題
          • 16.3.2 傳播行為
          • 16.3.3 讀寫(xiě)性
          • 16.3.4 事務(wù)超時(shí)
          • 16.3.5 事務(wù)回滾
        • 16.4 編織
      • 十七、注解開(kāi)發(fā)
        • 17.1 聲明bean
        • 17.2 注入(DI)
        • 17.3 事務(wù)控制
        • 17.4 注解所需配置
        • 17.5 AOP開(kāi)發(fā)
          • 17.5.1 注解使用
          • 17.5.2 配置
      • 十八、集成JUnit
        • 18.1 導(dǎo)入依賴(lài)
        • 18.2 編碼
      • 十九、個(gè)人擴(kuò)展
      • 二十 個(gè)人源碼解析

一、引言


1.1 原生web開(kāi)發(fā)中存在哪些問(wèn)題?

  • 傳統(tǒng)Web開(kāi)發(fā)存在硬編碼所造成的過(guò)度程序耦合(例如:Service中作為屬性Dao對(duì)象)。
  • UserDao userdao = new UserDaoImpl();
  • 部分Java EE API較為復(fù)雜,使用效率低(例如:JDBC開(kāi)發(fā)步驟 ,Servlet的開(kāi)發(fā)步驟)。
  • 侵入性強(qiáng),移植性差(例如:DAO實(shí)現(xiàn)的更換,從Connection到SqlSession)。

二、Spring框架


2.1 概念

  • Spring是一個(gè)項(xiàng)目管理框架,同時(shí)也是一套Java EE解決方案。

  • Spring是眾多優(yōu)秀設(shè)計(jì)模式的組合(工廠、單例、代理、適配器、包裝器、觀察者、模板、策略)。

  • Spring并未替代現(xiàn)有框架產(chǎn)品,而是將眾多框架進(jìn)行有機(jī)整合,簡(jiǎn)化企業(yè)級(jí)開(kāi)發(fā),俗稱(chēng)"膠水框架"。

2.2 訪問(wèn)與下載

官方網(wǎng)站:https://spring.io/

下載地址:http://repo.spring.io/release/org/springframework/spring/

三、Spring架構(gòu)組成


Spring架構(gòu)由諸多模塊組成,可分類(lèi)為

  • 核心技術(shù):依賴(lài)注入,事件,資源,i18n,驗(yàn)證,數(shù)據(jù)綁定,類(lèi)型轉(zhuǎn)換,SpEL,AOP。
  • 測(cè)試:模擬對(duì)象,TestContext框架,Spring MVC測(cè)試,WebTestClient。
  • 數(shù)據(jù)訪問(wèn):事務(wù),DAO支持,JDBC,ORM,封送XML。
  • Spring MVC和 Spring WebFlux Web框架。
  • 集成:遠(yuǎn)程處理,JMS,JCA,JMX,電子郵件,任務(wù),調(diào)度,緩存。
  • 語(yǔ)言:Kotlin,Groovy,動(dòng)態(tài)語(yǔ)言。
Spring架構(gòu)組成
image-20220430130018321
GroupIdArtifactId說(shuō)明
org.springframeworkspring-beansBeans 支持,包含 Groovy
org.springframeworkspring-aop基于代理的AOP支持
org.springframeworkspring-aspects基于AspectJ 的切面
org.springframeworkspring-context應(yīng)用上下文運(yùn)行時(shí),包括調(diào)度和遠(yuǎn)程抽象
org.springframeworkspring-context-support支持將常見(jiàn)的第三方類(lèi)庫(kù)集成到 Spring 應(yīng)用上下文
org.springframeworkspring-core其他模塊所依賴(lài)的核心模塊
org.springframeworkspring-expressionSpring 表達(dá)式語(yǔ)言,SpEL
org.springframeworkspring-instrumentJVM 引導(dǎo)的儀表(監(jiān)測(cè)器)代理
org.springframeworkspring-instrument-tomcatTomcat 的儀表(監(jiān)測(cè)器)代理
org.springframeworkspring-jdbc支持包括數(shù)據(jù)源設(shè)置和 JDBC 訪問(wèn)支持
org.springframeworkspring-jms支持包括發(fā)送/接收J(rèn)MS消息的助手類(lèi)
org.springframeworkspring-messaging對(duì)消息架構(gòu)和協(xié)議的支持
org.springframeworkspring-orm對(duì)象/關(guān)系映射,包括對(duì) JPA 和 Hibernate 的支持
org.springframeworkspring-oxm對(duì)象/XML 映射(Object/XML Mapping,OXM)
org.springframeworkspring-test單元測(cè)試和集成測(cè)試支持組件
org.springframeworkspring-tx事務(wù)基礎(chǔ)組件,包括對(duì) DAO 的支持及 JCA 的集成
org.springframeworkspring-webweb支持包,包括客戶(hù)端及web遠(yuǎn)程調(diào)用
org.springframeworkspring-webmvcREST web 服務(wù)及 web 應(yīng)用的 MVC 實(shí)現(xiàn)
org.springframeworkspring-webmvc-portlet用于 Portlet 環(huán)境的MVC實(shí)現(xiàn)
org.springframeworkspring-websocketWebSocket 和 SockJS 實(shí)現(xiàn),包括對(duì) STOMP 的支持
org.springframeworkspring-jclJakarta Commons Logging 日志系統(tǒng)

四、山寨版的Spring容器

創(chuàng)建容器 ,從容器得到對(duì)象 ,而不是程序員自己new 對(duì)象,從而實(shí)現(xiàn) 對(duì)象間的解耦

4.1準(zhǔn)備工作

UserService

public interface UserService {public void addUser();
}

UserServiceImpl

    @Overridepublic void addUser() {//使用 spring容器 之前的做法  是 在這里 new 一個(gè) dao 對(duì)象  程序員自己new//UserDao userDao = new UserJdbcDaoImpl();//現(xiàn)在 需求變了 要使用mybatis 操作數(shù)據(jù)庫(kù)      硬編碼     耦合度太高   我們希望 不改代碼 來(lái)改變底層的實(shí)現(xiàn)userDao = new UserMybatisDaoImpl();userDao.addUser();}

UserDao

public interface UserDao {void addUser();}

UserJdbcDaoImpl

public class UserJdbcDaoImpl implements UserDao {@Overridepublic void addUser() {System.out.println("使用jdbc來(lái)添加用戶(hù)");}
}

UserMybatisDaoImpl

public class UserMybatisDaoImpl implements UserDao {@Overridepublic void addUser() {System.out.println("使用mybatis來(lái)添加用戶(hù)");}
}

原來(lái)咱們的做法 沒(méi)有spring容器的時(shí)候

    @Testpublic void test1(){//使用 spring  容器之前的 做法   自己 newUserService userService = new UserServiceImpl();userService.addUser();}

4.2 山寨IOC容器

引入spring 容器, 從容器中獲取對(duì)象

MyClassPathXmlApplicationContext

package com.glls.java2301.framework;import com.glls.java2301.dao.UserDao;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;/*** @date 2023/4/19* @desc   山寨版IOC容器  來(lái)模擬 真實(shí)的  基于XML的 spring 容器*/
public class MyClassPathXmlApplicationContext {//用于 存放 解析完 xml文件之后的   bean 的 信息, 以 beanId  為key  以BeanDefinition 為值private Map<String,BeanDefinition> beansMap = new HashMap<>();//這個(gè)map 用于存放 spring 容器 創(chuàng)建出來(lái)的對(duì)象   在容器里面創(chuàng)建出來(lái)的對(duì)象 叫 bean// 這個(gè)map 以 beanId 為 key  以反射創(chuàng)建出來(lái)的對(duì)象 為值private Map<String,Object> objectMap = new HashMap<>();public MyClassPathXmlApplicationContext() {}public MyClassPathXmlApplicationContext(String xmlPath) throws DocumentException, ClassNotFoundException, InstantiationException, IllegalAccessException, InvocationTargetException {//這個(gè)構(gòu)造方法  創(chuàng)建 容器對(duì)象 , 創(chuàng)建容器對(duì)象的時(shí)候   要把容器管理的bean 對(duì)象 也創(chuàng)建好//咱們就得告訴 Spring 容器  它所管理的bean對(duì)象 有哪些 ,通常 咱們會(huì)通過(guò)  xml , 注解,  java 配置類(lèi)//這些方式 告訴 spring 容器  管理的 bean 有哪些 ,這里 咱們 采用的方式 是 xml 的方式  告知spring 管理// 哪些bean   所以 現(xiàn)在 咱們要做的事情  就是  解析 xml 文件  ,得到 要?jiǎng)?chuàng)建的 bean 的 信息//1. 解析 xml 文件  得到 bean的信息  把bean 的信息 封裝到 BeanDefinition  ,每個(gè)bean 都會(huì)有自己的//beanDefinition  , 咱們把 很多 bean 的 beanDefinition 放入一個(gè) map 中parseXml(xmlPath);//2.從 beansMap 中 獲取bean 的信息 通過(guò)反射 創(chuàng)建對(duì)象 將創(chuàng)建出來(lái)的對(duì)象 放入 objectMapcreateObject();//3. di    依賴(lài)注入   第二部創(chuàng)建的對(duì)象的屬性時(shí)沒(méi)有值的di(); //dependency injection  屬性注入}//依賴(lài)注入  通過(guò)反射 調(diào)用對(duì)象的 set 方法  給對(duì)象的屬性賦值private void di() throws ClassNotFoundException, InvocationTargetException, IllegalAccessException {Set<Map.Entry<String, BeanDefinition>> entrySet = beansMap.entrySet();Iterator<Map.Entry<String, BeanDefinition>> iterator = entrySet.iterator();while (iterator.hasNext()){Map.Entry<String, BeanDefinition> beanDefinitionEntry = iterator.next();String beanId = beanDefinitionEntry.getKey();BeanDefinition beanDefinition = beanDefinitionEntry.getValue();//得到的bean 的property 集合Map<String, PropertyDefinition> propsMap = beanDefinition.getPropsMap();Set<Map.Entry<String, PropertyDefinition>> proSet = propsMap.entrySet();Iterator<Map.Entry<String, PropertyDefinition>> proIter = proSet.iterator();while (proIter.hasNext()){Map.Entry<String, PropertyDefinition> propertyDefinitionEntry = proIter.next();//得到 property 的nameString proName = propertyDefinitionEntry.getKey();PropertyDefinition propertyDefinition = propertyDefinitionEntry.getValue();//ref 指向 屬性對(duì)應(yīng)的beanIdString ref = propertyDefinition.getRef();//根據(jù)屬性名 得到set方法  通過(guò)set方法給對(duì)象的屬性賦值//setUserDaoString setMethodName = "set" + proName.substring(0,1).toUpperCase()+proName.substring(1);//通過(guò)反射 得到方法對(duì)象String beanClass = beanDefinition.getBeanClass();Class<?> aClass = Class.forName(beanClass);Method[] declaredMethods = aClass.getDeclaredMethods();for(Method m:declaredMethods){//判斷對(duì)象中 有沒(méi)有這個(gè) set 方法if(m.getName().equals(setMethodName)){//表示 有這個(gè) set 方法//得到對(duì)象  給這個(gè)對(duì)象的屬性賦值  要反射調(diào)用這個(gè)對(duì)象的 set 方法Object o = objectMap.get(beanId);//得到 set 方法的參數(shù)Object para = objectMap.get(ref);//反射調(diào)用set 方法 給 對(duì)象o 的屬性賦值// userService.setUserDao(para);m.invoke(o,para);}}}}}//創(chuàng)建對(duì)象private void createObject() throws ClassNotFoundException, InstantiationException, IllegalAccessException {//通過(guò)反射創(chuàng)建對(duì)象 要拿到類(lèi)的全路徑信息Set<Map.Entry<String, BeanDefinition>> entrySet = beansMap.entrySet();Iterator<Map.Entry<String, BeanDefinition>> iterator = entrySet.iterator();while (iterator.hasNext()){Map.Entry<String, BeanDefinition> bean = iterator.next();String beanId = bean.getKey();BeanDefinition beanDefinition = bean.getValue();//得到類(lèi)的全路徑名String beanClass = beanDefinition.getBeanClass();//通過(guò)反射創(chuàng)建對(duì)象Object o = Class.forName(beanClass).newInstance();//將創(chuàng)建好的對(duì)象 存入 obejctMapobjectMap.put(beanId,o);}}private void parseXml(String xmlPath) throws DocumentException {//讀取配置文件 得到流對(duì)象InputStream resourceAsStream = this.getClass().getClassLoader().getResourceAsStream(xmlPath);//使用dom4j的apiSAXReader saxReader = new SAXReader();//得到文檔對(duì)象Document doc = saxReader.read(resourceAsStream);//得到根節(jié)點(diǎn)Element rootElement = doc.getRootElement();//遍歷根節(jié)點(diǎn)Iterator<Element> iterator = rootElement.elementIterator();while (iterator.hasNext()){Element bean = iterator.next();String beanId = bean.attributeValue("id");String beanClass = bean.attributeValue("class");//System.out.println(beanId+"---"+beanClass);//把解析出來(lái)的信息 存入 BeanDefinition 中BeanDefinition beanDefinition = new BeanDefinition();beanDefinition.setBeanId(beanId);beanDefinition.setBeanClass(beanClass);//遍歷bean 標(biāo)簽的子標(biāo)簽Iterator<Element> proIterator = bean.elementIterator();while (proIterator.hasNext()){Element pro = proIterator.next();String proName = pro.attributeValue("name");String proRef = pro.attributeValue("ref");//將bean 的 子節(jié)點(diǎn) 屬性信息 封裝到 PropertyDefinition 中PropertyDefinition propertyDefinition = new PropertyDefinition();propertyDefinition.setName(proName);propertyDefinition.setRef(proRef);//將屬性信息 封裝到 BeanDefinition 中的 propsMapMap<String, PropertyDefinition> propsMap = beanDefinition.getPropsMap();propsMap.put(proName,propertyDefinition);}//將這個(gè) bean 的定義信息 封裝到 beansMapbeansMap.put(beanId,beanDefinition);}}//從容器拿對(duì)象的方法public Object getBean(String beanName) {return objectMap.get(beanName);}
}

4.3 配置文件告訴容器 管理哪些bean

<beans><bean id="userJdbcDao" class="com.glls.java2301.dao.impl.UserJdbcDaoImpl" ></bean><bean id="userMybatisDao" class="com.glls.java2301.dao.impl.UserMybatisDaoImpl"></bean><bean id="userService" class="com.glls.java2301.service.impl.UserServiceImpl">
<!--        以后需求變了  不想使用jdbc 來(lái)訪問(wèn)數(shù)據(jù)庫(kù)了 ,想使用mybatis  那么僅僅只需要改一下下面的ref 就可以了--><property name="userDao" ref="userMybatisDao"></property></bean></beans>

4.4 相關(guān)類(lèi)

BeanDefinition

package com.glls.java2301.framework;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;import java.util.HashMap;
import java.util.Map;/*** @date 2023/4/19* @desc  bean 的定義信息  來(lái)封裝bean 的 信息*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class BeanDefinition {//解析xml   解析出來(lái)的數(shù)據(jù) 封裝到這個(gè)類(lèi)的對(duì)象中private String beanId;   // bean 的 名字 bean 在容器中的標(biāo)識(shí)private String beanClass;  // 封裝bean 的 全路徑private Map<String,PropertyDefinition> propsMap = new HashMap<>();}

PropertyDefinition

@Data
@AllArgsConstructor
@NoArgsConstructor
public class PropertyDefinition {//property 節(jié)點(diǎn)的 name 屬性值private String name;//property 節(jié)點(diǎn)的 ref 屬性值private String ref;}

4.5 測(cè)試 容器

 @Testpublic void test2() throws DocumentException, ClassNotFoundException, InstantiationException, IllegalAccessException, InvocationTargetException {//山寨版的IOC容器// 由容器 來(lái) 創(chuàng)建  管理 對(duì)象// 創(chuàng)建咱們 的IOC 容器, 從容器中 獲取 對(duì)象  ,這里 咱們模擬的情況是//容器 創(chuàng)建好了   里面的bean 也創(chuàng)建好了  , 可以直接用了String config= "applicationContext.xml";//創(chuàng)建容器對(duì)象  告知容器對(duì)象掃描的 xml 配置文件    ,xml 文件中 記錄了 spring 容器要管理的 bean的信息MyClassPathXmlApplicationContext applicationContext = new MyClassPathXmlApplicationContext(config);//UserDao userDao = (UserDao) applicationContext.getBean("userJdbcDao");//UserDao userDao2 = (UserDao) applicationContext.getBean("userMybatisDao");UserService userService = (UserService) applicationContext.getBean("userService");//userDao.addUser();//userDao2.addUser();userService.addUser();}

手寫(xiě) ioc 容器 – 基于 xml 版本的 目的 理解 ioc 容器

詳見(jiàn) springday1 案例

后面有時(shí)間 再帶大家寫(xiě)一個(gè) 基于注解版本的 理解 bean的生命周期

五、構(gòu)建Maven項(xiàng)目


5.1 新建項(xiàng)目

使用IDEA打開(kāi)已創(chuàng)建的文件夾目錄
image-20220430130308905

5.2 選擇Maven目錄

選擇Maven項(xiàng)目
image-20220430130350368

5.3 GAV坐標(biāo)

GAV坐標(biāo)
image-20220430130422064

六、Spring環(huán)境搭建


6.1 pom.xml中引入Spring常用依賴(lài)

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.qf</groupId><artifactId>hello-spring</artifactId><version>1.0-SNAPSHOT</version><dependencies><!-- Spring常用依賴(lài) --><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.1.6.RELEASE</version></dependency></dependencies>
</project>

6.2 創(chuàng)建Spring配置文件

命名無(wú)限制,約定俗成命名有:spring-context.xml、applicationContext.xml、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 http://www.springframework.org/schema/beans/spring-beans.xsd"></beans>

七、Spring工廠編碼


定義目標(biāo)Bean類(lèi)型

public class MyClass{public void show(){System.out.println("HelloWorld");}
}

spring-context.xml中的< beans >內(nèi)部配置bean標(biāo)簽

<!-- 在 spring 配置文件中,使用 bean 標(biāo)簽,標(biāo)簽里面添加對(duì)應(yīng)屬性,就可以實(shí)現(xiàn)對(duì)象創(chuàng)建, 配置實(shí)例(id:“唯一標(biāo)識(shí)”  class="需要被創(chuàng)建的目標(biāo)對(duì)象全限定名") 創(chuàng)建對(duì)象時(shí)候,默認(rèn)也是執(zhí)行無(wú)參數(shù)構(gòu)造方法完成對(duì)象創(chuàng)建-->
<bean id="mc" class="com.qf.spring.part1.factory.MyClass" />

調(diào)用Spring工廠API(ApplicationContext接口)

public class TestFactory{/*** 程序中的對(duì)象都交由Spring的ApplicationContext工廠進(jìn)行創(chuàng)建。*/public static void main(String[] args){//1. 讀取配置文件中所需創(chuàng)建的bean對(duì)象,并獲得工廠對(duì)象ApplicationContext ctx = new ClassPathXmlApplicationContext("spring-context.xml");//2. 通過(guò)id獲取bean對(duì)象MyClass mc = (MyClass) ctx.getBean("mc");//3. 使用對(duì)象mc.show();}
}

八、依賴(lài)與配置文件詳解


Spring框架包含多個(gè)模塊,每個(gè)模塊各司其職,可結(jié)合需求引入相關(guān)依賴(lài)Jar包實(shí)現(xiàn)功能。

8.1 Spring依賴(lài)關(guān)系

Spring常用功能的Jar包依賴(lài)關(guān)系
image-20191230164517693
  • 注意:Jar包彼此存在依賴(lài),只需引入最外層Jar即可由Maven自動(dòng)將相關(guān)依賴(lài)Jar引入到項(xiàng)目中。

8.2 schema

配置文件中的頂級(jí)標(biāo)簽中包含了語(yǔ)義化標(biāo)簽的相關(guān)信息

  • xmlns:語(yǔ)義化標(biāo)簽所在的命名空間。
  • xmlns:xsi:XMLSchema-instance 標(biāo)簽遵循Schema標(biāo)簽標(biāo)準(zhǔn)。
  • xsi:schemaLocation:xsd文件位置,用以描述標(biāo)簽語(yǔ)義、屬性、取值范圍等。

九、IoC(Inversion of Control )控制反轉(zhuǎn)【重點(diǎn)


Inverse Of Controll:控制反轉(zhuǎn)

反轉(zhuǎn)了依賴(lài)關(guān)系的滿(mǎn)足方式,由之前的自己創(chuàng)建依賴(lài)對(duì)象,變?yōu)橛晒S推送。(變主動(dòng)為被動(dòng),即反轉(zhuǎn))

解決了具有依賴(lài)關(guān)系的組件之間的強(qiáng)耦合,使得項(xiàng)目形態(tài)更加穩(wěn)健

補(bǔ)充: 什么是IOC

1.控制反轉(zhuǎn),把對(duì)象創(chuàng)建和對(duì)象之間的調(diào)用過(guò)程,交給 Spring 進(jìn)行管理

2.使用 IOC 目的:為了耦合度降低

3.入門(mén)案例就是 IOC 實(shí)現(xiàn)

IOC 底層原理

xml 解析、工廠模式、反射

9.1 項(xiàng)目中強(qiáng)耦合問(wèn)題

public class UserDAOImpl implements UserDAO{....}
public class UserServiceImpl implements UserService {// !!!強(qiáng)耦合了UserDAOImpl!!!,使得UserServiceImpl變得不穩(wěn)健!!private UserDAO userDAO= new UserDAOImpl();@Overridepublic User queryUser() {return userDAO.queryUser();}....
}

9.2 解決方案

// 不引用任何一個(gè)具體的組件(實(shí)現(xiàn)類(lèi)),在需要其他組件的位置預(yù)留存取值入口(set/get)
public class UserServiceImpl implements UserService {// !!!不再耦合任何DAO實(shí)現(xiàn)!!!,消除不穩(wěn)健因素!!private UserDAO userDAO;// 為userDAO定義set/get,允許userDAO屬性接收spring賦值//Getters And Setters@Overridepublic User queryUser() {return userDAO.queryUser();}....
}
<bean id="userDAO" class="com.qf.spring.part1.injection.UserDaoImpl"></bean>
<!-- UserServiceImpl組件 -->
<bean id="userService" class="com.qf.spring.part1.injection.UserServiceImpl"><!-- 由spring為userDAO屬性賦值,值為id="userDAO"的bean --><property name="userDAO" ref="userDAO"/>
</bean>

此時(shí),如果需要更換其他UserDAO實(shí)現(xiàn)類(lèi),則UserServiceImpl不用任何改動(dòng)!

則此時(shí)的UserServiceImpl組件變得更加穩(wěn)健!

9.3 IOC 接口

1.IOC 思想基于 IOC 容器完成,IOC 容器底層就是對(duì)象工廠

2.Spring 提供 IOC 容器實(shí)現(xiàn)兩種方式:(兩個(gè)接口)

  • BeanFactory:IOC 容器基本實(shí)現(xiàn),是 Spring 內(nèi)部的使用接口,不提供開(kāi)發(fā)人員進(jìn)行使用

    • 加載配置文件時(shí)候不會(huì)創(chuàng)建對(duì)象,在獲取對(duì)象(使用)才去創(chuàng)建對(duì)象
  • ApplicationContext:BeanFactory 接口的子接口,提供更多更強(qiáng)大的功能,一般由開(kāi)發(fā)人 員進(jìn)行使用

    • 加載配置文件時(shí)候就會(huì)把在配置文件對(duì)象進(jìn)行創(chuàng)建

image-20210803101900198

3.IOC操作bean管理

Bean的管理指的是兩個(gè)操作:1.Spring創(chuàng)建對(duì)象 2.Spring注入屬性

Bean的常見(jiàn)的管理操作有兩種方式:1.基于 xml 配置文件方式實(shí)現(xiàn) 2.基于注解方式實(shí)現(xiàn)

十、DI(Dependency Injection)依賴(lài)注入【重點(diǎn)


10.1 概念

在Spring創(chuàng)建對(duì)象的同時(shí),為其屬性賦值,稱(chēng)之為依賴(lài)注入。

10.2 Set注入

創(chuàng)建對(duì)象時(shí),Spring工廠會(huì)通過(guò)Set方法為對(duì)象的屬性賦值。

10.2.1 定義目標(biāo)Bean類(lèi)型
public class User {private Integer id;private String password;private String sex;private Integer age;private Date bornDate;private String[] hobbys;private Set<String> phones;private List<String> names;private Map<String,String> countries;private Properties files;//Getters And Setters
}
10.2.2 基本類(lèi)型 + 字符串類(lèi)型 + 日期類(lèi)型
<bean id="u1" class="com.qf.spring.part1.injection.User"><!--base field--><property name="id" value="1001" /><property name="password" value="123456" /><property name="sex" value="male" /><property name="age" value="20" /><property name="bornDate" value="1990/1/1" /><!--注意格式"/"-->
</bean>
10.2.3 容器類(lèi)型
<bean id="u1" class="com.qf.spring.part1.injection.User">	<!--Array--><property name="hobbys"><array><value>Run</value><value>Swim</value><value>Climb</value></array></property><!--Set--><property name="phones"><set><value>13777777777</value><value>13888888888</value><value>13999999999</value></set></property><!--List--><property name="names"><list><value>tom</value><value>jack</value><value>marry</value></list></property><!--Map--><property name="countries"><map><entry key="CN" value="China" /><entry key="US" value="America" /><entry key="KR" value="Korea" /></map></property><!--Properties--><property name="files"><props><prop key="first">One</prop><prop key="second">Two</prop><prop key="third">Three</prop></props></property>
</bean>
10.2.4 自建類(lèi)型
<!--次要bean,被作為屬性-->
<bean id="addr" class="com.qf.spring.part1.injection.Address"><property name="position" value="北京市海淀區(qū)" /><property name="zipCode" value="100001" />
</bean><!--主要bean,操作的主體-->
<bean id="u2" class="com.qf.spring.part1.injection.User"><property name="address" ref="addr" /><!--address屬性引用addr對(duì)象-->
</bean>
<!--次要bean,被作為屬性-->
<bean id="userDao" class="com.qf.spring.part1.injection.UserDaoImpl" /><!--主要bean,操作的主體-->
<bean id="userService" class="com.qf.spring.part1.injection.UserServiceImpl"><property name="ud" ref="userDao" /><!--ud屬性引用userDao對(duì)象-->
</bean>

10.3 構(gòu)造注入【了解】

創(chuàng)建對(duì)象時(shí),Spring工廠會(huì)通過(guò)構(gòu)造方法為對(duì)象的屬性賦值。

10.3.1 定義目標(biāo)Bean類(lèi)型
public class Student {private Integer id;private String name;private String sex;private Integer age;//Constructorspublic Student(Integer id , String name , String sex , Integer age){this.id = id;this.name = name;this.sex = sex;this.age = age;}
}
10.3.2 注入
 <!--構(gòu)造注入-->
<bean id="u3" class="com.qf.zcg.spring.day1.t2.ioc.Student"><constructor-arg name="id" value="1234" /> <!-- 除標(biāo)簽名稱(chēng)有變化,其他均和Set注入一致 --><constructor-arg name="name" value="tom" /><constructor-arg name="age" value="20" /><constructor-arg name="sex" value="male" />
</bean>

10.4 自動(dòng)注入

不用在配置中 指定為哪個(gè)屬性賦值,及賦什么值.

由spring自動(dòng)根據(jù)某個(gè) “原則” ,在工廠中查找一個(gè)bean,為屬性注入屬性值

也叫自動(dòng)裝配 根據(jù)裝配規(guī)則 (屬性名和屬性類(lèi)型) spring 自動(dòng)將匹配的屬性值進(jìn)行注入

演示過(guò)程

1.根據(jù)屬性名稱(chēng)自動(dòng)注入在  bean  標(biāo)簽 使用 autowire 配置自動(dòng)裝配,autowire 屬性 常用兩個(gè)值:byName   根據(jù)屬性名稱(chēng)注入     注入值的 bean 的 id 和  類(lèi)的屬性名一樣byType     根據(jù)屬性類(lèi)型注入   如果 容器內(nèi) 有多個(gè)這個(gè)類(lèi)型的bean 那么 容器如果不知道注入哪一個(gè) 就會(huì)報(bào)錯(cuò)
public class UserServiceImpl implements UserService {private UserDAO userDAO;//Getters And Setters....
}
<bean id="userDao" class="com.qf.spring.part1.injection.UserDaoImpl" />
<!-- 為UserServiceImpl中的屬性基于類(lèi)型自動(dòng)注入值 -->
<bean id="userService" class="com.qf.spring.part1.injection.UserServiceImpl" autowire="byType"></bean>
<bean id="userDao" class="com.qf.spring.part1.injection.UserDaoImpl" />
<!-- 為UserServiceImpl中的屬性基于名字自動(dòng)注入值 -->
<bean id="userService" class="com.qf.spring.part1.injection.UserServiceImpl" autowire="byName"></bean>

十一、Bean細(xì)節(jié)


11.1 控·制簡(jiǎn)單對(duì)象的單例、多例模式 ----- bean的作用域

在spring 容器里 設(shè)置 bean 實(shí)例 是 單例 還是 多例 , 默認(rèn)情況下 bean 是 單例的

配置< bean scope=“singleton | prototype” />

<!--singleton(默認(rèn)):每次調(diào)用工廠,得到的都是同一個(gè)對(duì)象。  加載 spring 配置文件時(shí)候就會(huì)創(chuàng)建單實(shí)例對(duì)象prototype:每次調(diào)用工廠,都會(huì)創(chuàng)建新的對(duì)象。   不是在加載 spring 配置文件時(shí)候創(chuàng)建 對(duì)象,在調(diào)用
getBean 方法時(shí)候創(chuàng)建多實(shí)例對(duì)象-->
<bean id="mc" class="com.qf.zcg.spring.day1.t1.basic.MyClass" scope="singleton" /> 
  • 注意:需要根據(jù)場(chǎng)景決定對(duì)象的單例、多例模式。
  • 可以共用:Service、DAO、SqlSessionFactory(或者是所有的工廠)。
  • 不可共用:Connection、SqlSession、ShoppingCart。

11.2 FactoryBean創(chuàng)建復(fù)雜對(duì)象

注意 和 前面的 BeanFactory 的區(qū)別

補(bǔ)充:spring有兩種類(lèi)型的bean ,一種是 普通bean ,另外一種是 工廠bean (FactoryBean)

普通的bean : 在配置文件中定義的bean的類(lèi)型 就是返回類(lèi)型

工廠bean 在配置文件中定義的bean類(lèi)型可以和返回的bean類(lèi)型不一樣

作用:讓Spring可以創(chuàng)建復(fù)雜對(duì)象、或者無(wú)法直接通過(guò)反射創(chuàng)建的對(duì)象。

FactoryBean解決復(fù)雜對(duì)象創(chuàng)建
image-20190419235128663
11.2.1 實(shí)現(xiàn)FactoryBean接口
接口方法描述
image-20190419234550731
  • 注意:isSingleton方法的返回值,需根據(jù)所創(chuàng)建對(duì)象的特點(diǎn)決定返回true/false。
  • 例如:Connection 不應(yīng)該被多個(gè)用戶(hù)共享,返回false。
  • 例如:SqlSessionFactory 重量級(jí)資源,不該過(guò)多創(chuàng)建,返回true。
11.2.2 配置spring-context.xml
配置與獲取方式
image-20190419235939298
11.2.3 特例
獲取FactoryBean接口的實(shí)現(xiàn)類(lèi)對(duì)象,而非getObject()所生產(chǎn)的對(duì)象。
image-20190420000713143

十二、Spring工廠特性


12.1 餓漢式創(chuàng)建優(yōu)勢(shì) — 面試題 為什么spring bean 默認(rèn)是單例

工廠創(chuàng)建之后,會(huì)將Spring配置文件中的所有對(duì)象都創(chuàng)建完成(餓漢式)。

提高程序運(yùn)行效率。避免多次IO,減少對(duì)象創(chuàng)建時(shí)間。(概念接近連接池,一次性創(chuàng)建好,使用時(shí)直接獲取)

如果默認(rèn)是多例bean 首先創(chuàng)建多例bean 會(huì)消耗資源 還會(huì)占用堆空間

12.2 生命周期方法 ---- 面試題 spring bean 的聲明周期是什么 非常重要

什么生命周期?

bean 對(duì)象從創(chuàng)建到銷(xiāo)毀的過(guò)程

步驟

  1. bean 的實(shí)例化 通過(guò)構(gòu)造方法創(chuàng)建bean 的實(shí)例 默認(rèn)是無(wú)參構(gòu)造
  2. 給bean 的屬性賦值 調(diào)用 set 方法
  3. 執(zhí)行初始化的方法 需要配置初始化方法
  4. 得到完整的bean 對(duì)象 ,這時(shí)的bean 對(duì)象才能夠使用
  5. 銷(xiāo)毀bean 需要配置 銷(xiāo)毀的方法

要考慮 bean 的后置處理器 BeanPostProcessor

創(chuàng)建一個(gè)類(lèi)實(shí)現(xiàn)BeanPostProcessor 重寫(xiě) 他的兩個(gè)方法

public class MyBeanPost implements BeanPostProcessor {@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {System.out.println("在bean 初始化之前執(zhí)行");return bean;}@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {System.out.println("在bean初始化之后執(zhí)行");if(bean instanceof User){User user = (User) bean;user.setName("貂蟬");return user;}return bean;}
}

在配置文件 配置這個(gè) bean

 <bean id="myPostProcessor" class="com.qf.postprocessor.MyBeanPost"></bean>

總結(jié): 面試答案

  1. bean 的實(shí)例化 通過(guò)構(gòu)造方法創(chuàng)建bean 的實(shí)例 默認(rèn)是無(wú)參構(gòu)造
  2. 給bean 的屬性賦值
  3. 把 bean 的 實(shí)例 傳遞給 bean的后置處理器的方法 postProcessBeforeInitialization
  4. 執(zhí)行初始化的方法
  5. 把 bean 的 實(shí)例 傳遞給 bean的后置處理器的方法 postProcessAfterInitialization
  6. 得到完整的bean 對(duì)象 ,這時(shí)的bean 對(duì)象才能夠使用
  7. 銷(xiāo)毀bean 當(dāng)容器關(guān)閉的時(shí)候 調(diào)用銷(xiāo)毀的方法
  • 自定義初始化方法:添加“init-method”屬性,Spring則會(huì)在創(chuàng)建對(duì)象之后,調(diào)用此方法。

  • 自定義銷(xiāo)毀方法:添加“destroy-method”屬性,Spring則會(huì)在銷(xiāo)毀對(duì)象之前,調(diào)用此方法。

  • 銷(xiāo)毀:工廠的close()方法被調(diào)用之后,Spring會(huì)毀掉所有已創(chuàng)建的單例對(duì)象。

  • 分類(lèi):Singleton對(duì)象由Spring容器銷(xiāo)毀、Prototype對(duì)象由JVM銷(xiāo)毀。

12.3 生命周期注解

初始化注解、銷(xiāo)毀注解

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;@PostConstruct //初始化 
public void init(){System.out.println("init method executed");
}@PreDestroy //銷(xiāo)毀
public void destroy(){System.out.println("destroy method executed");
}

12.4 生命周期階段

**單例bean:**singleton

隨工廠啟動(dòng)創(chuàng)建 ==》 構(gòu)造方法 ==》 set方法(注入值) ==》 init(初始化) ==》 構(gòu)建完成 ==》隨工廠關(guān)閉銷(xiāo)毀

**多例bean:**prototype

被使用時(shí)創(chuàng)建 ==》 構(gòu)造方法 ==》 set方法(注入值) ==》 init(初始化) ==》 構(gòu)建完成 ==》JVM垃圾回收銷(xiāo)毀

十三、代理設(shè)計(jì)模式


13.1 概念

將核心功能與輔助功能(事務(wù)、日志、性能監(jiān)控代碼)分離,達(dá)到核心業(yè)務(wù)功能更純粹、輔助業(yè)務(wù)功能可復(fù)用。

功能分離
image-20190420002535800

13.2 靜態(tài)代理設(shè)計(jì)模式

通過(guò)代理類(lèi)的對(duì)象,為原始類(lèi)的對(duì)象(目標(biāo)類(lèi)的對(duì)象)添加輔助功能,更容易更換代理實(shí)現(xiàn)類(lèi)、利于維護(hù)。

靜態(tài)代理
image-20190420004330551
  • 代理類(lèi) = 實(shí)現(xiàn)原始類(lèi)相同接口 + 添加輔助功能 + 調(diào)用原始類(lèi)的業(yè)務(wù)方法。
  • 靜態(tài)代理的問(wèn)題
    • 代理類(lèi)數(shù)量過(guò)多,不利于項(xiàng)目的管理。
    • 多個(gè)代理類(lèi)的輔助功能代碼冗余,修改時(shí),維護(hù)性差。

13.3 動(dòng)態(tài)代理設(shè)計(jì)模式

動(dòng)態(tài)創(chuàng)建代理類(lèi)的對(duì)象,為原始類(lèi)的對(duì)象添加輔助功能。

13.3.1 JDK動(dòng)態(tài)代理實(shí)現(xiàn)(基于接口) 代理對(duì)象和真實(shí)對(duì)象的關(guān)系 像是兄弟 代理對(duì)象 對(duì)真實(shí)對(duì)象進(jìn)行增強(qiáng)
//目標(biāo)
final OrderService os = new OrderServiceImpl();
//額外功能
InvocationHandler handler = new InvocationHandler(){//1.設(shè)置回調(diào)函數(shù)(額外功能代碼)@Overridepublic Object invoke(Object proxy, Method method, Object[] args)throws Throwable {System.out.println("start...");method.invoke(os, args);System.out.println("end...");return null;}
};
//2.創(chuàng)建動(dòng)態(tài)代理類(lèi)
Object proxyObj = Proxy.newProxyInstance(ClassLoader , Interfaces , InvocationHandler);

個(gè)人代碼

接口

public interface Marry {public void marry();public int money();}

真實(shí)對(duì)象

public class You implements Marry {@Overridepublic void marry() {System.out.println("終身大事");}@Overridepublic int money() {int num = 10;System.out.println("花了"+num+"塊錢(qián)");return num;}
}

封裝的一個(gè)工具類(lèi)

public class JdkProxy implements InvocationHandler {private Object target;   //真實(shí)對(duì)象   被代理的對(duì)象//把真實(shí)對(duì)象傳進(jìn)來(lái)   返回代理對(duì)象public Object getProxy(Object target){this.target = target;return Proxy.newProxyInstance(this.getClass().getClassLoader(),target.getClass().getInterfaces(),this);}//對(duì)真實(shí)對(duì)象的功能增強(qiáng)@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("準(zhǔn)備工作");Object result = method.invoke(target, args);System.out.println("收尾工作");if(target instanceof Marry){return 100;}return result;}
}

測(cè)試

public class TestJdkProxy {public static void main(String[] args) {//真實(shí)對(duì)象You you = new You();JdkProxy jdkProxy = new JdkProxy();//得到代理對(duì)象Marry proxy = (Marry) jdkProxy.getProxy(you);//調(diào)用代理對(duì)象的方法proxy.marry();int money = proxy.money();System.out.println(money);}
}    
13.3.2 CGlib動(dòng)態(tài)代理實(shí)現(xiàn)(基于繼承) 代理對(duì)象和真實(shí)對(duì)象的關(guān)系 就像是 父子
final OrderService os = new OrderServiceImpl();
Enhancer cnh = new Enhancer();//1.創(chuàng)建字節(jié)碼曾強(qiáng)對(duì)象
enh.setSuperclass(os.getClass());//2.設(shè)置父類(lèi)(等價(jià)于實(shí)現(xiàn)原始類(lèi)接口)
enh.setCallback(new InvocationHandler(){//3.設(shè)置回調(diào)函數(shù)(額外功能代碼)@Overridepublic Object invoke(Object proxy , Method method, Object[] args) throws Throwable{System.out.println("start...");Object ret = method.invoke(os,args);System.out.println("end...");return ret;}
});
OrderService proxy = (OrderService)enh.create();//4.創(chuàng)建動(dòng)態(tài)代理類(lèi)
proxy,createOrder();

個(gè)人代碼

真實(shí)對(duì)象

public class You {public void marry() {System.out.println("終身大事");}public int money() {int num = 10;System.out.println("花了"+num+"塊錢(qián)");return num;}}

工具類(lèi) 封裝得到代理對(duì)象的方法 和 回調(diào)方法

package com.qf.proxy.cglibproxy;import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.InvocationHandler;import java.lang.reflect.Method;public class CglibProxy implements InvocationHandler {//真實(shí)對(duì)象private Object target;//傳入真實(shí)對(duì)象 得到代理對(duì)象public Object getProxy(Object target){this.target = target;Enhancer enhancer = new Enhancer();//1.創(chuàng)建字節(jié)碼曾強(qiáng)對(duì)象enhancer.setSuperclass(target.getClass());//2.設(shè)置父類(lèi)(等價(jià)于實(shí)現(xiàn)原始類(lèi)接口)//設(shè)置回調(diào)函數(shù)enhancer.setCallback(this);//返回代理對(duì)象return enhancer.create();}//真實(shí)對(duì)象方法增強(qiáng)@Overridepublic Object invoke(Object o, Method method, Object[] objects) throws Throwable {System.out.println("準(zhǔn)備工作");Object result = method.invoke(target, objects);System.out.println("收尾工作");return result;}
}

測(cè)試

package com.qf.proxy.cglibproxy;public class TestCglibProxy {public static void main(String[] args) {//真實(shí)對(duì)象You you = new You();//工具類(lèi)對(duì)象CglibProxy cglibProxy = new CglibProxy();//得到代理對(duì)象You proxy = (You) cglibProxy.getProxy(you);proxy.marry();}
}

十四、面向切面編程【重點(diǎn)


14.1 概念

AOP(Aspect Oriented Programming),即面向切面編程,利用一種稱(chēng)為"橫切"的技術(shù),剖開(kāi)封裝的對(duì)象內(nèi)部,并將那些影響了多個(gè)類(lèi)的公共行為封裝到一個(gè)可重用模塊,并將其命名為"Aspect",即切面。所謂"切面",簡(jiǎn)單說(shuō)就是那些與業(yè)務(wù)無(wú)關(guān),卻為業(yè)務(wù)模塊所共同調(diào)用的邏輯或責(zé)任封裝起來(lái),便于減少系統(tǒng)的重復(fù)代碼,降低模塊之間的耦合度,并有利于未來(lái)的可操作性和可維護(hù)性。

什么是AOP ?

1.面向切面編程 利用AOP 可以對(duì)業(yè)務(wù)邏輯的各個(gè)部分進(jìn)行隔離 從而使業(yè)務(wù)邏輯的各部分之間 耦合度降低,提高程序的可重用性,提好了開(kāi)發(fā)效率,通俗的講 可以實(shí)現(xiàn)不修改源代碼的方式,在核心業(yè)務(wù)里面 添加新的功能

AOP 底層的原理 就是 動(dòng)態(tài)代理 ,真正干活的 bean 是 代理bean , 代理bean 對(duì)真實(shí)bean 功能增強(qiáng)

14.2 AOP開(kāi)發(fā)術(shù)語(yǔ)

  • 連接點(diǎn)(Joinpoint):連接點(diǎn)是程序類(lèi)中客觀存在的方法,可被Spring攔截并切入內(nèi)容。
  • 說(shuō)白了 類(lèi)中的哪些方法 可以被增強(qiáng) 這些方法 就稱(chēng)為是 連接點(diǎn)
  • 切入點(diǎn)(Pointcut):被Spring切入連接點(diǎn)。
  • 真正被增強(qiáng)的方法 稱(chēng)為 切入點(diǎn)
  • 通知、增強(qiáng)(Advice):可以為切入點(diǎn)添加額外功能,分為:前置通知、后置通知、異常通知、環(huán)繞通知,最終通知等。
  • 實(shí)際增強(qiáng)的邏輯部分 稱(chēng)為通知(增強(qiáng))
  • 目標(biāo)對(duì)象(Target):代理的目標(biāo)對(duì)象 真實(shí)對(duì)象
  • 引介(Introduction):一種特殊的增強(qiáng),可在運(yùn)行期為類(lèi)動(dòng)態(tài)添加Field和Method。
  • 織入(Weaving):把通知應(yīng)用到具體的類(lèi),進(jìn)而創(chuàng)建新的代理類(lèi)的過(guò)程。
  • 代理(Proxy):被AOP織入通知后,產(chǎn)生的結(jié)果類(lèi)。
  • 切面(Aspect):由切點(diǎn)和通知組成,將橫切邏輯織入切面所指定的連接點(diǎn)中。是一個(gè)動(dòng)作 把通知 應(yīng)用到 切入點(diǎn)的過(guò)程

14.3 作用

Spring的AOP編程即是通過(guò)動(dòng)態(tài)代理類(lèi)為原始類(lèi)的方法添加輔助功能。

14.4 環(huán)境搭建

引入AOP相關(guān)依賴(lài)

<dependency><groupId>org.springframework</groupId><artifactId>spring-aspects</artifactId><version>5.1.6.RELEASE</version>
</dependency>

spring-context.xml引入AOP命名空間

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:context="http://www.springframework.org/schema/context"xmlns:p="http://www.springframework.org/schema/p"xmlns:aop="http://www.springframework.org/schema/aop"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd"></beans>

14.5 開(kāi)發(fā)流程

定義原始類(lèi)

package com.qf.aaron.aop.basic;public interface UserService {public void save();
}
package com.qf.aaron.aop.basic;public class UserServiceImpl implements UserService {public void save() {System.out.println("save method executed...");}
}

下面是 基于 Schema-based 的 aop實(shí)現(xiàn)方式 得認(rèn)識(shí)

四種通知

image-20220418161638452

MyBeforeAdvice 前置通知

AfterReturningAdvice 后置返回通知

注意 Schema-based 沒(méi)有最終通知

MethodInterceptor 環(huán)繞通知

ThrowsAdvice 異常通知

定義通知類(lèi)(添加額外功能)

package com.qf.aaron.aop.basic;
import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;public class MyAdvice implements MethodBeforeAdvice { //實(shí)現(xiàn)前置通知接口public void before(Method method, Object[] args, Object target) throws Throwable {System.out.println("before advice executed...");}
}

定義bean標(biāo)簽

<!--原始對(duì)象-->
<bean id="us" class="com.qf.aaron.aop.basic.UserServiceImpl" /><!--輔助對(duì)象-->
<bean id="myAdvice" class="com.qf.aaron.aop.basic.MyAdvice" />

定義切入點(diǎn)(PointCut)

形成切面(Aspect)

<aop:config><!--切點(diǎn)--><aop:pointcut id="myPointCut" expression="execution(* save())" />
</aop:config>
<aop:config><!--組裝切面 --><aop:advisor advice-ref="myAdvice" pointcut-ref="myPointCut" />
</aop:config>

下面是基于 AspectJ 的 AOP 實(shí)現(xiàn)方式

方式1 基于 xml 的配置

創(chuàng)建 通知類(lèi)

package com.qf.aspectjadvice;import org.aspectj.lang.ProceedingJoinPoint;/*** @ClassName : MyAspectJAdvice* @Description :   AspectJ 的 通知類(lèi)  無(wú)需實(shí)現(xiàn)接口*/
public class MyAspectJAdvice {public void mybefore(){System.out.println("aspectj的前置通知");}public void myafter(){System.out.println("aspectj的后置通知");}public Object myaround(ProceedingJoinPoint p) throws Throwable {System.out.println("環(huán)繞前置");Object result = p.proceed();System.out.println("環(huán)繞后置");return  result;}
}

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:aop="http://www.springframework.org/schema/aop"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd"><!--基于注解的形式 管理 bean--><!--掃描 com.qf 下的全部組件--><context:component-scan base-package="com.qf"></context:component-scan><!--了解   基于 AspectJ 的 xml 的  AOP實(shí)現(xiàn) 配置--><bean id="myaspectj" class="com.qf.aspectjadvice.MyAspectJAdvice"></bean><aop:config><aop:aspect ref="myaspectj"><aop:pointcut id="aspectjpoint1" expression="execution(* save(..))"/></aop:aspect><aop:aspect ref="myaspectj"><aop:pointcut id="aspectjpoint2" expression="execution(* com.qf.service.impl.OrderServiceImpl.save(..))"/></aop:aspect><aop:aspect ref="myaspectj"><aop:before method="mybefore" pointcut-ref="aspectjpoint1"></aop:before><aop:after method="myafter" pointcut-ref="aspectjpoint1"></aop:after><aop:around method="myaround" pointcut-ref="aspectjpoint2"></aop:around></aop:aspect></aop:config></beans>

測(cè)試:

 @Testpublic void test2(){// 基于 Aspectj  的 xml 的  AOP  了解   看得懂ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans2.xml");UserService userService = applicationContext.getBean("userService", UserService.class);OrderService orderService = applicationContext.getBean("orderService", OrderService.class);userService.save();//userService.delete(1);Order order = new Order(1, "訂單描述");//orderService.save(order);}

方式2 aspectj 基于 注解的aop 實(shí)現(xiàn) 要求掌握

  1. 配置文件
<?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"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd"><!--基于注解的形式 管理 bean--><!--掃描 com.qf 下的全部組件--><context:component-scan base-package="com.qf"></context:component-scan><!--掌握   基于 AspectJ 的 注解 的  AOP實(shí)現(xiàn) 配置--><aop:aspectj-autoproxy></aop:aspectj-autoproxy></beans>
  1. 通知類(lèi)
package com.qf.aspectaannotation;import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;@Aspect
@Component
public class AspectjAnnotationAdvice {// @Before 表示前置通知@Before("execution(* save(..))")public void before(){System.out.println("基于aspectj注解形式的前置通知,要求大家掌握");}
}
  1. 測(cè)試效果

14.6 AOP小結(jié)

  • 通過(guò)AOP提供的編碼流程,更便利的定制切面,更方便的定制了動(dòng)態(tài)代理。

  • 進(jìn)而徹底解決了輔助功能冗余的問(wèn)題;

  • 業(yè)務(wù)類(lèi)中職責(zé)單一性得到更好保障;

  • 輔助功能也有很好的復(fù)用性。

14.7 通知類(lèi)【可選】

定義通知類(lèi),達(dá)到通知效果

前置通知:MethodBeforeAdvice后置通知:AfterAdvice后置通知:AfterReturningAdvice //有異常不執(zhí)行,方法會(huì)因異常而結(jié)束,無(wú)返回值異常通知:ThrowsAdvice環(huán)繞通知:MethodInterceptor

沒(méi)有必要把通知的執(zhí)行順序 記得非常精確 因?yàn)?spring 新版本 5 和 之前的舊版本 通知的執(zhí)行順序 不一樣

14.8 通配切入點(diǎn)

根據(jù)表達(dá)式通配切入點(diǎn)

<!--匹配參數(shù)-->
<aop:pointcut id="myPointCut" expression="execution(* *(com.qf.aaron.aop.basic.User))" />
<!--匹配方法名(無(wú)參)-->
<aop:pointcut id="myPointCut" expression="execution(* save())" />
<!--匹配方法名(任意參數(shù))-->
<aop:pointcut id="myPointCut" expression="execution(* save(..))" />
<!--匹配返回值類(lèi)型-->
<aop:pointcut id="myPointCut" expression="execution(com.qf.aaron.aop.basic.User *(..))" />
<!--匹配類(lèi)名-->
<aop:pointcut id="myPointCut" expression="execution(* com.qf.aaron.aop.basic.UserServiceImpl.*(..))" />
<!--匹配包名-->
<aop:pointcut id="myPointCut" expression="execution(* com.qf.aaron.aop.basic.*.*(..))" />
<!--匹配包名、以及子包名-->
<aop:pointcut id="myPointCut" expression="execution(* com.qf.aaron.aop..*.*(..))" />

切入點(diǎn)表達(dá)式:expression 知道對(duì)哪個(gè)類(lèi)的那個(gè)方法進(jìn)行增強(qiáng)

語(yǔ)法結(jié)構(gòu): execution([權(quán)限修飾符] [返回值類(lèi)型] [類(lèi)全路徑] [方法名稱(chēng)] ([參數(shù)列表])

14.9 JDK和CGLIB選擇

  • spring底層,包含了jdk代理和cglib代理兩種動(dòng)態(tài)代理生成機(jī)制

  • 基本規(guī)則是:目標(biāo)業(yè)務(wù)類(lèi)如果有接口則用JDK代理,沒(méi)有接口則用CGLib代理

class DefaultAopProxyFactory{// 該方法中明確定義了 JDK代理和CGLib代理的選取規(guī)則// 基本規(guī)則是:目標(biāo)業(yè)務(wù)類(lèi)如果有接口則用JDK代理,沒(méi)有接口則用CGLib代理public AopProxy createAopProxy(){...}
}

14.10 后處理器

  • spring中定義了很多后處理器;

  • 每個(gè)bean在創(chuàng)建完成之前 ,都會(huì)有一個(gè)后處理過(guò)程,即再加工,對(duì)bean做出相關(guān)改變和調(diào)整;

  • spring-AOP中,就有一個(gè)專(zhuān)門(mén)的后處理器,負(fù)責(zé)通過(guò)原始業(yè)務(wù)組件(Service),再加工得到一個(gè)代理組件。

常用后處理器
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來(lái)直接上傳(img-7iaN9bjA-1682258194560)(https://gllspictures.oss-cn-beijing.aliyuncs.com/img/系統(tǒng)后處理器.jpg)]
14.10.1 后處理器定義
/*** 定義bean后處理器* 作用:在bean的創(chuàng)建之后,進(jìn)行再加工*/
public class MyBeanPostProcessor implements BeanPostProcessor{/*** 在bean的init方法之前執(zhí)行* @param bean  原始的bean對(duì)象* @param beanName* @return* @throws BeansException*/public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {System.out.println("后處理器 在init之前執(zhí)行~~~"+bean.getClass());return bean;}/*** 在bean的init方法之后執(zhí)行* @param bean  postProcessBeforeInitialization返回的bean* @param beanName* @return* @throws BeansException*/@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {System.out.println("后處理器 在init之后執(zhí)行~~~"+bean.getClass());return bean;// 此處的返回是 getBean() 最終的返回值}
}
14.10.2 配置后處理器
<!-- 配置后處理器,將對(duì)工廠中所有的bean聲明周期進(jìn)行干預(yù) -->
<bean class="com.qianfeng.beanpostprocessor.MyBeanPostProcessor"></bean>
14.10.3 bean生命周期

構(gòu)造 》 注入屬性 滿(mǎn)足依賴(lài) 》 后處理器前置過(guò)程 》 初始化 》后處理器后置過(guò)程 》 返回 》 銷(xiāo)毀

記住 記住 記住 記住 記住 記住

1.如果是單例 bean , 隨著容器的創(chuàng)建而創(chuàng)建 即 實(shí)例化,多例bean 是 獲取的時(shí)候 實(shí)例化

2.屬性注入

3.后處理器前置過(guò)程 即在初始化方法之前執(zhí)行的 方法 postProcessBeforeInitialization

4.初始化方法

5.后處理器后置過(guò)程 即在初始化方法之后執(zhí)行的 方法 postProcessAfterInitialization aop動(dòng)態(tài)代理就在這一步

6.得到最終的 bean

7.銷(xiāo)毀

14.10.4 動(dòng)態(tài)代理源碼(了解)
// AbstractAutoProxyCreator是 AspectJAwareAdvisorAutoProxyCreator的父類(lèi)
// 該后處理器類(lèi)中的 wrapIfNecessary方法即動(dòng)態(tài)代理生成過(guò)程
AbstractAutoProxyCreator#postProcessAfterInitialization(Object bean, String beanName){if (!this.earlyProxyReferences.contains(cacheKey)) {// 開(kāi)始動(dòng)態(tài)定制代理return wrapIfNecessary(bean, beanName, cacheKey);}
}

十五、Spring + MyBatis【重點(diǎn)


15.1 配置數(shù)據(jù)源

將數(shù)據(jù)源配置到項(xiàng)目中

15.1.1 引入jdbc.properties配置文件
#jdbc.properties
jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mydb?useUnicode=true&characterEncoding=UTF-8
jdbc.username=root
jdbc.password=123456
15.1.2 整合Spring配置文件和properties配置文件
<!--spring-context.xml-->
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:context="http://www.springframework.org/schema/context"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd"><!--配置文件參數(shù)化(參數(shù)占位符)--><context:property-placeholder location="classpath:jdbc.properties" /><!--與PooledDataSource集成(二選一)--><bean id="dataSource" class="org.apache.ibatis.datasource.pooled.PooledDataSource"><property name="driver" value="${driverClass}"/><property name="url" value="${url}"/><property name="username" value="${username}"/><property name="password" value="${password}"/></bean><!--與DruidDataSource集成(二選一)--><bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close"><!--基本配置--><property name="driverClassName" value="${jdbc.driverClass}"/><property name="url" value="${jdbc.url}"/><property name="username" value="${jdbc.username}"/><property name="password" value="${jdbc.password}"/></bean>
</bean>
15.1.3 Druid連接池可選參數(shù)
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close"><!--基本配置--><property name="driverClassName" value="${jdbc.driverClass}"/><property name="url" value="${jdbc.url}"/><property name="username" value="${jdbc.username}"/><property name="password" value="${jdbc.password}"/><!-- 配置初始化大小、最小、最大 --><property name="initialSize" value="${jdbc.init}"/><property name="minIdle" value="${jdbc.minIdle}"/><property name="maxActive" value="${jdbc.maxActive}"/><!-- 配置獲取連接等待超時(shí)的時(shí)間 --><property name="maxWait" value="60000"/><!-- 配置間隔多久才進(jìn)行一次檢測(cè),檢測(cè)需要關(guān)閉的空閑連接,單位是毫秒 --><property name="timeBetweenEvictionRunsMillis" value="60000"/><!-- 配置一個(gè)連接在池中最小生存的時(shí)間,單位是毫秒 --><property name="minEvictableIdleTimeMillis" value="300000"/>
</bean>
15.1.4 Druid監(jiān)控中心
<!--web.xml-->
<servlet><servlet-name>DruidStatView</servlet-name><servlet-class>com.alibaba.druid.support.http.StatViewServlet</servlet-class>
</servlet>
<servlet-mapping><servlet-name>DruidStatView</servlet-name><url-pattern>/druid/*</url-pattern>
</servlet-mapping>
15.1.5 測(cè)試監(jiān)控中心

配置tomcat,并訪問(wèn)protocol://ip:port/project/druid/index.html

15.2 整合MyBatis

將 SqlSessionFactory、DAO、Service 配置到項(xiàng)目中

15.2.1 導(dǎo)入依賴(lài)
<!-- spring-jdbc -->
<dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>5.1.6.RELEASE</version>
</dependency><!-- spring+mybatis集成依賴(lài) -->
<dependency><groupId>org.mybatis</groupId><artifactId>mybatis-spring</artifactId><version>1.3.1</version>
</dependency>
15.2.2 配置SqlSessionFactory
<!-- 工廠bean:生成SqlSessionFactory -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"><!-- 注入連接池 --><property name="dataSource" ref="dataSource"></property><!-- 注入dao-mapper文件信息 ,如果映射文件和dao接口 同包且同名,則此配置可省略--><property name="mapperLocations"><list><value>classpath:com/qf/spring/dao/*.xml</value></list></property><!-- 為 dao-mapper文件中的實(shí)體 定義缺省包路徑 如:<select id="queryAll" resultType="User"> 中 User類(lèi)可以不定義包--><property name="typeAliasesPackage" value="com.qf.entity"></property>
</bean>
15.2.3 配置MapperScannerConfigurer

管理DAO實(shí)現(xiàn)類(lèi)的創(chuàng)建,并創(chuàng)建DAO對(duì)象,存入工廠管理

  • 掃描所有DAO接口,去構(gòu)建DAO實(shí)現(xiàn)

  • 將DAO實(shí)現(xiàn)存入工廠管理

  • DAO實(shí)現(xiàn)對(duì)象在工廠中的id是:“首字母小寫(xiě)的-接口的類(lèi)名”,

    例如:UserDAO==>userDAO , OrderDAO==>orderDAO

<!-- mapperScannerConfigurer -->
<bean id="mapperScannerConfigurer9" class="org.mybatis.spring.mapper.MapperScannerConfigurer"><!-- dao接口所在的包  如果有多個(gè)包,可以用逗號(hào)或分號(hào)分隔 <property name="basePackage" value="com.a.dao,com.b.dao"></property>--><property name="basePackage" value="com.qf.spring.dao"></property><!-- 如果工廠中只有一個(gè)SqlSessionFactory的bean,此配置可省略 --><property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
</bean>
15.2.4 配置Service
<bean id="userService" class="com.qf.spring.service.UserServiceImpl"><!-- 注意ref中的值是對(duì)應(yīng)DAO接口的首字母小寫(xiě)的接口名 --><property name="userDAO" ref="userDAO"></property>
</bean>

15.3 我的整合步驟 看我的這個(gè)步驟 上面的可以不看

1.添加依賴(lài)

<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.qf</groupId><artifactId>sm</artifactId><version>1.0-SNAPSHOT</version><packaging>war</packaging><name>sm Maven Webapp</name><!-- FIXME change it to the project's website --><url>http://www.example.com</url><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><maven.compiler.source>1.8</maven.compiler.source><maven.compiler.target>1.8</maven.compiler.target></properties><dependencies><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.2.0.RELEASE</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-aspects</artifactId><version>5.2.0.RELEASE</version></dependency><!--MyBatis核心依賴(lài)--><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.4.6</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.21</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.20</version></dependency><!-- log4j日志依賴(lài) https://mvnrepository.com/artifact/log4j/log4j --><dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.17</version></dependency><!-- spring-jdbc --><dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>5.2.0.RELEASE</version></dependency><!-- spring+mybatis集成依賴(lài) --><dependency><groupId>org.mybatis</groupId><artifactId>mybatis-spring</artifactId><version>1.3.2</version></dependency><!-- https://mvnrepository.com/artifact/com.alibaba/druid --><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.1.16</version></dependency></dependencies><build><finalName>sm</finalName><pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) --><plugins><plugin><artifactId>maven-clean-plugin</artifactId><version>3.1.0</version></plugin><!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging --><plugin><artifactId>maven-resources-plugin</artifactId><version>3.0.2</version></plugin><plugin><artifactId>maven-compiler-plugin</artifactId><version>3.8.0</version></plugin><plugin><artifactId>maven-surefire-plugin</artifactId><version>2.22.1</version></plugin><plugin><artifactId>maven-war-plugin</artifactId><version>3.2.2</version></plugin><plugin><artifactId>maven-install-plugin</artifactId><version>2.5.2</version></plugin><plugin><artifactId>maven-deploy-plugin</artifactId><version>2.8.2</version></plugin></plugins></pluginManagement><!-- 如果不添加此節(jié)點(diǎn)src/main/java目錄下的所有配置文件都會(huì)被漏掉。 --><resources><resource><directory>src/main/java</directory><includes><include>**/*.xml</include></includes></resource><resource><directory>src/main/resources</directory><includes><include>**/*.xml</include><include>**/*.properties</include><include>**/*.ini</include></includes></resource></resources></build>
</project>

2.spring的配置文件

準(zhǔn)備數(shù)據(jù)源配置文件 db.properties

jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/ssm?characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true
jdbc.username=root
jdbc.password=123456
<?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"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd"><!--基于注解的形式 管理 bean--><!--掃描 com.qf 下的全部組件--><context:component-scan base-package="com.qf"></context:component-scan><!--掌握   基于 AspectJ 的 注解 的  AOP實(shí)現(xiàn) 配置--><aop:aspectj-autoproxy></aop:aspectj-autoproxy><!--配置文件參數(shù)化(參數(shù)占位符)--><context:property-placeholder location="classpath:db.properties" /><bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close"><!--基本配置--><property name="driverClassName" value="${jdbc.driver}"/><property name="url" value="${jdbc.url}"/><property name="username" value="${jdbc.username}"/><property name="password" value="${jdbc.password}"/><!-- 配置獲取連接等待超時(shí)的時(shí)間 --><property name="maxWait" value="60000"/><!-- 配置間隔多久才進(jìn)行一次檢測(cè),檢測(cè)需要關(guān)閉的空閑連接,單位是毫秒 --><property name="timeBetweenEvictionRunsMillis" value="60000"/><!-- 配置一個(gè)連接在池中最小生存的時(shí)間,單位是毫秒 --><property name="minEvictableIdleTimeMillis" value="300000"/></bean><!-- 工廠bean:生成SqlSessionFactory --><bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"><!--數(shù)據(jù)源屬性--><property name="dataSource" ref="dataSource"></property><!--mybatis的配置文件--><property name="configLocation" value="classpath:mybatis-config.xml"></property></bean><bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"><!--掃描mapper 接口  自動(dòng)創(chuàng)建mapper層代理對(duì)象  交給spring管理--><property name="basePackage" value="com.qf.mapper"></property><property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property></bean></beans>

mybatis的配置文件

<?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><typeAliases><!--自動(dòng)掃描包,將原類(lèi)名作為別名--><package name="com.qf.pojo" /></typeAliases><mappers><!--掃描xml  映射文件--><package name="com.qf.mapper"/></mappers>
</configuration>

整合 logback 日志

添加依賴(lài)

 <!--logback 日志--><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId><version>1.7.25</version></dependency><dependency><groupId>ch.qos.logback</groupId><artifactId>logback-core</artifactId><version>1.2.3</version></dependency><dependency><groupId>ch.qos.logback</groupId><artifactId>logback-classic</artifactId><version>1.2.3</version></dependency><dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.17</version></dependency><dependency><groupId>org.logback-extensions</groupId><artifactId>logback-ext-spring</artifactId><version>0.1.4</version></dependency>

添加日志的配置文件 logback.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration><appender name="stdout" class="ch.qos.logback.core.ConsoleAppender"><Target>System.out</Target><Encoding>UTF-8</Encoding><encoder><pattern>%d{yyyy-MM-dd_HH:mm:ss.SSS} %5p [%t] [%c{1}]:%L - %m%n</pattern></encoder></appender><appender name="logfile"class="ch.qos.logback.core.rolling.RollingFileAppender"><Encoding>UTF-8</Encoding><encoder><pattern>%d %p [%t] [%c]:%L - %m%n</pattern></encoder><filter class="ch.qos.logback.classic.filter.ThresholdFilter"><level>DEBUG</level></filter><rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"><fileNamePattern>log/%d{yyyy-MM-dd-HH'.log'}</fileNamePattern></rollingPolicy></appender><logger name="org.springframework" level="WARN" /><logger name="org.springframework.remoting" level="WARN" /><logger name="org.springframework.scheduling.quartz" level="WARN" /><logger name="org.springframework.data.jpa" level="DEBUG" /><logger name="org.cometd" level="WARN" /><logger name="ch.qos.logback" level="WARN" /><logger name="com.springapp.mvc" level="DEBUG" /><logger name="com.qf.mapper" level="DEBUG"></logger><!-- <logger name="com.ibatis" level="DEBUG"></logger> --><root level="ERROR"><appender-ref ref="stdout" /><appender-ref ref="logfile" /></root>
</configuration>
配置到 web.xml 中
    <!-- logback --><context-param><param-name>logbackConfigLocation</param-name><param-value>classpath:logback.xml</param-value></context-param><listener><listener-class>ch.qos.logback.ext.spring.web.LogbackConfigListener</listener-class></listener>

整合 servlet ,后期 換成 springmvc ,當(dāng)前先用servlet

1.添加依賴(lài)

  <!--整合一下 web--><dependency><groupId>org.springframework</groupId><artifactId>spring-web</artifactId><version>5.2.0.RELEASE</version></dependency><dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>3.1.0</version><scope>provided</scope></dependency><dependency><groupId>javax.servlet</groupId><artifactId>jsp-api</artifactId><version>2.0</version><scope>provided</scope></dependency><dependency><groupId>javax.servlet</groupId><artifactId>jstl</artifactId><version>1.2</version></dependency>

2.在web.xml 中 添加一個(gè)監(jiān)聽(tīng)器 用于讀取spring 的配置文件 創(chuàng)建 容器

 <context-param><param-name>contextConfigLocation</param-name><param-value>classpath:applicationContext.xml</param-value></context-param><!--這個(gè)監(jiān)聽(tīng)器  幫助加載spring 配置文件,創(chuàng)建spring 容器--><listener><listener-class>org.springframework.web.context.ContextLoaderListener</listener-class></listener>
  1. 創(chuàng)建servlet 在 servlet中 得到 容器對(duì)象 再通過(guò)容器對(duì)象來(lái)得到 service bean
package com.qf.web;import com.qf.pojo.User;
import com.qf.service.UserService;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;/*** @ClassName : LoginServlet* @Author : glls* @Date: 2021/8/10 14:43* @Description :*/
@WebServlet("/login")
public class LoginServlet extends HttpServlet {private UserService userService;@Overridepublic void init() throws ServletException {WebApplicationContext applicationContext = WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext());userService = applicationContext.getBean("userService", UserService.class);}@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {this.doPost(req,resp);}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {String username = req.getParameter("username");String password = req.getParameter("password");//有了spring 管理 bean ,就不要再自己new 對(duì)象了 ,所以//從容器 把 userService 取出來(lái)User user = new User();user.setName(username);user.setPassword(password);User result = userService.login(user);System.out.println(result);}
}

十六、事務(wù)【重點(diǎn)

  1. 什么是事務(wù)?

    事務(wù)是數(shù)據(jù)庫(kù)操作的基本單元,邏輯上的一組操作,要么都成功,要么都失敗,也就是說(shuō)只有一組操作中 有一個(gè)失敗了,那么這組操作都失敗

    舉個(gè)栗子

    wsc轉(zhuǎn)賬500給wjl

    update t_account set money = money-500 where accountid = 1 wsc 的賬戶(hù) 減500

    update t_account set money = money+500 where accountid=2 wjl的賬戶(hù) 加 500

  2. 事務(wù)的特性 ACID

    A atomicity 原子性 一組操作 整體不可拆分要么都成功 要么都失敗

    C consistency 一致性 數(shù)據(jù)在事務(wù)的前后,業(yè)務(wù)整體一致

    I isolation 隔離性 事務(wù)之間 互相隔離

    D durability 持久性 一旦事務(wù)執(zhí)行成功 數(shù)據(jù)一定會(huì)落盤(pán)在數(shù)據(jù)庫(kù)

3.準(zhǔn)備事務(wù)的環(huán)境

賬戶(hù)表

image-20210811092715563

service 定義轉(zhuǎn)賬方法

    //轉(zhuǎn)賬操作@Overridepublic void transferMoney(int from, int to, double money) {//from 給   to 轉(zhuǎn)了  money//一個(gè)賬戶(hù) 扣錢(qián)accountMapper.reduceMoney(from,money);//模擬一個(gè)異常int i = 5/0;//一個(gè)賬戶(hù)加錢(qián)accountMapper.addMOney(to,money);}

dao

    @Update("update t_account set money= money - #{money} where userid= #{from} ")void reduceMoney(@Param("from") int from,@Param("money") double money);@Update("update t_account set money = money + #{money} where userid = #{to} ")void addMOney(@Param("to")int to, @Param("money") double money);

轉(zhuǎn)賬過(guò)程中 模擬異常,出現(xiàn)一個(gè)賬戶(hù)扣錢(qián)了,另一個(gè)賬戶(hù)卻沒(méi)有加錢(qián) 數(shù)據(jù)不一致問(wèn)題 怎么解決?

使用事務(wù) 進(jìn)行解決

spring提供了 事務(wù)的解決方案 底層原理是 AOP

  1. 基于注解的方案 掌握
  2. 基于xml配置文件的方式 了解

16.1 配置DataSourceTransactionManager

事務(wù)管理器,其中持有DataSource,可以控制事務(wù)功能(commit,rollback等)。

<!-- 1. 引入一個(gè)事務(wù)管理器,其中依賴(lài)DataSource,借以獲得連接,進(jìn)而控制事務(wù)邏輯 -->
<bean id="tx" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource" ref="dataSource"></property>
</bean>

注意:DataSourceTransactionManager 和 SqlSessionFactoryBean 要注入同一個(gè)DataSource的Bean,否則事務(wù)控制失敗!!!

####16.2 配置事務(wù)通知

基于事務(wù)管理器,進(jìn)一步定制,生成一個(gè)額外功能:Advice。

此Advice可以切入任何需要事務(wù)的方法,通過(guò)事務(wù)管理器為方法控制事務(wù)。

<tx:advice id="txManager" transaction-manager="tx"><tx:attributes><!--<tx:method name="insertUser" rollback-for="Exception" isolation="DEFAULT"    propagation="REQUIRED" read-only="false"/>--><!-- 以User結(jié)尾的方法,切入此方法時(shí),采用對(duì)應(yīng)事務(wù)實(shí)行--><tx:method name="*User" rollback-for="Exception"/><!-- 以query開(kāi)頭的方法,切入此方法時(shí),采用對(duì)應(yīng)事務(wù)實(shí)行 --><tx:method name="query*" propagation="SUPPORTS"/><!-- 剩余所有方法 --><tx:method name="*"/></tx:attributes>
</tx:advice>

16.3 事務(wù)屬性

16.3.1 隔離級(jí)別
16.3.1.1 概念

isolation 隔離級(jí)別

名稱(chēng)描述
default(默認(rèn)值)(采用數(shù)據(jù)庫(kù)的默認(rèn)的設(shè)置) (建議)
read-uncommited讀未提交
read-commited讀提交 (Oracle數(shù)據(jù)庫(kù)默認(rèn)的隔離級(jí)別)
repeatable-read可重復(fù)讀 (MySQL數(shù)據(jù)庫(kù)默認(rèn)的隔離級(jí)別)
serialized-read序列化讀

隔離級(jí)別由低到高為:read-uncommited < read-commited < repeatable-read < serialized-read

16.3.1.2 特性
  • 安全性:級(jí)別越高,多事務(wù)并發(fā)時(shí),越安全。因?yàn)楣蚕淼臄?shù)據(jù)越來(lái)越少,事務(wù)間彼此干擾減少。

  • 并發(fā)性:級(jí)別越高,多事務(wù)并發(fā)時(shí),并發(fā)越差。因?yàn)楣蚕淼臄?shù)據(jù)越來(lái)越少,事務(wù)間阻塞情況增多。

16.3.1.3 并發(fā)問(wèn)題

事務(wù)并發(fā)時(shí)的安全問(wèn)題

問(wèn)題描述
臟讀一個(gè)事務(wù)讀取到另一個(gè)事務(wù)還未提交的數(shù)據(jù)。大于等于 read-commited 可防止
不可重復(fù)讀一個(gè)事務(wù)內(nèi)多次讀取一行數(shù)據(jù)的相同內(nèi)容,其結(jié)果不一致。大于等于 repeatable-read 可防止
幻影讀幻讀,并不是說(shuō)兩次讀取獲取的結(jié)果集不同,幻讀側(cè)重的方面是某一次的 select 操作得到的結(jié)果所表征的數(shù)據(jù)狀態(tài)無(wú)法支撐后續(xù)的業(yè)務(wù)操作。更為具體一些:select 某記錄是否存在,不存在,準(zhǔn)備插入此記錄,但執(zhí)行 insert 時(shí)發(fā)現(xiàn)此記錄已存在,無(wú)法插入,此時(shí)就發(fā)生了幻讀。mysql 幻讀的詳解、實(shí)例及解決辦法 - SegmentFault 思否
16.3.2 傳播行為

propagation傳播行為

當(dāng)涉及到事務(wù)嵌套(Service調(diào)用Service)時(shí),可以設(shè)置:

  • SUPPORTS = 不存在外部事務(wù),則不開(kāi)啟新事務(wù);存在外部事務(wù),則合并到外部事務(wù)中。(適合查詢(xún))

  • REQUIRED = 不存在外部事務(wù),則開(kāi)啟新事務(wù);存在外部事務(wù),則合并到外部事務(wù)中。 (默認(rèn)值)(適合增刪改)

參考資料: 事務(wù)隔離級(jí)別和傳播行為_(kāi)Spring事務(wù)的傳播行為和隔離級(jí)別_weixin_39604685的博客-CSDN博客

16.3.3 讀寫(xiě)性

readonly 讀寫(xiě)性

  • true:只讀,可提高查詢(xún)效率。(適合查詢(xún))

  • false:可讀可寫(xiě)。 (默認(rèn)值)(適合增刪改)

16.3.4 事務(wù)超時(shí)

timeout事務(wù)超時(shí)時(shí)間

當(dāng)前事務(wù)所需操作的數(shù)據(jù)被其他事務(wù)占用,則等待。

  • 100:自定義等待時(shí)間100(秒)。
  • -1:由數(shù)據(jù)庫(kù)指定等待時(shí)間,默認(rèn)值。(建議)
16.3.5 事務(wù)回滾

rollback-for 回滾屬性

  • 如果事務(wù)中拋出 RuntimeException,則自動(dòng)回滾

  • 如果事務(wù)中拋出 CheckException(非運(yùn)行時(shí)異常 Exception),不會(huì)自動(dòng)回滾,而是默認(rèn)提交事務(wù)

  • 處理方案 : 將CheckException轉(zhuǎn)換成RuntimException上拋,或 設(shè)置 rollback-for=“Exception.class”

16.4 編織

將事務(wù)管理的Advice 切入需要事務(wù)的業(yè)務(wù)方法中

<aop:config><aop:pointcut expression="execution(* com.qf.spring.service.UserServiceImpl.*(..))" id="pc"/><!-- 組織切面 --><aop:advisor advice-ref="txManager" pointcut-ref="pc"/>
</aop:config>

基于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:aop="http://www.springframework.org/schema/aop"xmlns:context="http://www.springframework.org/schema/context"xmlns:tx="http://www.springframework.org/schema/tx"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/txhttp://www.springframework.org/schema/tx/spring-tx.xsd"><!--1. 配置事務(wù)管理器--><bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource" ref="dataSource"></property></bean><!--2. 配置 事務(wù)的通知--><tx:advice id="txadvice" transaction-manager="transactionManager"><tx:attributes><tx:method name="transferMoney" propagation="REQUIRED"/></tx:attributes></tx:advice><!--3.織入切面--><aop:config><!--配置切點(diǎn)--><aop:pointcut id="txpoint" expression="execution(* com.qf.service.impl.AccountServiceImpl.*(..))"/><!--配置切面--><aop:advisor advice-ref="txadvice" pointcut-ref="txpoint"></aop:advisor></aop:config></beans>    

十七、注解開(kāi)發(fā)

1.什么是注解

(1)注解是代碼特殊標(biāo)記,格式:@注解名稱(chēng)(屬性名稱(chēng)=屬性值, 屬性名稱(chēng)=屬性值…)

(2)使用注解,注解作用在類(lèi)上面,方法上面,屬性上面

(3)使用注解目的:簡(jiǎn)化 xml 配置

2.spring針對(duì)Bean管理創(chuàng)建對(duì)象提供的注解

(1)@Component

(2)@Service

(3)@Controller

(4)@Repository

上面四個(gè)注解功能是一樣的,都可以用來(lái)創(chuàng)建 bean 實(shí)例

3.基于注解方式 實(shí)現(xiàn)對(duì)象創(chuàng)建

1.需要aop 依賴(lài)的支持 spring-aop

2.開(kāi)啟組件掃描

1 如果掃描多個(gè)包,多個(gè)包使用逗號(hào)隔開(kāi) 2 掃描包上層目錄
<?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"xmlns:p="http://www.springframework.org/schema/p"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd"><!--    掃描--><context:component-scan base-package="com.glls"></context:component-scan></beans>

3.創(chuàng)建類(lèi) 在類(lèi)上添加創(chuàng)建bean 的注解

//在注解里面 value 屬性值可以省略不寫(xiě),

//默認(rèn)值是類(lèi)名稱(chēng),首字母小寫(xiě)

//UserService – userService

4.開(kāi)啟組件掃描細(xì)節(jié)配置

 <!--下面的配置 是 只掃描Controller<context:component-scan base-package="com.glls" use-default-filters="false"><context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/></context:component-scan>--><!--下面的配置 是 忽略Controller<context:component-scan base-package="com.glls" ><context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/></context:component-scan>--><!--掃描該包下 的所有注解--><context:component-scan base-package="com.glls" ></context:component-scan>

5.基于注解的方式 實(shí)現(xiàn)屬性注入

(1)@Autowired:先根據(jù)類(lèi)型注入 再根據(jù)名字注入

第一步 把 service 和 dao 對(duì)象創(chuàng)建,在 service 和 dao 類(lèi)添加創(chuàng)建對(duì)象注解

第二步 在 service 注入 dao 對(duì)象,在 service 類(lèi)添加 dao 類(lèi)型屬性,在屬性上面使用注解

@Service public class UserService { //定義 dao 類(lèi)型屬性 //不需要添加 set 方法 //添加注入屬性注解 @Autowired  private UserDao userDao; public void add() { System.out.println("service add......."); userDao.add(); } }

(2)@Qualifier:根據(jù)名稱(chēng)進(jìn)行注入

這個(gè)@Qualifier 注解的使用,和上面@Autowired 一起使用

//定義 dao 類(lèi)型屬性 //不需要添加 set 方法//添加注入屬性注解 @Autowired //根據(jù)類(lèi)型進(jìn)行注入 @Qualifier(value = "userDaoImpl1") //根據(jù)名稱(chēng)進(jìn)行注入 private UserDao userDao;

(3)@Resource:先根據(jù)名字注入 再根據(jù)類(lèi)型注入

//@Resource //根據(jù)類(lèi)型進(jìn)行注入 @Resource(name = "userDaoImpl1") //根據(jù)名稱(chēng)進(jìn)行注入 private UserDao userDao; 

(4)@Value:注入普通類(lèi)型屬性

@Value(value = "abc") private String name;

6、完全注解開(kāi)發(fā)

(1)創(chuàng)建配置類(lèi),替代 xml 配置文件

@Configuration //作為配置類(lèi),替代 xml 配置文件 @ComponentScan(basePackages = {"com.glls"}) public class SpringConfig { } 

(2)編寫(xiě)測(cè)試類(lèi)

@Test public void testService2() { //加載配置類(lèi) ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class); UserService userService = context.getBean("userService",  UserService.class); System.out.println(userService); userService.add(); }

[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來(lái)直接上傳(img-2kf3XTow-1682258194561)(D:\前鋒學(xué)習(xí)筆記\筆記\image-20230423162534899.png)]


17.1 聲明bean

用于替換自建類(lèi)型組件的 <bean…>標(biāo)簽;可以更快速的聲明bean

  • @Service 業(yè)務(wù)類(lèi)專(zhuān)用
    @Repository dao實(shí)現(xiàn)類(lèi)專(zhuān)用
    @Controller web層專(zhuān)用

  • @Component 通用

  • @Scope 用戶(hù)控制bean的創(chuàng)建模式

// @Service說(shuō)明 此類(lèi)是一個(gè)業(yè)務(wù)類(lèi),需要將此類(lèi)納入工廠  等價(jià)替換掉 <bean class="xxx.UserServiceImpl">
// @Service默認(rèn)beanId == 首字母小寫(xiě)的類(lèi)名"userServiceImpl"
// @Service("userService") 自定義beanId為"userService"
@Service //聲明bean,且id="userServiceImpl"
@Scope("singleton") //聲明創(chuàng)建模式,默認(rèn)為單例模式 ;@Scope("prototype")即可設(shè)置為多例模式
public class UserServiceImpl implements UserService {...   
}

17.2 注入(DI)

用于完成bean中屬性值的注入

  • @Autowired 基于類(lèi)型自動(dòng)注入 先根據(jù)類(lèi)型注入 如果找到多個(gè) 再根據(jù)名稱(chēng)注入
  • @Resource 基于名稱(chēng)自動(dòng)注入 先根據(jù)名稱(chēng)注入 如果根據(jù)名稱(chēng)沒(méi)找到 則根據(jù)類(lèi)型找 根據(jù)類(lèi)型 找到多個(gè) 則報(bào)錯(cuò) 找到一個(gè)則注入
  • @Qualifier(“userDAO”) 限定要自動(dòng)注入的bean的id,一般和@Autowired聯(lián)用
  • @Value 注入簡(jiǎn)單類(lèi)型數(shù)據(jù) (jdk8種+String)
@Service
public class UserServiceImpl implements UserService {@Autowired //注入類(lèi)型為UserDAO的bean@Qualifier("userDAO2") //如果有多個(gè)類(lèi)型為UserDAO的bean,可以用此注解從中挑選一個(gè)private UserDAO userDAO;
}
@Service
public class UserServiceImpl implements UserService {@Resource("userDAO3") //注入id=“userDAO3”的beanprivate UserDAO userDAO;/*@Resource //注入id=“userDAO”的beanprivate UserDAO userDAO;*/
}
public class XX{@Value("100") //注入數(shù)字private Integer id;@Value("shine") //注入Stringprivate String name;
}

17.3 事務(wù)控制

用于控制事務(wù)切入

  • @Transactional

  • 工廠配置中的 <tx:advice… 和 <aop:config… 可以省略 !!

//類(lèi)中的每個(gè)方法都切入事務(wù)(有自己的事務(wù)控制的方法除外)
@Transactional(isolation=Isolation.READ_COMMITTED,propagation=Propagation.REQUIRED,readOnly=false,rollbackFor=Exception.class,timeout = -1)
public class UserServiceImpl implements UserService {...//該方法自己的事務(wù)控制,僅對(duì)此方法有效@Transactional(propagation=Propagation.SUPPORTS)public List<User> queryAll() {return userDao.queryAll();}public void save(User user){userDao.save(user);}
}

17.4 注解所需配置

<!-- 告知spring,哪些包中 有被注解的類(lèi)、方法、屬性 -->
<!-- <context:component-scan base-package="com.qf.a,com.xx.b"></context:component-scan> -->
<context:component-scan base-package="com.qf"></context:component-scan><!-- 1. 引入一個(gè)事務(wù)管理器,其中依賴(lài)DataSource,借以獲得連接,進(jìn)而控制事務(wù)邏輯 --><bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource" ref="dataSource"></property></bean><!--    開(kāi)啟事務(wù)的注解--><tx:annotation-driven transaction-manager="transactionManager"/>

17.5 AOP開(kāi)發(fā)

17.5.1 注解使用
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;@Aspect // 聲明此類(lèi)是一個(gè)切面類(lèi):會(huì)包含切入點(diǎn)(pointcut)和通知(advice)
@Component //聲明組件,進(jìn)入工廠
public class MyAspect {// 定義切入點(diǎn)@Pointcut("execution(* com.qf.spring.service.UserServiceImpl.*(..))")public void pc(){}@Before("pc()") // 前置通知public void mybefore(JoinPoint a) {System.out.println("target:"+a.getTarget());System.out.println("args:"+a.getArgs());System.out.println("method's name:"+a.getSignature().getName());System.out.println("before~~~~");}@AfterReturning(value="pc()",returning="ret") // 后置通知public void myAfterReturning(JoinPoint a,Object ret){System.out.println("after~~~~:"+ret);}@Around("pc()") // 環(huán)繞通知public Object myInterceptor(ProceedingJoinPoint p) throws Throwable {System.out.println("interceptor1~~~~");Object ret = p.proceed();System.out.println("interceptor2~~~~");return ret;}@AfterThrowing(value="pc()",throwing="ex") // 異常通知public void myThrows(JoinPoint jp,Exception ex){System.out.println("throws");System.out.println("===="+ex.getMessage());}
}
17.5.2 配置
<!-- 添加如下配置,啟用aop注解 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>

十八、集成JUnit


18.1 導(dǎo)入依賴(lài)

<dependency><groupId>org.springframework</groupId><artifactId>spring-test</artifactId><version>4.3.6.RELEASE</version>
</dependency>
<dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version>
</dependency>

18.2 編碼

可以免去工廠的創(chuàng)建過(guò)程;

可以直接將要測(cè)試的組件注入到測(cè)試類(lèi)。

@RunWith(SpringJUnit4ClassRunner.class) //由SpringJUnit4ClassRunner啟動(dòng)測(cè)試
@ContextConfiguration("classpath:applicationContext.xml") //spring的配置文件位置
public class SpringTest{//當(dāng)前測(cè)試類(lèi)也會(huì)被納入工廠中,所以其中屬性可以注入@Autowired // 注入要測(cè)試的組件@Qualifier("userDAO")private UserDAO userDAO;@Testpublic void test(){// 測(cè)試使用userDAOuserDAO.queryUser();....}
}

集成Junit 5

    <!--spring整合 junit 5 --><dependency><groupId>org.springframework</groupId><artifactId>spring-test</artifactId><version>5.2.9.RELEASE</version></dependency><dependency><groupId>org.junit.jupiter</groupId><artifactId>junit-jupiter-api</artifactId><version>5.5.2</version><scope>test</scope></dependency>

測(cè)試類(lèi)

@SpringJUnitConfig(locations = "classpath:applicationContext2.xml")
class OrderServiceImplTest {@Autowiredprivate OrderService orderService;@Testvoid findOrderByUserId() {List<Order> orderByUserId = orderService.findOrderByUserId(10);}
}

十九、個(gè)人擴(kuò)展

spring5 新的模塊 webflux

1、SpringWebflux 介紹

(1)是 Spring5 添加新的模塊,用于 web 開(kāi)發(fā)的,功能和 SpringMVC 類(lèi)似的,Webflux 使用 當(dāng)前一種比較流程響應(yīng)式編程出現(xiàn)的框架。

image-20210806205431737

(2)使用傳統(tǒng) web 框架,比如 SpringMVC,這些基于 Servlet 容器,Webflux 是一種異步非阻 塞的框架,異步非阻塞的框架在 Servlet3.1 以后才支持,核心是基于 Reactor 的相關(guān) API 實(shí)現(xiàn) 的。

(3)解釋什么是異步非阻塞

  • 異步和同步
  • 非阻塞和阻塞
  • 上面都是針對(duì)對(duì)象不一樣
  • 異步和同步針對(duì)調(diào)用者,調(diào)用者發(fā)送請(qǐng)求,如果等著對(duì)方回應(yīng)之后才去做其他事情就是同 步,如果發(fā)送請(qǐng)求之后不等著對(duì)方回應(yīng)就去做其他事情就是異步
  • 阻塞和非阻塞針對(duì)被調(diào)用者,被調(diào)用者受到請(qǐng)求之后,做完請(qǐng)求任務(wù)之后才給出反饋就是阻 塞,受到請(qǐng)求之后馬上給出反饋然后再去做事情就是非阻塞

(4)Webflux 特點(diǎn):

第一 非阻塞式:在有限資源下,提高系統(tǒng)吞吐量和伸縮性,以 Reactor 為基礎(chǔ)實(shí)現(xiàn)響應(yīng)式編程

第二 函數(shù)式編程:Spring5 框架基于 java8,Webflux 使用 Java8 函數(shù)式編程方式實(shí)現(xiàn)路由請(qǐng)求

(5)比較 SpringMVC

image-20210806205708184

第一 兩個(gè)框架都可以使用注解方式,都運(yùn)行在 Tomet 等容器中

第二 SpringMVC 采用命令式編程,Webflux 采用異步響應(yīng)式編程

2、響應(yīng)式編程(Java 實(shí)現(xiàn))

(1)什么是響應(yīng)式編程 響應(yīng)式編程是一種面向數(shù)據(jù)流和變化傳播的編程范式。這意味著可以在編程語(yǔ)言中很方便 地表達(dá)靜態(tài)或動(dòng)態(tài)的數(shù)據(jù)流,而相關(guān)的計(jì)算模型會(huì)自動(dòng)將變化的值通過(guò)數(shù)據(jù)流進(jìn)行傳播。 電子表格程序就是響應(yīng)式編程的一個(gè)例子。單元格可以包含字面值或類(lèi)似"=B1+C1"的公 式,而包含公式的單元格的值會(huì)依據(jù)其他單元格的值的變化而變化。

3.手寫(xiě)spring 偽源碼

  • 創(chuàng)建maven工程 無(wú)需添加任何依賴(lài)

image-20210628174533499

  • 在spring包下創(chuàng)建容器類(lèi) GllsApplicationContext

    • 
      

二十 個(gè)人源碼解析

個(gè)人學(xué)習(xí)

源碼分析

image-20210731150909753

image-20210731150926698

ClassPathXmlApplicationContext:

image-20210731151321658

super(parent); 此時(shí) 傳進(jìn)來(lái)的super 為空, 在這個(gè)方法中 調(diào)父類(lèi)AbstractApplicationContext 構(gòu)造方法 創(chuàng)建了資源解析器

/**
Create a new AbstractApplicationContext with no parent.
*/
public AbstractApplicationContext() {
this.resourcePatternResolver = getResourcePatternResolver();
}

setConfigLocations(configLocations);

image-20210731170316872
image-20210731170329424
image-20210731170341320
image-20210731170621745

image-20210731170640411

調(diào)父類(lèi)構(gòu)造

image-20210731170733825

image-20210731170751050

這個(gè)方法由子類(lèi)重寫(xiě)

image-20210731170819152
image-20210731170858551
image-20210731170927146

總結(jié): resolvePath(String path) 方法做了什么事情?

1.實(shí)例化 Environment

2.解析傳進(jìn)來(lái)的 path


refresh()方法

AbstractApplicationContext 類(lèi)中
@Overridepublic void refresh() throws BeansException, IllegalStateException {synchronized (this.startupShutdownMonitor) {// Prepare this context for refreshing.prepareRefresh();// Tell the subclass to refresh the internal bean factory.ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();// Prepare the bean factory for use in this context.prepareBeanFactory(beanFactory);try {// Allows post-processing of the bean factory in context subclasses.postProcessBeanFactory(beanFactory);// Invoke factory processors registered as beans in the context.invokeBeanFactoryPostProcessors(beanFactory);// Register bean processors that intercept bean creation.registerBeanPostProcessors(beanFactory);// Initialize message source for this context.initMessageSource();// Initialize event multicaster for this context.initApplicationEventMulticaster();// Initialize other special beans in specific context subclasses.onRefresh();// Check for listener beans and register them.registerListeners();// Instantiate all remaining (non-lazy-init) singletons.finishBeanFactoryInitialization(beanFactory);// Last step: publish corresponding event.finishRefresh();}catch (BeansException ex) {if (logger.isWarnEnabled()) {logger.warn("Exception encountered during context initialization - " +"cancelling refresh attempt: " + ex);}// Destroy already created singletons to avoid dangling resources.destroyBeans();// Reset 'active' flag.cancelRefresh(ex);// Propagate exception to caller.throw ex;}finally {// Reset common introspection caches in Spring's core, since we// might not ever need metadata for singleton beans anymore...resetCommonCaches();}}}
http://www.risenshineclean.com/news/36289.html

相關(guān)文章:

  • 軟件項(xiàng)目管理名詞解釋seo矩陣培訓(xùn)
  • vs網(wǎng)站開(kāi)發(fā)效果圖手機(jī)免費(fèi)建網(wǎng)站
  • 北京微網(wǎng)站建設(shè)設(shè)計(jì)服務(wù)公司東莞網(wǎng)絡(luò)公司網(wǎng)絡(luò)推廣
  • 建設(shè)銀行網(wǎng)站首頁(yè)口關(guān)鍵詞優(yōu)化方法有什么步驟
  • 網(wǎng)站建設(shè)需要會(huì)什么軟件有哪些內(nèi)容seo網(wǎng)站推廣工作內(nèi)容
  • 免費(fèi)h5網(wǎng)站模版谷歌seo服務(wù)
  • 瑞安做網(wǎng)站百度云盤(pán)官網(wǎng)登錄入口
  • 成都建設(shè)工程交易中心網(wǎng)站深圳seo招聘
  • 扁平化企業(yè)網(wǎng)站媒體發(fā)布平臺(tái)
  • 廈門(mén)網(wǎng)站制作費(fèi)用怎么搭建屬于自己的網(wǎng)站
  • 服裝購(gòu)物網(wǎng)站建設(shè)網(wǎng)絡(luò)營(yíng)銷(xiāo)組織的概念
  • 如何制作一個(gè)官網(wǎng)sem優(yōu)化軟件選哪家
  • 開(kāi)一個(gè)網(wǎng)站建設(shè)公司外鏈工具xg
  • 怎么給公司做微網(wǎng)站軟文關(guān)鍵詞排名推廣
  • 石家莊新聞網(wǎng)seo推廣服務(wù)哪家好
  • 站長(zhǎng)工具seo綜合查詢(xún)排名怎么做關(guān)鍵詞排名靠前
  • 香港vps可看netflix東營(yíng)seo網(wǎng)站推廣
  • 做電子商務(wù)系統(tǒng)網(wǎng)站建設(shè)怎么推廣產(chǎn)品最有效
  • 如何在百度上做網(wǎng)站品牌策劃書(shū)
  • 福州交通建設(shè)集團(tuán)官方網(wǎng)站軟文營(yíng)銷(xiāo)寫(xiě)作技巧
  • 建設(shè)工程施工合同條例湖北搜索引擎優(yōu)化
  • 織夢(mèng)映像網(wǎng)絡(luò)推廣seo怎么弄
  • 企業(yè) 網(wǎng)站 程序愛(ài)站網(wǎng)關(guān)鍵詞查詢(xún)
  • 如何用vps做網(wǎng)站中央新聞
  • 網(wǎng)站如何制作浙江技能培訓(xùn)班
  • 做電商的批發(fā)網(wǎng)站可以直接進(jìn)入的輿情網(wǎng)站
  • 扶貧基金會(huì)網(wǎng)站建設(shè)是哪家公司班級(jí)優(yōu)化大師官方網(wǎng)站
  • 中國(guó)設(shè)計(jì)聯(lián)盟官網(wǎng)短視頻入口seo
  • 網(wǎng)站網(wǎng)頁(yè)設(shè)計(jì)內(nèi)容百度網(wǎng)盤(pán)客服在線咨詢(xún)
  • 做網(wǎng)站橫幅用什么軟件好河南網(wǎng)站關(guān)鍵詞優(yōu)化