Spring框架 --- 深入

来源:https://www.cnblogs.com/zhangze-lifetime/archive/2019/10/30/11768566.html
-Advertisement-
Play Games

1.Spring IOC IOC技術: 控制反轉,也叫(依賴註入) 控制反轉:Bean的生命周期不受你控制,而是交給Spring容器管理。 Spring框架如何利用IOC ?: 實現了控制反轉,Spring容器能幫我們實例化對象,但是並沒有做到DI(依賴註入)。 作用: (1) 構建Bean (2) ...


1.Spring IOC

  IOC技術: 控制反轉,也叫(依賴註入)

  控制反轉:Bean的生命周期不受你控制,而是交給Spring容器管理。

  Spring框架如何利用IOC ?:
          實現了控制反轉,Spring容器能幫我們實例化對象,但是並沒有做到DI(依賴註入)。

  作用:
        (1) 構建Bean
        (2) Bean之間有依賴關係的話,可以自動幫我們註入
    優勢:
        解耦:低耦合,實現面向介面的編程思想

2.Spring AOP

  動態代理設計模式
      原理和靜態代理設計模式沒有本質區別:
          被代理類、代理類、被代理和代理類是同一個介面
          代理類的創建過程有區別:
          (1)靜態代理:
                  自己編寫代理類,代理類自己實現介面
          (2)動態代理:
                  代理類不需要自己編寫,他Proxy.newProxyinstance(xx)靜態方法
                  在程式執行過程中,動態產生代理類
                  InvocationHandler:裡邊含有被代理類的引用

   AOP:面向切麵的編程

  代理模式主要的作用:
          在業務代碼不之情的情況下,切入額外的功能。
    原理:Spring框架具有IOC的功能,所以我們可以利用該功能配置業務Bean 。代理設計模式(動態)
        例如: AccountServiceImpl
        <bean id="AccountServiceImpl" class="service.AccountServiceImpl"></bean>
        然後,Spring框架利用動態代理設計模式創建一個AccountServiceImpl的動態代理對象
        然後就可以在AccountServiceImpl的業務方法的基礎上增加相應的功能。
        那Spring把這種技術稱為AOP面向切麵的編程,其實就是在程式員不知情的情況下在其業務方法上切入額外的功能。

 

  使用 XML 配置實現具體的操作:
      (1)使用Spring的AOP功能,就需要引入jar  pom.xml
      (2)自己編寫切麵。很類似於InvocationHandler
          被代理介面   :  業務介面
          被代理類: 實現了被代理口,被代理類也叫業務實現類;
          例子:class CalFfabImpl implements ICalFab

代碼示例:

  Maven項目

  pom.xml 添加的插件  

<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjrt -->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
            <version>1.8.10</version>
        </dependency>       
 <!-- https://mvnrepository.com/artifact/aopalliance/aopalliance -->
        <dependency>
            <groupId>aopalliance</groupId>
            <artifactId>aopalliance</artifactId>
            <version>1.0</version>
        </dependency>
        
        <!-- https://mvnrepository.com/artifact/org.aspectj/aspectjrt -->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.8.10</version>
        </dependency>
                
        <!-- https://mvnrepository.com/artifact/org.springframework/spring-aop -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>${spring.version}</version>
        </dependency>            

 

  添加資源配置文件 beans.xml

<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
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd">
    <!-- Spring IOC --> 
   <bean id="calFab" class="day02.aop.CalFabImpl"></bean>
   <bean id="selfAspectRef" class="day02.aop.SelfAspect"></bean>
   
   <!-- Spring Aop 配置切麵 -->
   <aop:config>
           <!-- 配置切麵 -->
           <aop:aspect ref="selfAspectRef">
               <!-- 切點  在CalFabImpl類的任何方法上加通知 -->
               <aop:pointcut expression="execution(* day02.aop.CalFabImpl.*(..))" id="selfPointcut"/>
               <!-- 通知 -->
               <aop:before method="testBefore" pointcut-ref="selfPointcut"/>
               <aop:after method="testAfter" pointcut-ref="selfPointcut"/>
               <aop:around method="testAround" pointcut-ref="selfPointcut"/>
           </aop:aspect>
   </aop:config>
   
</beans>

 

  新建介面 ICalFab.java

 1 /**
 2  * 業務介面
 3  * @author 張澤
 4  */
 5 public interface ICalFab {
 6     
 7     int calFaByLoop(int n);
 8     int calFabByRecursion(int n); 
 9 
10 }

 

  新建類實現介面:

/**
 * 業務實現類:被代理類
 * @author 張澤
 */
class CalFabImpl implements ICalFab{
    @Override
    public int calFaByLoop(int n) {
        int n1=1,n2= 1,n3=0;
        for (int i = 3; i < n; i++) {
            n3=n1+n2;
            n1=n2;
            n2=n3;
        }
        return n3;
    }
    @Override
    public int calFabByRecursion(int n) {
        if(n==1||n==2) return 1;
        return calFabByRecursion(n-1)+calFabByRecursion(n-2);
        
    }
    
    
}

 

  新建類:SelfAspect.java

import org.aspectj.lang.ProceedingJoinPoint;

/**
 * 自定義功能性切麵:利用xml配置實現。
 * @author 張澤
 *
 */
public class SelfAspect {
    //--通知:Before類型的Advice
    public void testBefore() {
        System.out.println("before do something...");
    }
    //--通知:after類型的通知
    public void testAfter() {
        System.out.println("after do Something...");
    }
    //-- 通知:Around環繞   通知方法的執行點
    public int testAround(ProceedingJoinPoint jp) {
        int result = 0;
        try {
            long start = System.currentTimeMillis();
            result = (int)jp.proceed();    //-- 執行業務方法
            long end = System.currentTimeMillis();
            System.out.println(end-start+"ms");
        } catch (Throwable e) {
            e.printStackTrace();
        }    
        return result;
    }
} 

 

  新建調用類:Invoker.java

 

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * Invoker類
 * 功能切入更加靈活
 * @author 張澤
 *
 */
public class Invoker {
    public static void main(String[] args) {
        //-- 1. Spring容器
        ApplicationContext ctx =
                new ClassPathXmlApplicationContext("application.xml");
        //-- 2. 獲取業務類
        ICalFab calFab= (ICalFab)ctx.getBean("calFab");
        //-- 3. 調用業務方法
        System.out.println(calFab.calFaByLoop(40));
        System.out.println(calFab.calFabByRecursion(40));
        System.out.println(calFab instanceof ICalFab);
        
    }
}

 

 

 

 

  使用 註解 配置實現具體的操作:

    (1) Config類來代替xml的配置
          @EnableAspectJAutoProxy //-- 啟用SpringAop的功能
          //-- 啟用Spring的IOC功能
          @Configuration
          @ComponentScan({"package1","package2"})
      (2)編寫切麵。

 

代碼示例:

  新建介面 ICalFab.java 

/**
 * 業務介面
 * @author 張澤
 *
 */

public interface ICalFab {
    
    int calFaByLoop(int n);
    int calFabByRecursion(int n); 

}

 

  新建實現類 CalFabImpl.java

import org.springframework.stereotype.Component;

/**
 * 業務實現類:被代理類
 * @author 張澤
 */
@Component    //-- Spring IOC
class CalFabImpl implements ICalFab{
    @Override
    public int calFaByLoop(int n) {
        int n1=1,n2= 1,n3=0;
        for (int i = 3; i < n; i++) {
            n3=n1+n2;
            n1=n2;
            n2=n3;
        }
        return n3;
    }
    @Override
    public int calFabByRecursion(int n) {
        if(n==1||n==2) return 1;
        return calFabByRecursion(n-1)+calFabByRecursion(n-2);
        
    }
    
    
}

 

  新建配置類 AppConfig.java

 

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

/**
 * 配置類
 * @author 張澤
 * 實現IOC功能
 * 
 */
@Configuration
@EnableAspectJAutoProxy //-- 啟用SpringAop的功能
@ComponentScan("day.annocation")//-- 包名
public class AppConfig {
//    @Bean
//    public ICalFab calFabBean() {
//        return new CalFabImpl();
//    }
}

 

 

 

 

  新建類:SelfAspect.java

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

/**
 * 利用標註自定義切麵
 * @author 張澤
 *
 */
@Aspect
@Component
public class SelfAspect {
    
    //-- 1. 自定義切點,指定目標方法的位置
    @Pointcut("execution(* day02.annocation.CalFabImpl.*(..))")
    public void selfPointcut() {
        
    }
    //-- 2. 通知
    @Before("selfPointcut()")
    public void testBefore() {
        System.out.println("before do something...");
    }
    
    @After("selfPointcut()")
    public void testAfter() {
        System.out.println("After do something...");
    }
    @Around("selfPointcut()")
    public int testAround(ProceedingJoinPoint jp) {
        int result = 0;
        try {
            long start = System.currentTimeMillis();
            result = (int)jp.proceed();    //-- 執行業務方法
            long end = System.currentTimeMillis();
            System.out.println(end-start+"ms");
        } catch (Throwable e) {
            e.printStackTrace();
        }    
        return result;
    }
}

 

  新建類:Invoker.java

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Invoker {
    public static void main(String[] args) {
        //-- 1.構造Spring容器
        ApplicationContext ctx = 
                new AnnotationConfigApplicationContext(AppConfig.class);
        //-- 2.獲取Beans
        ICalFab calFab =(ICalFab)ctx.getBean("calFabImpl");//-- 預設是類名首字母小寫
        calFab.calFabByRecursion(40);
        
        //-- Web伺服器啟動的時候實例化一個Spring容器,在Web伺服器關閉的時候關閉Spring容器
        //-- Servlet的監聽
        //-- 容器關閉
        ((AnnotationConfigApplicationContext)ctx).close();
    }
}

 

 

 

3.Spring Test


     Spring 的測試框架建立在JUnit測試框架基礎上的,它是對JUnit的再次封裝。

使用:

  配置文件 pom.xml 引入插件

<!-- https://mvnrepository.com/artifact/junit/junit -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12-beta-3</version>
            <scope>test</scope>
        </dependency>
        <!-- Spring Test -->
        <!-- https://mvnrepository.com/artifact/org.springframework/spring-test -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>5.1.7.RELEASE</version>
            <scope>test</scope>
        </dependency>

 

示例測試工程的代碼:

/**
 * 業務介面
 * @author 張澤
 *
 */

public interface IUserService {
    void login();
}

 

 

import org.springframework.stereotype.Component;

/**
 * 業務實現類
 * @author 張澤
 *
 */
@Component
public class UserServiceImpl implements IUserService {

    @Override
    public void login() {
        System.out.println("login success");
        
    }

}

 

 

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

/**
 * Spring配置
 * @author 張澤
 *
 */
@Configuration
@ComponentScan("day03")
public class AppConfig {
    
    @Bean("hello")
    public String hello() {
        return "hello";
    }
}

 

 

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

/**
 * 調用
 * @author 張澤
 *
 */
public class Invoker {
    public static void main(String[] args) {
        //-- Spring COntainer
        ApplicationContext ctx = 
                new AnnotationConfigApplicationContext(AppConfig.class);
        //-- 2.
        System.out.println(ctx.getBean("hello"));
    }
}

 

 

JUnit測試代碼:

/**
 * 1. 先利用JUnit做單元測試
 * @author 張澤
 *
 */

import org.junit.Before;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class TestDemo {
    private ApplicationContext ctx;
    
    @Before
    public void before() {
        ctx = new AnnotationConfigApplicationContext(AppConfig.class);    
    }
    
    @Test
    public void test() {
        System.out.println(ctx.getBean("hello"));
    }
    
    
}

 

利用Spring test 框架測試:
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

/**
 * 2. 利用Spring test 框架
 * 
 * @RunWith: 實例化Spring容器
 * @ContextConfiguration: 指定Spring容器需要的配置類
 * 以後你會很少看到Spring容器了
 * 
 */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes= {AppConfig.class})
public class TestSpringDemo {
    @Autowired
    private String hi;
    @Autowired
    private IUserService userService;
    
    @Test
    public void test() {
        System.out.println(hi);
    }
    @Test
    public void test1() {
        userService.login();
    }
}

 

 

該項目的配置文件:pom.xml

<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.uek.course</groupId>
    <artifactId>spring-app</artifactId>
    <version>0.0.1</version>
    <packaging>war</packaging>

    <!-- 2. 項目屬性配置 -->
    <properties>
        <!-- 項目編碼使用UTF-8 -->
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <!-- 忽略掉web.xml文件 ,因為我們使用servlet3.0開發web項目 -->
        <failOnMissingWebXml>false</failOnMissingWebXml>
        <spring.version>5.1.7.RELEASE</spring.version>
    </properties>
    <!-- 3. 配置項目所需要的第三方jar 包 -->
    <dependencies>
        <!-- servlet api -->
        <!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
        <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>jstl</artifactId>
            <version>1.2</version>
        </dependency>

        <!-- MySQL資料庫連接池 -->
        <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.48</version>
        </dependency>

        <!-- Druid -->
        <!-- https://mvnrepository.com/artifact/com.alibaba/druid -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.20</version>
        </dependency>
        <!-- 單元測試 -->
        <!-- https://mvnrepository.com/artifact/junit/junit -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12-beta-3</version>
            <scope>test</scope>
        </dependency>
        <!-- Spring Test -->
        <!-- https://mvnrepository.com/artifact/org.springframework/spring-test -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>${spring.version}</version>
            <scope>test</scope>
        </dependency>
        
        
        <!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.springframework/spring-core -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring.version}</version>
        </dependency>
        
        
        <!-- https://mvnrepository.com/artifact/org.aspectj/aspectjrt -->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
            <version>1.8.10</version>
        </dependency>
        
        
        <!-- https://mvnrepository.com/artifact/aopalliance/aopalliance -->
        <dependency>
            <groupId>aopalliance</groupId>
            <artifactId>aopalliance</artifactId>
            <version>1.0</	   

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 安裝RabbitMQ,可以選擇使用Docker或者在CentOS下安裝RabbitMQ。這裡就不介紹這些高大上的安裝,就介紹在本地安裝吧。 第一步、下載並安裝erlang 為什麼要先下載安裝erlang呢?因為RabbitMQ服務端代碼是使用併發式語言Erlang編寫的,安裝RabbitMQ的前提是 ...
  • 事件起因 昨天有同事找我到,說他搭建的 XXL JOB 任務調度系統不能工作了,調用總是出錯(服務端返回 500)希望我能幫忙處理一下,不過說實話我也沒有搭建過 XXL JOB 的經驗,但是既然同事請求了,就只能硬著頭皮幫忙一起看下,解決的過程還算比較順利,但是發現網上這塊的資料很少,所以打算把解決 ...
  • 項目中要用到RabbitMQ,領導讓我先瞭解一下。在之前的公司中,用到過消息隊列MQ,阿裡的那款RocketMQ,當時公司也做了簡單的技術分享,自己也看了一些博客。自己在有道雲筆記上,做了一些整理,但後來也就擱在那了。現在有時間,就對MQ的一些簡單的概念做下整理吧。 RabbitMQ的一些介紹,請參 ...
  • 前段時間我朋友介紹我看一套b站Java教程 說這個教程是b站口碑最好的 我去看了一段時間 確實講的非常好 這套是求知講堂出的 網址:https://www.bilibili.com/video/av61604219 大家一起學習 有看過評價下這套教程 覺得他是不是b站最好的Java教程 ...
  • 今天,讓我們一起來探討 Java 併發編程中的知識點:volatile 關鍵字 本文主要從以下三點講解 volatile 關鍵字: 1. volatile 關鍵字是什麼? 2. volatile 關鍵字能解決什麼問題?使用場景是什麼? 3. volatile 關鍵字實現的原理? volatile 關 ...
  • 圖文簡介 邏輯關係 效果演示 快速開始 1、Spring Boot 應用暴露監控指標【版本 1.5.7.RELEASE】 首先,添加依賴如下依賴: 然後,在啟動類 添加如下註解: 最後,配置預設的登錄賬號和密碼,在 中: 提示:不建議配置 啟動應用程式後,會看到如下一系列的 Mappings 利用賬 ...
  • (手機橫屏看源碼更方便) 引子 大家知道,我最近在招人,今天遇到個同學,他的源碼看過一些,然後我就開始了AQS連環問。 我:說說AQS的大致流程? 他:AQS包含一個狀態變數,一個同步隊列……balabala……互斥鎖balabala,共用鎖balabala…… 我:AQS中除了同步隊列,還有什麼隊 ...
  • [TOC] 1. 概念 1.1 基本概念 時間,對於我們來說很重要,什麼時候做什麼?什麼時候發生什麼?沒有時間的概念,生活就亂了。 在日常的運維當中,我們更關註告警的時間:什麼時候發生、什麼事故、影響範圍、什麼時候解決,都是有關聯性的,所以時間的準確性是非常非常的重要。 你可能會好奇,時間到底是怎麼 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...