主頁 > 後端開發 > 【Java學習】 Spring的基礎理解 IOC、AOP以及事務

【Java學習】 Spring的基礎理解 IOC、AOP以及事務

2023-06-19 07:37:09 後端開發

一、簡介

    官網: https://spring.io/projects/spring-framework#overview     官方下載工具: https://repo.spring.io/release/org/springframework/spring/     github下載: https://github.com/spring-projects/spring-framework     maven依賴:
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>5.2.0.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>5.2.0.RELEASE</version>
</dependency>

  1.spring全家桶的結構構圖:

             最下邊的是測驗單元   其中spring封裝了自己的測驗單元
  1.  Core Container

    上邊一層(Core Container)是核心容器,也是spring框架的基礎 也是核心
  • core:提供了框架的基本組成部分  包括ioc和依賴注入功能
  • beans:提供了BeanFactory  實作了工廠模式,方便解耦
  • context:背景關系內容
  • expression:提供了強大的運算式語言,用于在運行時查詢和操作物件,

    3.Data Access/Integration 資料訪問/集成

  • 該模塊包含JDBC、ORM、OXM、JMS和事務處理模塊
  • JDBC:提供了JDBC的抽象層,可以更方便的處理資料庫
  • ORM:模塊提供了流行的物件關系型映射的API的集成
  • OXM:模塊提供了對OXM實作的支持(啥是OXM)
  • JMS:包含了生產和消費訊息的功能
  • 事務:毋庸置疑,可以實作特殊介面類以及所有的pojo支持編程式和宣告式事務管理,

     4.Web

            Web層由Web、Servlet、Web-Sockethe和Web-Portlet組成
  • Web模塊:提供面向web的基本功能和面向web的應用背景關系
  • Servlet模塊:為web應用提供了模型視圖看著(MVC)和RestWeb服務的實作,Spring的MVC框架可以將代碼與web表單進行分離,
  • Web-Socket
  • Web-Portlet
    5.AOP             Aop模塊提供了面向切面編程的實作,允許自定義放啊攔截器和切入點,對代碼繼續寧解耦,可以減少模塊間的耦合度,方便擴展和提高可維護性     6.Instrumentation     7.Messaging     8.Aspects             也是面向切面編程     9.Test

二、IOC:

  2.1理論:IOC也就是控制反轉             其基本理解就是Spring將創建物件的程序轉交給了IOC容器,,在其它類中我們只需要呼叫即可,不需要重新創建物件,         在我們傳統的三層架構模型中,目錄結構分別為pojo、dao、和service     當我們在service中呼叫dao時,常會使用到         private UserDao userDao=new UserDao();     這就是我們通常的思維,需要創建物件才可以使用,但是引入spring后,便可以使用<bean>標簽就可以創建物件,     2.2 Spring 中IOC的實作提供了兩種方式:         2.2.1BeanFactory:這是IOC的基本實作,是Spring的內部介面,不會提供給開發人員使用,         加載組態檔時,不會創建物件,只有在使用的時候才會創建物件(一會可以代碼解釋  注意的是getBean的動作)         2.2.2ApplicationContext 它是BeanFactory介面的子介面,提供了更加強大的功能開發人員進行加載組態檔的時候就進行了創建,
//1.引入jar包

//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:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">
配置物件  id為唯一限定名 一般為類名的小寫   class是類所在的位置
    <bean id="teacher" ></bean>
</beans>

//3.測驗
@Test
public void testTeacherCreate(){
    //加載組態檔
    ApplicationContext ac=new ClassPathXmlApplicationContext("applicationConfig.xml");
    Teacher teacher = ac.getBean("teacher", Teacher.class);
    System.out.println(teacher);
}

//在以上代碼中  如果使用的是ApplicationContext 則在進行加載組態檔時 就已經在IOC容器中創建好了teacher物件
//如果是使用的是 BeanFactory ac 創建物件,則在getbean時才會創建物件(不可操作,因為該介面不對開發人員透明)

2.2.3 ApplicationContext介面的實作類的繼承關系

由上圖可以看出,我們能使用的只有ClassPathXMlApplicationContext和FileSystemXmlApplicationContext來決議我們的xml組態檔, 其中Class開頭的可以去classpath路徑下去尋找 File開頭的可以加載磁盤路徑下的組態檔 之后我們還可以使用AnnotationconfigApplicationContext可以使用注解方式來創建容器,   2.3 IOC對Bean的管理     2.3.1 創建bean         bean就是我們所說的Java物件,在之前所學的創建Java物件,一般是使用new關鍵字 呼叫類中的構造器來創建物件,     因此創建bean的方法就可以有三種方式:使用默認的無參構造、使用簡單工廠方式創建、使用靜態工廠方式創建         A:使用默認的無參構造
<bean id="唯一標識" > </bean>

        B :使用普通工廠類創建bean實體

1.建立普通類teacher,包含個別屬性,并添加get、set方法

2.創建工廠類
public class SchoolFactory {
    Teacher teacher=new Teacher();
    public  Teacher getInstance(){
        return teacher;
    }
}
在工廠類中實體化物件,并添加一個普通方法可以獲取到物件

3.組態檔

<!--    普通工廠類創建bean實體-->
    <bean id="factory"  ></bean>
    <bean id="teacher1" factory-bean="factory" factory-method="getInstance"></bean>

第一個bean是一個實體化的物件也就是物件工廠
第二個bean 是利用物件工廠來創建的物件實體化
            factory標簽指的是  是哪個工廠物件,對應上邊的id
            factory-method指的是呼叫可以獲取物件實體的方法(普通方法)


4.測驗:

/**
* 測驗普通工廠類創建bean實體
*/
@Test
public void testTeacherFactory1(){
    //加載組態檔
    ApplicationContext ac=new ClassPathXmlApplicationContext("applicationConfig.xml");
    Teacher teacher1 = ac.getBean("teacher1", Teacher.class);
    System.out.println(teacher1);
}

如果在程式中可能需要頻繁的創建某個類的實體物件,采用工廠模式會更好

  2.3.2 依賴注入 也就是注入屬性               依賴注入也就是對屬性的注入,分為三種:構造器注入、set注入以及p標簽注入             其中的構造注入,需要走的是帶參構造             set注入,走的是set方法和無參構造             p標簽注入和set注入基本一樣,只不過頭檔案中需要引入           物件工廠介面中最基本的是BeanFactory,它可以支持懶加載,也就是在加載組態檔時,不會創建實體物件,而是在需要呼叫時才會創建,         如今使用的是applicationContext來決議組態檔,他的底層介面也是BeanFactory,但是它可以在加載組態檔的時候,就直接創建了bean實體,             以Student類作為演示
public class Student {
    private String sname;
    private int age;
    private String sex;


    public Student(String sname, int age, String sex) {
        this.sname = sname;
        this.age = age;
        this.sex = sex;
        System.out.println("這是三個引數的無參構造");
    }


    public Student(String sname, int age) {
        this.sname = sname;
        this.age = age;
        System.out.println("這是第一個屬性為name的兩個引數的構造");
    }
    public Student( int age,String sname) {
        this.sname = sname;
        this.age = age;
        System.out.println("這是第一個屬性為age的兩個引數的構造");


    }


    public Student() {
        System.out.println("這是無參構造");
    }




    public String getSname() {
        return sname;
    }


    public void setSname(String sname) {
        this.sname = sname;
    }


    public int getAge() {
        return age;
    }


    public void setAge(int age) {
        this.age = age;
    }


    public String getSex() {
        return sex;
    }


    public void setSex(String sex) {
        this.sex = sex;
    }


    @Override
    public String toString() {
        return "Student{" +
                "sname='" + sname + '\'' +
                ", age=" + age +
                ", sex='" + sex + '\'' +
                '}';
    }
}
  A 構造器注入 <constructor-arg>
<bean id="stu1" >
    <constructor-arg name="sname" value="https://www.cnblogs.com/qiang2023/archive/2023/06/18/zs"></constructor-arg>
    <constructor-arg name="age" value="https://www.cnblogs.com/qiang2023/archive/2023/06/18/15"></constructor-arg>
</bean>
看我們的物體類中就可以發現,我們的含有兩個引數的構造器,有兩個,在這個時候我們使用的構造器的建構式就不知道使用的是哪個帶參的構造器
因此我們可以使用 index來標識下標 就可以指定先執行那個代餐的構造

    其中constructor-arg中也可以使用type來標識引數型別來確定屬性
        如果是八大基本資料型別,則可以直接寫關鍵字,如果是其他型別,則需要添加類的全限定路徑

    如果其中還含有其他物件型別的引數,
    如此時的student類中包含屬性  private Grade grade;
    
    構造器:
        <bean>
        <construct-arg type="com.qiang.Grade" ref="grade"></construct-arg>
        </bean>
            
        <bean id="grade" ></bean>

   B set方法注入  此時需要在類中對屬性添加set方法 以及無參構造

<bean id="student2" >
        <property name="id" value="https://www.cnblogs.com/qiang2023/archive/2023/06/18/2"></property>
        <property name="name" value="https://www.cnblogs.com/qiang2023/archive/2023/06/18/李四"></property>
    </bean>

    C :p標簽注入 此時就要添加對應的set方法以及無參構造 以及添加頭檔案

    D:也可以set注入和構造器注入 混合使用 但是需要有對應的構造方法

  2.3.3   不同屬性型別對應的寫法:         由于我們的屬性的在不同的使用場景下可能有不同的屬性型別,如集合、陣列等情況,因此可能會需要使用到不同的標簽,下面只演示使用set方法注入的情況 那就意味著,我們需要添加構造方法和無參構造,
物體類
public class Order {
    private String [] cources;
    private List<String> lists;
    private Map<String,String> maps;
    private Set<String> sets;
組態檔

<!--    測驗不同屬性型別的屬性注入-->
    <bean id="order" >
<!--        陣列集合使用array標簽-->
        <property name="cources">
            <array>
                <value>美羊羊</value>
                <value>蘭羊羊</value>
            </array>
        </property>
<!--        list集合型別使用list標簽-->
        <property name="lists">
            <list>
                <value>舒克</value>
                <value>貝塔</value>
            </list>
        </property>
<!--        set集合使用set標簽-->
        <property name="sets">
            <set>
                <value>mysql</value>
                <value>javase</value>
                <value>javaweb</value>
            </set>
        </property>


        <property name="maps">
            <map>
                <entry key="java" value="https://www.cnblogs.com/qiang2023/archive/2023/06/18/我們在學習的語言"></entry>
                <entry key="web" value="https://www.cnblogs.com/qiang2023/archive/2023/06/18/前端的"></entry>
            </map>
        </property>
陣列型別的使用<array><value></value></array>     list類表型別的使用:<list><value></value></list>     set集合型別的使用<set><value></value></set>     map集合型別的使用<map><entry key="" value=""></entry></map>   2.4 Bean的作用域: scope屬性
  • singleton:默認值  單例模式 每次獲取的bean都是同一個物件
  • prototype:每次獲取bean都會被重新實體化
  • request:每次請求都會重新實體化物件,但是在同一請求下獲取的情況下的bean是單例的
  • session  每次會話內的bean是單例的
  • application:整個應用程式物件內的bean實體都是單例模式的
  • websocket:同一個websocket物件內的物件是單例的,
Singleton
<!--    測驗單例模式-->
    <bean id="stu3"  scope="singleton"></bean>

測驗類:

@Test
public void testStudent3(){
    //加載組態檔
    BeanFactory ac=new ClassPathXmlApplicationContext("applicationConfig2.xml");
    Student stu1 = ac.getBean("stu3", Student.class);
    System.out.println(stu1);
    Student stu2 = ac.getBean("stu3", Student.class);
    System.out.println(stu2);
    System.out.println(stu1==stu2);
}

結果:
com.qiang.pojo.Student@10a035a0
com.qiang.pojo.Student@10a035a0
true
prototype

<!--    測驗多例模式-->
<bean id="stu4"  scope="prototype"></bean>

測驗類

@Test
public void testStudent4(){
    //加載組態檔
    BeanFactory ac=new ClassPathXmlApplicationContext("applicationConfig2.xml");
    Student stu1 = ac.getBean("stu4", Student.class);
    System.out.println(stu1);
    Student stu2 = ac.getBean("stu4", Student.class);
    System.out.println(stu2);
    System.out.println(stu1==stu2);
}

結果:
com.qiang.pojo.Student@10a035a0
com.qiang.pojo.Student@67b467e9
false
2.5  bean的生命周期      2.5.1 一般理解下的bean的生命周期:
  • 通過構造器創建bean實【此時執行的是無參構造】
  • 為bean屬性設定值以及對其他的bean的參考【set注入】
  • 呼叫bean的初始化方法,在組態檔中配置
  • bean物件可以使用了 【已經獲取到了物件】
  • 當容器關閉時,呼叫bean的銷毀方法【在組態檔中配置】
物體類物件
public class People implements Serializable {
    private String oid;
    public People() {
        System.out.println("第一步:執行無參構造");
    }
    public String getOid() {
        return oid;
    }
    public void setOid(String oid) {
        this.oid = oid;
        System.out.println("第二步: 呼叫set方法給屬性設定值......");
    }
    public void initMethod(){
        System.out.println("第三步:執行初始化方法............");
    }
    public void destroyMethod(){
        System.out.println("第五步:執行銷毀方法............");
    }
    @Override
    public String toString() {
        return "People{" +
                "oid='" + oid + '\'' +
                '}';
    }
}
組態檔  添加初始化方法 和銷毀方法
<bean id="people"  
    init-method="initMethod" 
    destroy-method="destroyMethod">
</bean>
其中的標簽init-method、destroy-method 中的方法是在物體類中自定義的

 測驗類

/**
* 測驗bean的生命周期
*/
@Test
public void testBeanLive(){
    //加載組態檔
    ClassPathXmlApplicationContext ac=new ClassPathXmlApplicationContext("applicationConfig2.xml");
    //獲取bean實體
    People people = ac.getBean("people", People.class);
    System.out.println("第四步:獲取bean實體物件 ,,,");
    System.out.println(people);
    //手動銷毀
    ac.close();
}



結果:
第一步:執行無參構造
第三步:執行初始化方法............
第四步:獲取bean實體物件 ,,,
People{oid='null'}
第五步:執行銷毀方法............

 

  2.5.2 添加后置處理器的生命周期的方法
  • 第一步:執行無引數的構造方法 ,,,
  • 第二步: 呼叫set方法給屬性設定值......
  • 在初始化之前執行的方法
  • 第三步:執行初始化方法............
  • 在初始化之后執行的方法
  • 第四步:獲取bean實體物件 ,,,
  • 第五步:執行銷毀方法............

 

在物體類中 實作了BeanPostProcessor介面
    并重寫了
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    System.out.println("在初始化之前執行的方法");
    return bean;
}


@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    System.out.println("在初始化之后執行的方法");


    return bean;
}

 

  2.6 自動裝配:     裝配的意思是 就是怎么去創建物件 spring的裝配方式有三種:         在xml中顯示的裝配 也就是使用<bean>標簽         在Java中的顯示配置 new關鍵字         自動裝配機制           Spring的自動裝配你有兩個角度的實作             分別是 組件掃描和 自動裝配                 組件掃描:spring 回自動發現應用背景關系中所創建的bean                 自動裝配:spring自動滿足bean之間的依賴,也就是使用IOC和DI      自動裝配的實作方式有兩種,一種是通過xml的bena標簽 也可以使用注解方式         2.6.1  通過XMl中的標簽 自動裝配          A:byName 按名稱自動裝配         通俗理解:在xml組態檔中 使用bean標簽 通過bynae自動諸如和,每次遇到名稱為 byname屬性值時就自動創建物件
物體類Dog
private String color;
private int age;


組態檔
<bean id="d1"  autowire="byName">
    <property name="age" value="https://www.cnblogs.com/qiang2023/archive/2023/06/18/15"></property>
</bean>

測驗類:
@Test
public void testDog1(){
    ApplicationContext ac=new ClassPathXmlApplicationContext("applicationConfig.xml");
    Dog d1 = ac.getBean("d1", Dog.class);
    System.out.println(d1.getAge());
}

結果:
15

  B.byType 按型別自動裝配

組態檔
<bean id="d1"  autowire="byType">
    <property name="age" value="https://www.cnblogs.com/qiang2023/archive/2023/06/18/21"></property>
</bean>


測驗類:
@Test
public void testDog1(){
    ApplicationContext ac=new ClassPathXmlApplicationContext("applicationConfig.xml");
    Dog d1 = ac.getBean(Dog.class);
    System.out.println(d1.getAge());
}


結果:
21

 

2.6.2根據注解開發             spring中的注解注入的有:@Autowired、@Resources @Qualifier   @Service @Commonent @Controller  @Repository     在使用注解開發時,需要現在組態檔中開啟組件掃描功能 <!--開啟組件掃描-->     <context:component-scan base-package="cn.liushao"></context:component-scan>   開啟組件掃描  便可以自動查找其中的自動注入     不同的注解的區分:
  • Autowired是自動注入,自動從spring的背景關系找到合適的bean來注入,
  • Resource用來指定名稱注入,
  • Qualifier和Autowired配合使用,指定bean的名稱,
  • Service,Controller,Repository分別標記類是Service層類,Controller層類,Dao層的類,spring掃描注解配置時,會標記這些類要生成bean,
  • Component是一種泛指,標記類是組件,spring掃描注解配置時,會標記這些類要生成bean,
@Autowired注解     默認按型別裝配springbean 默認情況下,必須要求依賴物件必須存在,如果容器中有多個相同型別的bean,則框架會拋出例外,     @Qualifier     此注解用來消除依賴注入沖突的,我們可以消除需要注入那個bean的問題     通過該注解,我們可以使用特定的Spring Bean一起裝配,Spring框架可以從多個相同型別并滿足裝配要求的bean中找到我們想要的,     @Resource是按名稱裝配:

 

分析:  由于注解@Autowired是默認按型別裝配的,一個型別的可能會有多個實作方法
        因此在演示的時候 就可以選擇一個介面,有多個實作類來作為演示

1.構建一個介面
public interface TeacherService {
    public void sayName();
    public void saysex();
}


2.創建多個實作類(以三個舉例)
@Component
public class TeacherServiceImpl1 implements TeacherService {
    @Override
    public void sayName() {
        System.out.println("A");
    }
}

@Component
public class TeacherServiceImpl1 implements TeacherService {
    @Override
    public void sayName() {
        System.out.println("B");
    }
}

@Component
public class TeacherServiceImpl1 implements TeacherService {
    @Override
    public void sayName() {
        System.out.println("C");
    }
}

3.創建兩外一個類,可以呼叫該類的實作類
public class TeacherController {
    @Autowired
    //創建物件
    private TeacherService teacherService;
    public void soutResult(){
        teacherService.sayName();
    }
}

4.修改組態檔 開啟掃描

<!--    測驗注解開發-->
    <context:component-scan base-package="com.qiang"></context:component-scan>

5.測驗:

@Test
public void testAopAno(){
    ApplicationContext ac=new ClassPathXmlApplicationContext("applicationConfig.xml");
    TeacherController contro = ac.getBean("teacherController", TeacherController.class);
    contro.soutResult();
}
6.觀察結果:
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'teacherController': Unsatisfied dependency expressed through field 'teacherService'; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.qiang.service.TeacherService' available: expected single matching bean but found 3: teacherServiceImpl1,teacherServiceImpl2,teacherServiceImpl3

分析:由于在service介面有多個實作類,使用autowired是按型別注入,可能會找不到使用哪個  因此可以搭配使用@Qualifier注解


修改第三步:
public class TeacherController {
    @Autowired
    @Qualifier("teacherServiceImpl1")
    //創建物件
    private TeacherService teacherService;
    public void soutResult(){
        teacherService.sayName();
    }
}
繼續進行測驗  結果為:
A
結果顯示正常


繼續修改第三步:
public class TeacherController {
   @Resource(name = "teacherServiceImpl1")
    //創建物件
    private TeacherService teacherService;
    public void soutResult(){
        teacherService.sayName();
    }
}
繼續進行測驗  結果為:
A
結果顯示正常

 

通過上述例子可以看出,如果一個類需要由多個實體變數時,可以搭配使用 @Autowired     @Qualifier("teacherServiceImpl1"),也可以單獨使用 @Resource(name = "teacherServiceImpl1"

 

三、AOP       3.1AOP簡介:         AOP通俗理解就是面向切面編程,是對面向物件的一種補充、將那些與業務無關的,但卻對多個物件產生影響的公共行為和邏輯,抽取并封裝為一個可重用的模板,這個模板就被稱為”切面“,使用AOP減少了系統中的重復代碼、降低了模塊間的耦合度,同時提高了系統的可維護性,     AOP的底層是動態代理,分別為JDK動態代理和CGLIB動態代理       3.2術語:         連接點:可以被增強的方法                  切入點: 實際真正被增強的方法,稱為切入點           通知(增強):又被叫做增強,實際增強的邏輯部分稱為通知[增強]           切面(是個動作):把通知應用到切入點的程序,   其中:通知有五種:         前置通知(before) 后置(回傳)通知(after returning) 、環繞通知(Around)、例外通知(after-throwing)   通知通俗理解就是AOP暴漏給我們的方法,我們在這個方法中直接定義需要擴展的代碼即可,但是其執行順序,交給了spring來處理,             3.3 AOP的準備作業: 首先介紹一下Aspect J  這個是一個獨立的AOP模型,但不是Spring框架的內容,     因此在演示的時候需要匯入相關的jar包,或者使用maven檔案         切入點運算式:知道對那個類的方法進行增強         execution( [權限修飾符] [回傳值型別] [類的全路徑] [方法名][引數串列])       3.4 AOP通知         3.4.1基于XML的配置通知     A 第一種方式:
1.添加jar包

2.建造物體類和代理物件類
    普通類應包含一個普通方法,該普通方法也就是要增強的那個方法
public class Student implements Serializable {
    public void add(){
        System.out.println("這個只是一個普通的方法");
    }
}


public class StudentProxy {
    //配置前置通知
    public void before(){
        System.out.println("前置通知,,,,,");
    }
    //配置后置回傳通知
    public void afterreturning(){
        System.out.println("后置回傳通知....");
    }
    //配置最終通知
    public void after(){
        System.out.println("最終通知....");
    }
    //配置環繞通知
    public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("環繞通知前");
        proceedingJoinPoint.proceed();
        System.out.println("環繞通知后....");
    }
    //配置例外通知
    public void afterThrow(){
        System.out.println("例外通知....");
    }
}



3.修改組態檔


在修改組態檔時應注意,頭檔案也需要進行修改

xmlns:aop="http://www.springframework.org/schema/aop"
xsi:http://www.springframework.org/schema/aop
    https://www.springframework.org/schema/aop/spring-aop.xsd"

//注入
<bean id="student" ></bean>
<bean id="studentProxy" ></bean>

<aop:config >
    <!--切入點-->
    <aop:pointcut id="pc" expression="execution(* com.qiang.pojo.Student.add(..))"/>
    <!--配置切面-->
    <aop:aspect ref="studentProxy">
        <!--將增強應用到具體的方法上-->
        <!--前置通知-->
        <aop:before method="before" pointcut-ref="pc"></aop:before>
        <!--后置回傳通知-->
       <aop:after-returning method="afterreturning" pointcut-ref="pc"></aop:after-returning>
        <!--最終通知-->
        <aop:after method="after" pointcut-ref="pc"></aop:after>
        <!--環繞通知-->
        <aop:around method="around" pointcut-ref="pc"></aop:around>
    </aop:aspect>
以上沒有演示例外通知,例外通知在程式發生例外時才會發生,


測驗:
@Test
public void testAopXmlDemo1(){
    ApplicationContext ac=new ClassPathXmlApplicationContext("applicationConfig.xml");
    Student student = ac.getBean("student", Student.class);
    student.add();
}



結果:

前置通知,,,,,
環繞通知前
這個只是一個普通的方法
環繞通知后....
最終通知....
后置回傳通知....
分析:     前置通知:在連接點之前執行的通知     后置回傳通知:一般在方法的結尾,必然會多一個回傳值     環繞通知:包含了前置通知和后置通知     例外通知:處理例外資料,事務回滾      3.4.2基于注解的配置通知     B:第二種方式
1.引入jar包
 
2.創建物體類
@Component
public class User {
    public void add(){
        System.out.println("這是一個普通方法");
    }
}

3.創建代理類
@Component
@Aspect //生成代理物件
public class UserProxy {
    //前置通知
    @Before(value = "https://www.cnblogs.com/qiang2023/archive/2023/06/18/execution(* org.qiang.aop.anno.pojo.User.add(..))")
    public void before(){
        System.out.println("前置通知,,,");
    }
    //后置回傳通知
    @AfterReturning(value = "https://www.cnblogs.com/qiang2023/archive/2023/06/18/execution(* org.qiang.aop.anno.pojo.User.add(..))")
    public void afterReturning(){
        System.out.println("后置回傳通知afterReturning....");
    }
    //環繞通知
    @Around(value = "https://www.cnblogs.com/qiang2023/archive/2023/06/18/execution(* org.qiang.aop.anno.pojo.User.add(..))")
    public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{
        System.out.println("環繞之前....");
        // 被增強的方法執行了
        proceedingJoinPoint.proceed();
        System.out.println("環繞之后....");
    }
//    //例外通知 只有手動創造了例外才可以觸發這個通知
//    @AfterThrowing(value = "https://www.cnblogs.com/qiang2023/archive/2023/06/18/execution(* org.qiang.aop.anno.pojo.User.add(..))")
//    public void afterThrowing(){
//        System.out.println("例外通知 afterThrowing......");
//    }


//最終通知
    @After(value = "https://www.cnblogs.com/qiang2023/archive/2023/06/18/execution(* org.qiang.aop.anno.pojo.User.add(..))")
    public void after(){
        System.out.println("最終通知....");
    }

}

//修改組態檔


<!--    開啟組件掃描-->
    <context:component-scan base-package="org.qiang.aop.anno"></context:component-scan>


<!--    開啟Aspect生成代理物件-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>


//測驗:

@Test
public void testAopAnno(){
    ApplicationContext ac=new ClassPathXmlApplicationContext("applicationConfig2.xml");
    User user = ac.getBean("user", User.class);
    user.add();
}



結果:
環繞之前....
前置通知,,,
這是一個普通方法
環繞之后....
最終通知....
后置回傳通知afterReturning....

    C:第三種方式抽取重復代碼

只需要修改代理類物件就可以了
@Component
@Aspect //生成代理物件
public class UserProxy {




//    抽取切入點
    @Pointcut(value = "https://www.cnblogs.com/qiang2023/archive/2023/06/18/execution(* org.qiang.aop.anno.pojo.User.add(..))")
    public void pointcutDemo(){


    }
    //前置通知
    @Before(value = "https://www.cnblogs.com/qiang2023/archive/2023/06/18/pointcutDemo()")
    public void before(){
        System.out.println("前置通知,,,");
    }
   
   
    //后置回傳通知
    @AfterReturning(value = "https://www.cnblogs.com/qiang2023/archive/2023/06/18/pointcutDemo()")
    public void afterReturning(){
        System.out.println("后置回傳通知afterReturning....");
    }
   
   
    //環繞通知
    @Around(value = "https://www.cnblogs.com/qiang2023/archive/2023/06/18/pointcutDemo()")
    public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{
        System.out.println("環繞之前....");
        // 被增強的方法執行了
        proceedingJoinPoint.proceed();
        System.out.println("環繞之后....");
    }
    
    
//    //例外通知 只有手動創造了例外才可以觸發這個通知
//    @AfterThrowing(value = "https://www.cnblogs.com/qiang2023/archive/2023/06/18/pointcutDemo()")
//    public void afterThrowing(){
//        System.out.println("例外通知 afterThrowing......");
//    }


    
    
    //最終通知
    @After(value = "https://www.cnblogs.com/qiang2023/archive/2023/06/18/pointcutDemo()")
    public void after(){
        System.out.println("最終通知....");
    }
    
}
  D :  AOP 底層是動態代理默認的是JDK動態代理的方法,也可以通過     <aop: aspectj-autoproxy proxy-target-></aop :aspect-autoproxy> 標簽來修改,其默認值是false是JDK動態代理的格式,改為true就可以使用CGLIB代理格式,

 

3.5 Spring的事務管理       Spring框架將固定的冗余部分的套路代碼進行了封裝,對程式員僅提供簡單的XML配置就可以完成事務的管理,不需要在撰寫事務管理代碼,這也就是Spring的非常重要功能--宣告式事務          宣告式事務是基于AOP實作的(動態代理),程式員只需要呼叫持久層代碼和業務邏輯代碼,將開啟事務的代碼反正該了前置通知中,將事務回滾和事務提交的代碼放在了后置通知中,         使用事物可以保證操作前后資料的完整性,事務的四個特性:ACID 原子性、一致性、隔離性和持久性         編程式事務:整個事務的操作都是由程式員進行手動管理,手動提交,手動回滾     宣告式事務:整個事務由其他框架進行管理,我們使用事務的時候只需要進行簡單的宣告或                         者配置即可,         Spring中的Tx模塊就包含了對宣告式事務的封裝,以下是我們的日常的手動提交事務的寫法:
public void testdemo1() throws SQLException {
    Connection conn= DriverManager.getConnection("","","");
    //關閉自動提交
    conn.setAutoCommit(false);
    try {
        PreparedStatement ptst=conn.prepareStatement("insert into bank  values=(?,?)");
        
        ptst.executeUpdate();
        
    }catch (Exception e){
    //再發生例外時,就會進行事務的回滾
        conn.rollback();
    }
    
}
   回顧Aop切面編程,可以發現共通點,在關閉自動提交的部分,可以用前置通知來代替,try代碼塊的部分就可以理解為是切入點,事務提交的部分可以使用后置通知來實作,而對于出現例外,事務回滾的操作就可以使用例外通知來處理, 也就是:
在org.springframework.jdbc.datasource.DataSourceTransactionManager 中的
方法:
protected void doBegin(){
    conn.setAutoCommit(false)
}

protected void doBegin() {

}

protected void doRollback() {


}

 

添加事務通知:

<tx:advice id="tt" transaction-manager="transactionmanager">
    <tx:attributes>
            <tx: method name="方法名">
    </tx:attributes>
</ tx: advice>


<aop:config>
              <aop:pointcut id="pt"  expression="execution(* 類的全路徑.方法(. .))" />
            <aop:advisor advice-ref="tt"  pointcut-ref="pt"> </aop:advisor>
</aop:config>

 

 

宣告式事務的四個基礎屬性介紹:         <tx:method>標簽下有屬性配置,也可以用在注解上:

 

 

 

 

 

 

 

 

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/555491.html

標籤:其他

上一篇:尚醫通day13【預約掛號】(內附原始碼)

下一篇:返回列表

標籤雲
其他(161226) Python(38240) JavaScript(25505) Java(18246) C(15237) 區塊鏈(8271) C#(7972) AI(7469) 爪哇(7425) MySQL(7256) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5875) 数组(5741) R(5409) Linux(5347) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4603) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2436) ASP.NET(2404) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) .NET技术(1984) HtmlCss(1968) 功能(1967) Web開發(1951) C++(1941) python-3.x(1918) 弹簧靴(1913) xml(1889) PostgreSQL(1881) .NETCore(1863) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【C++】Microsoft C++、C 和匯編程式檔案

    ......

    uj5u.com 2020-09-10 00:57:23 more
  • 例外宣告

    相比于斷言適用于排除邏輯上不可能存在的狀態,例外通常是用于邏輯上可能發生的錯誤。 例外宣告 Item 1:當函式不可能拋出例外或不能接受拋出例外時,使用noexcept 理由 如果不打算拋出例外的話,程式就會認為無法處理這種錯誤,并且應當盡早終止,如此可以有效地阻止例外的傳播與擴散。 示例 //不可 ......

    uj5u.com 2020-09-10 00:57:27 more
  • Codeforces 1400E Clear the Multiset(貪心 + 分治)

    鏈接:https://codeforces.com/problemset/problem/1400/E 來源:Codeforces 思路:給你一個陣列,現在你可以進行兩種操作,操作1:將一段沒有 0 的區間進行減一的操作,操作2:將 i 位置上的元素歸零。最終問:將這個陣列的全部元素歸零后操作的最少 ......

    uj5u.com 2020-09-10 00:57:30 more
  • UVA11610 【Reverse Prime】

    本人看到此題沒有翻譯,就附帶了一個自己的翻譯版本 思考 這一題,它的第一個要求是找出所有 $7$ 位反向質數及其質因數的個數。 我們應該需要質數篩篩選1~$10^{7}$的所有數,這里就不慢慢介紹了。但是,重讀題,我們突然發現反向質數都是 $7$ 位,而將它反過來后的數字卻是 $6$ 位數,這就說明 ......

    uj5u.com 2020-09-10 00:57:36 more
  • 統計區間素數數量

    1 #pragma GCC optimize(2) 2 #include <bits/stdc++.h> 3 using namespace std; 4 bool isprime[1000000010]; 5 vector<int> prime; 6 inline int getlist(int ......

    uj5u.com 2020-09-10 00:57:47 more
  • C/C++編程筆記:C++中的 const 變數詳解,教你正確認識const用法

    1、C中的const 1、區域const變數存放在堆疊區中,會分配記憶體(也就是說可以通過地址間接修改變數的值)。測驗代碼如下: 運行結果: 2、全域const變數存放在只讀資料段(不能通過地址修改,會發生寫入錯誤), 默認為外部聯編,可以給其他源檔案使用(需要用extern關鍵字修飾) 運行結果: ......

    uj5u.com 2020-09-10 00:58:04 more
  • 【C++犯錯記錄】VS2019 MFC添加資源不懂如何修改資源宏ID

    1. 首先在資源視圖中,添加資源 2. 點擊新添加的資源,復制自動生成的ID 3. 在解決方案資源管理器中找到Resource.h檔案,編輯,使用整個專案搜索和替換的方式快速替換 宏宣告 4. Ctrl+Shift+F 全域搜索,點擊查找全部,然后逐個替換 5. 為什么使用搜索替換而不使用屬性視窗直 ......

    uj5u.com 2020-09-10 00:59:11 more
  • 【C++犯錯記錄】VS2019 MFC不懂的批量添加資源

    1. 打開資源頭檔案Resource.h,在其中預先定義好宏 ID(不清楚其實ID值應該設定多少,可以先新建一個相同的資源項,再在這個資源的ID值的基礎上遞增即可) 2. 在資源視圖中選中專案資源,按F7編輯資源檔案,按 ID 型別 相對路徑的形式添加 資源。(別忘了先把檔案拷貝到專案中的res檔案 ......

    uj5u.com 2020-09-10 01:00:19 more
  • C/C++編程筆記:關于C++的參考型別,專供新手入門使用

    今天要講的是C++中我最喜歡的一個用法——參考,也叫別名。 參考就是給一個變數名取一個變數名,方便我們間接地使用這個變數。我們可以給一個變數創建N個參考,這N + 1個變數共享了同一塊記憶體區域。(參考型別的變數會占用記憶體空間,占用的記憶體空間的大小和指標型別的大小是相同的。雖然參考是一個物件的別名,但 ......

    uj5u.com 2020-09-10 01:00:22 more
  • 【C/C++編程筆記】從頭開始學習C ++:初學者完整指南

    眾所周知,C ++的學習曲線陡峭,但是花時間學習這種語言將為您的職業帶來奇跡,并使您與其他開發人員區分開。您會更輕松地學習新語言,形成真正的解決問題的技能,并在編程的基礎上打下堅實的基礎。 C ++將幫助您養成良好的編程習慣(即清晰一致的編碼風格,在撰寫代碼時注釋代碼,并限制類內部的可見性),并且由 ......

    uj5u.com 2020-09-10 01:00:41 more
最新发布
  • 【Java學習】 Spring的基礎理解 IOC、AOP以及事務

    一、簡介 官網: https://spring.io/projects/spring-framework#overview 官方下載工具: https://repo.spring.io/release/org/springframework/spring/ github下載: https://git ......

    uj5u.com 2023-06-19 07:37:09 more
  • 尚醫通day13【預約掛號】(內附原始碼)

    # 頁面預覽 ## 預約掛號 - 根據預約周期,展示可預約日期,根據有號、無號、約滿等狀態展示不同顏色,以示區分 - 可預約最后一個日期為即將放號日期 - 選擇一個日期展示當天可預約串列 ![image-20230227202834422](https://s2.loli.net/2023/06/1 ......

    uj5u.com 2023-06-19 07:36:36 more
  • 并行計算——緒論

    # 一、緒論 ## 1.1 基本概念 1. 加速比:表示加速效果。單個處理器運行花費時間 / P個處理器運行花費時間;$S=\frac{T(1)}{T(p)}$ 2. 效率:$E = \frac{S}{p} = \frac{T(1)}{T(p)\times p}$ 3. 開銷:$C=T(p)\tim ......

    uj5u.com 2023-06-19 07:31:09 more
  • 集合體系結構

    集合體系結構 List系列集合:添加的元素有序,可重復,有索引 Collection:是單列集合的祖宗介面,它的功能是全部單列集合都可以繼承使用的 set系列集合:添加的元素無序,不重復,無索引 方法名說明 public boolean add(E e) 把給定的物件添加到當前集合中 public ......

    uj5u.com 2023-06-18 08:13:56 more
  • 集合體系結構

    集合體系結構 List系列集合:添加的元素有序,可重復,有索引 Collection:是單列集合的祖宗介面,它的功能是全部單列集合都可以繼承使用的 set系列集合:添加的元素無序,不重復,無索引 方法名說明 public boolean add(E e) 把給定的物件添加到當前集合中 public ......

    uj5u.com 2023-06-18 08:12:55 more
  • rust 使用第三方庫構建mini命令列工具

    這是上一篇 [rust 學習 - 構建 mini 命令列工具](https://www.cnblogs.com/dreamHot/p/17467837.html)的續作,擴展增加一些 crate 庫。這些基礎庫在以后的編程作業中會常用到,他們作為基架存在于專案中,解決專案中的某個問題。 專案示例還是 ......

    uj5u.com 2023-06-18 07:49:48 more
  • [ARM 匯編]進階篇—例外處理與中斷—2.4.2 ARM處理器的例外向量

    #### 例外向量表簡介 在ARM架構中,例外向量表是一組固定位置的記憶體地址,它們包含了處理器在遇到例外時需要跳轉到的處理程式的入口地址。每個例外型別都有一個對應的向量地址。當例外發生時,處理器會自動跳轉到對應的向量地址,并開始執行例外處理程式。 #### 例外向量表的位置 ARM處理器的例外向量表 ......

    uj5u.com 2023-06-18 07:49:41 more
  • 基于回歸分析的波士頓房價分析

    #基于回歸分析的波士頓房價分析 專案實作步驟: 1.專案結構 2.處理資料 3.處理繪圖 4.對資料進行分析 5.結果展示 一.專案結構 ![image](https://img2023.cnblogs.com/blog/3047082/202306/3047082-2023061722315431 ......

    uj5u.com 2023-06-18 07:49:28 more
  • 通過模仿學會Python爬蟲(一):零基礎上手

    好家伙,爬蟲來了 爬蟲,這玩意,不會怎么辦, 誒,先抄一份作業回來 1.別人的爬蟲 Python爬蟲史上超詳細講解(零基礎入門,老年人都看的懂)_ChenBinBini的博客-CSDN博客 # -*- codeing = utf-8 -*- from bs4 import BeautifulSoup ......

    uj5u.com 2023-06-18 07:49:10 more
  • 09. centos使用docker方式安裝mysql

    ## 一、創建宿主機物理路徑 新建/mydata/mysql/data、log和conf三個檔案夾 ```bash mkdir -p /mnt/mysql/log mkdir -p /mnt/mysql/data mkdir -p /mnt/mysql/config ``` 或者 ```bash m ......

    uj5u.com 2023-06-18 07:49:00 more