spring

spring介紹
是一個輕量級的控制反轉(zhuǎn)(IOC),面向切面編程(AOP)的框架(容器),AOP的主要作用就是支持事務(wù)的處理

  • springboot 是一個快速開發(fā)的腳手架
    -- 基于springboot可以快速開發(fā)單個微服務(wù)
    -- 約定大于配置

  • springcloud
    -- springcloud是基于springboot實現(xiàn)的

現(xiàn)在多數(shù)公司在使用springboot進(jìn)行快速開發(fā)躯砰,學(xué)習(xí)springboot需要先學(xué)習(xí)spring和springMVC

spring理念:整合現(xiàn)有技術(shù)蹋偏,是個大雜燴褥蚯。弊端就是配置十分繁瑣

2. IOC:控制反轉(zhuǎn)

什么叫控制反轉(zhuǎn)酗捌,本來程序的主動權(quán)在程序員手里,客戶需要什么料仗,程序員調(diào)用什么湾盗。控制反轉(zhuǎn)就是把控制權(quán)轉(zhuǎn)交到客戶手里立轧,客戶需要什么就自己選擇格粪,不需要程序員調(diào)用


2.1 XML

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:util="http://www.springframework.org/schema/util"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">


2.11 spring 對bean管理

  • 創(chuàng)建bean的三種方式

    • 創(chuàng)建方式一:
      • 使用默認(rèn)構(gòu)造函數(shù)
        spring的配置文件使用bean標(biāo)簽且只有id和class屬性躏吊,沒有其他屬性和標(biāo)簽,
      • 如果沒有默認(rèn)構(gòu)造函數(shù)帐萎,就不能創(chuàng)建
  •  <bean id="accountService" class="service.impl.AccountServiceImpl"/>
    
    • 創(chuàng)建方法二:
      • 使用jar包中的方法創(chuàng)建對象(某個類中的方法創(chuàng)建對象)比伏,并存入spring容器
  • <bean id="instanceFactory" class="com.gx.InstanceFactory"/>
    <bean id="accountService" factory-bean="instancefactory" factory-method="saveAccount"/>
    
    • 創(chuàng)建方法三:
      • 使用工廠中的靜態(tài)方法創(chuàng)建對象(某個類中的靜態(tài)方法),并存入spring容器
        static不需要實例化沒疆导,所以可以直接合并成一句話
  •  <bean id="staticFactory" class="com.gx.staticFactory" factory-method="saveAccount"></bean>
    

  • 2.12 bean對象的作用范圍

    • bean的scope屬性: 用于指定bean的作用范圍
      • 取值:singleton:單例的(默認(rèn)值)
        • prototype:多例的
        • request:作用web請求的請求范圍
        • session:作用于web應(yīng)用的會話范圍
        • blobal-session;作用于全局會話(集群)范圍赁项,不是集群范圍就是session
  •    <bean id="accountService" class="service.impl.AccountServiceImpl" scope="prototype"/>
    

  • 2.13 bean對象的生命周期

    • 單例對象:單例對象的生命周期跟隨容器
      • 出生:但容器創(chuàng)建時,對象就出生
      • 存活:容器活著對象就活著
      • 死亡:容器銷毀澈段,對象死亡
    • 多例對象:
      • 出生:當(dāng)我們使用對象時spring框架為我們創(chuàng)建
      • 存活:單對象在使用中就存活
      • 死亡:單對象長時間不用悠菜,且沒有別的對象應(yīng)用,就被被垃圾回收
  •    <bean id="accountService" class="service.impl.AccountServiceImpl" scope="prototype" init-method="init" destroy-method="destroy"/>
    

  • 2.14 spring依賴注入

    • 依賴注入DI:Dependency Injection:降低程序的耦合
      • 能注入的數(shù)據(jù)由三種:
        • 基本類型和string
        • 其他bean類型(在配置文件中活著注解配置的bean)
        • 復(fù)雜類型败富、集合類型
      • 注入的方式三種:
        • 構(gòu)造函數(shù)提供
        • 使用set方法
        • 使用注解
  • 構(gòu)造函數(shù)注入
    • construct-arg :因為默認(rèn)構(gòu)造已經(jīng)不見了悔醋,所以要使用標(biāo)簽:construct-arg
      • 標(biāo)簽中的屬性:
        • type:指定要注入的數(shù)據(jù)類型
        • index:索引位置,指定要注入的數(shù)據(jù)兽叮,從0開始
          -(常用)name:給指定名稱賦值
        • value:給基本類型和String類型數(shù)據(jù)
        • ref:給其他類型數(shù)據(jù)芬骄,在spring容器中出現(xiàn)過的
    • 優(yōu)勢:創(chuàng)建bean對象時,必須注入數(shù)據(jù)鹦聪,否趙不能創(chuàng)建
    • 劣勢:改變了bean實例化账阻,當(dāng)我們用不到某些數(shù)據(jù)也必須賦值
      所以除了非用不可之外,一般使用set方法
  •   <bean id="accountService" class="service.impl.AccountServiceImpl">
      <constructor-arg name="name" value="YY"></constructor-arg>
      <constructor-arg name="age" value="18"></constructor-arg>
      <constructor-arg name="birthday" ref="date"></constructor-arg>
      </bean>
      <bean id="date" class="java.util.Date" ></bean> 
    

  • set方法注入
    • 標(biāo)簽: property泽本,出現(xiàn)在bean內(nèi)部
      • 標(biāo)簽中的屬性:
        • name:給指定名稱賦值,這邊的name不是變量名淘太,而是set的名稱
        • value:給基本類型和String類型數(shù)據(jù)
        • ref:給其他類型數(shù)據(jù),在spring容器中出現(xiàn)過的類里沒有默認(rèn)構(gòu)造函數(shù)不能使用
    • 優(yōu)勢规丽;創(chuàng)建對象沒有明確限制琴儿,可以直接使用默認(rèn)構(gòu)造方法
    • 弊端:沒有set方法就不能注入
  •   <bean id="accountService2" class="service.impl.AccountServiceImpl2">
      <property name="name" value="YY"/>
      <property name="age" value="18"/>
      <property name="birthday" ref="date"/>
      </bean>
      <bean id="date" class="java.util.Date" ></bean>        
    

  • 復(fù)雜類型、集合類型的注入
    • 用于給List結(jié)構(gòu)注入的標(biāo)簽:
      • list array set
    • 用于Map結(jié)構(gòu)集合注入的標(biāo)簽:
      • map props
    • 結(jié)構(gòu)相同嘁捷,可以互換,所以只要記兩組就行了
  •   <bean id="accountService3" class="service.impl.AccountServiceImpl3">
           <property name="strings">
               <array>
                   <value>YY</value>
                   <value>YZY</value>
               </array>
           </property>
           <property name="set">
               <set>
                   <value>YY</value>
                   <value>YZY</value>
               </set>
           </property>
           <property name="map">
               <map>
                   <entry key="A" value="B"></entry>
               </map>
           </property>
           <property name="list">
               <array>
                   <value>YY</value>
                   <value>YZY</value>
               </array>
           </property>
           <property name="properties">
               <props>
                   <prop key="A" >a</prop>
                   <prop key="B" >b</prop>
               </props>
           </property>
       </bean>
       <bean id="person" class="entity.Person" autowire="byType">
    
       </bean>
       <bean id="dog" class="entity.Dog"/>
       <bean id="cat" class="entity.Cat"/>
    

2.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:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
</beans>

注解的第一種方式:不用@Component,直接類在xml里手動注入

<!--支持注解模式-->
    <context:annotation-config></context:annotation-config>
    <!--使用@Autowired注解就不用寫property標(biāo)簽屬性了显熏,也可以在bean后面加autowired屬性-->
    <bean id="person" class="entity.Person"></bean>
    <bean id="dog" class="entity.Dog"/>
    <bean id="cat" class="entity.Cat"/>

注解的第二種方式:使用@Component雄嚣,等價于<bean id=""class=""/>

  • @Controller:一般用在表現(xiàn)層
  • @Service:業(yè)務(wù)層
  • @Repository:持久層
<!--指定要掃描的包,包下的注解會生效喘蟆,其實這條寫了缓升,支持注解模式那條就已經(jīng)包含進(jìn)去了-->
    <context:component-scan base-package="entity"></context:component-scan>
    @Autowired
    @Qualifier(value = "accountDao2")
    //這哥們一個頂上面?zhèn)z
    @Resource(name = "accountDao1")
    private Dog dog;

  • 2.21 注入數(shù)據(jù)的注解

        相當(dāng)于配置文件中的<bean>標(biāo)簽下的<property>標(biāo)簽
        使用注解注入時就可以不用set方法了
    
    • @Autowired:
      自動按照類型注入只要容器中有唯一的bean對象類型和注入的類型匹配,就可以注入成功

      • 注意點 用于匹配指定類型蕴轨,但是我擁有兩個相同的類所以就會無法匹配到確定的一個類上港谊,這時候就匹配與變量名相同的bean,如果都不對就報錯橙弱,這時候
        加上@Qualifier指定變量名
    • @Qualifier
      在按照類注入的基礎(chǔ)上按變量名注入歧寺,在給類成員注入時不能單獨使用燥狰,但是方法注入時可以
      屬性:value
      指定bean的id值

    • @Resource :上面兩個的集合體

      • 屬性 :name
        指定bean的id值
  • 以上三個注入都只能注入其他bean類型的數(shù)據(jù),基本類型無法使用斜筐,集合類型的只能在xml文件實現(xiàn)

    • @Value:用于注入基本類型和string
      • 屬性:value
        用于指定數(shù)據(jù)的值
      •        @Value(value="lanmao") 相當(dāng)于<property id="cat" value="lanmao">
                   private Cat cat;
        

2.22 注解作用范圍

相當(dāng)于配置文件中的<bean>標(biāo)簽中的scope屬性

  • @Scope :指定bean的作用范圍
    • 屬性:value 指定范圍的取值 這個和配置文件中一樣
  •                   @Scope(value = "prototype")
    

2.23 注解生命周期(了解)

  • 相當(dāng)于配置文件中的<bean>標(biāo)簽中的init-method和destroy-method屬性

  • @PostConstruct:創(chuàng)建方法

    •        @PostConstruct: 創(chuàng)建方法
             public void init(){
             System.out.println("對象出生");}  
      
  • @PreDestroy :銷毀方法

    •       public void destroy(){
            System.out.println("對象死亡");
            }
      

小結(jié) xml和注解

  • xml: 更萬能龙致,維護簡單
  • 注解:不是自己的類用不了,維護復(fù)雜

最佳實踐

  • xml用來管理bean
  • 注解負(fù)責(zé)屬性注入

3. 代理模式

為什么要學(xué)習(xí)代理模式顷链,因為這是SpringAOP的底層

是二十三種設(shè)計模式之一目代,springAOC和springMVC必考

  • 代理模式的分類

    • 靜態(tài)代理
    • 動態(tài)代理

3.1 靜態(tài)代理

角色分析

  • 抽象角色:一般使用接口或者抽象類來解決
  • 真實角色:被代理的角色
  • 代理角色:代理真實角色,并做一些附屬操作
  • 客戶:訪問代理角色的人

步驟:

  1. 接口(租房操作)
//租房接口
public interface Rent {
    
    public void rent();
    
}
  1. 真實角色(房東)
//房東要租出去的房子
public class House implements Rent {
    String housName;

    public String getHousName() {
        return housName;
    }

    public House(String housName){
       this.housName = housName;
    }

    public void rent(){
        System.out.println("房東要出租房子"+housName);
    }
}
  1. 代理角色(中介)
//代理
public class Proxy implements Rent{

    private House house;

    public Proxy(){

    }
    //代理去幫你租這個房子
    public Proxy(House house){
        this.house = house;
    }
//    房子被代理租出去了
    @Override
    public void rent(){
        house.rent();
        seeHouse(house.getHousName());
        money(house.housName);
        fire(house.getHousName());
    }
    public void seeHouse(String housName){
        System.out.println("中介帶你看房"+ housName);
    }
    public void money(String housName){
        System.out.println("中介收費"+ housName);
    }
    public void fire(String housName){
        System.out.println("簽合同"+ housName);
    }


}
  1. 客戶端訪問代理角色(租客)
public class Client {
    public static void main(String[] args) {
//        看中了某個房子
        House house = new House("無名公寓");
//        找中介
        Proxy proxy = new Proxy(house);
//        中介的附屬操作嗤练,不用和房東接觸
        proxy.rent();

    }

}

靜態(tài)代理好處:

  • 使真實角色(租客榛了,房東)更加操作純粹,不用關(guān)注公共業(yè)務(wù)(看房煞抬,簽合同)
  • 公共業(yè)務(wù)交給了代理(中介)霜大,實現(xiàn)了業(yè)務(wù)的分工(簽合同,看房)
  • 公共業(yè)務(wù)發(fā)生拓展的時候此疹,方便管理

缺點

  • 一個真實角色就要一個代理僧诚,代碼量翻倍,開發(fā)效率低

3.2 靜態(tài)代理加深理解

有一個service類用于使用增刪改查的操作

public class UserServiceImpl implements UserService{

    //        如果我還想再方法里加語句就很麻煩蝗碎,不方便去改源代碼湖笨,那么這個時候就要用代理類

    @Override
    public void add() {
        System.out.println("增");
    }

    @Override
    public void delete() {
        System.out.println("刪");
    }

    @Override
    public void update() {
        System.out.println("改");
    }

    @Override
    public void query() {
        System.out.println("查");
    }
}

現(xiàn)在我想加一個日志功能,能不能在service類里直接修改呢?

最好不要蹦骑,因為直接修改源代碼可能會出錯慈省,而且如果代碼量多的話十分麻煩,那么我們可以通過一個代理類來增加功能眠菇。

public class UserServiceProxy implements UserService {
    private UserService userService;
//    在代理類里調(diào)用并加上日志
public void setUserService(UserService userService) {
    this.userService = userService;
}
    public void log(String callname){
        System.out.println("調(diào)用了一次"+callname+"方法");
    }
    @Override
    public void add() {
        userService.add();
        log("add");
    }
    @Override
    public void delete() {
        userService.delete();
        log("delete");
    }
    @Override
    public void update() {
        userService.update();
        log("update");
    }
    @Override
    public void query() {
        userService.query();
        log("query");
    }
}

這就是只拓展不修改边败,不在改變原有代碼的基礎(chǔ)上增加新功能

沒有加一層封裝解決不了的方法,如果有捎废,就再加一層笑窜。

橫切.png

不改變業(yè)務(wù)的情況下,我們要增加功能登疗,日志就要橫切進(jìn)去排截,這就是橫向開發(fā),這就是切面辐益!

3.3 動態(tài)代理

  • 動態(tài)代理和靜態(tài)代理角色是一樣的
  • 動態(tài)代理是動態(tài)生成的断傲,不是我們直接寫好的
  • 分為兩大類
    • 基于接口理:基于JDK動態(tài)代理(我們學(xué)習(xí)的)
    • 基于類:cglik

需要了解兩個類:

  • Proxy:代理
    • 提供靜態(tài)方法方法能創(chuàng)建動態(tài)代理和實例
  • invocationHandler:調(diào)用處理程序
    • 每一個代理類都會有一個調(diào)用處理程序,當(dāng)代理類調(diào)用該方法智政,代理類分配到invoke方法通過反射反射

3.3.1 如果是單獨創(chuàng)建一個動態(tài)代理類然后main方法調(diào)用

 import java.lang.reflect.Method;//用這個類自動生成代理類
 public class ProxyInvocationhandler implements InvocationHandler {
     //    被代理的接口
     private Object target;
 
     public void setRent(Object target) {
         this.target = target;
     }
     /*newProxyInstance方法的參數(shù):
         classLoader:類加載器
             用于加載代理對象字節(jié)碼认罩。和被代理對象使用 相同的字節(jié)碼,固定寫法
     class[]:字節(jié)碼數(shù)組
             用于讓代理對象和被代理對象有相同的方法续捂。固定寫法
     InovocationHandler:用于提供增強的代碼
             讓我們寫如何代理垦垂。通常情況下都是匿名內(nèi)部類宦搬,但不是必須 */
     //得到代理類
     public Object getProxy() {
         return Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
     }
 
 //    處理實例并返回結(jié)果
     @Override
     public Object invoke(Object proxy,Method method,Object[] args){
//                      增強功能
                        log("YY");
//                          返回target類的方法和方法的參數(shù)
        return method.invoke(target,args);
}
     public void log(String callname){
         System.out.println("調(diào)用了一次"+callname+"方法");
     }
 }

3.32 如果是直接寫在main方法里

public class Client {
public static void main(String[] args){
  final House house = new House();
        /*newProxyInstance方法的參數(shù):
                 classLoader:類加載器
                     用于加載代理對象字節(jié)碼。和被代理對象使用 相同的字節(jié)碼乔外,固定寫法
             class[]:字節(jié)碼數(shù)組
                     用于讓代理對象和被代理對象有相同的方法床三。固定寫法
             InovocationHandler:用于提供增強的代碼
                     讓我們寫如何代理。通常情況下都是匿名內(nèi)部類杨幼,但不是必須 */
//                          前兩個都是寫被代理類的類加載器
    Rent12 rent12Proxy = (Rent12)Proxy.newProxyInstance(house.getClass().getClassLoader(),house.getClass().getInterfaces,
                      new InvocationHandler() {
                    @Override
                   /* proxy:當(dāng)前代理對象的引用
                      method:當(dāng)前執(zhí)行的方法
                      args:執(zhí)行方法需要的參數(shù)
                    **/
//          這里就相當(dāng)于代理類得到了真實角色的方法撇簿,可以再里面加功能,最后在main方法里調(diào)用你想要的代理類.方法
                public Object invoke(Object proxy,Method method,Object[] args) throws Throwable{
                            if("rent".equals(method.getName())){
                                System.out.println("房子被代理了");
                            }
                    return method(house,args);
                }
});
            rent12Proxy.rent();
}
}

注意點:代理類的類型為接口類型而不是被代理類的類型

通俗的講:代理類就是集成被代理類的接口差购,然后再把被代理類的具體方法方法拿過來用進(jìn)行可以拓展四瘫,
然后集合成一個調(diào)用處理程序,想用就直接調(diào)用這個程序就行了欲逃。


3.33 如果是直接寫在main方法里

上一個方法是接口代理找蜜,那么這個方法就是子類代理,需要用到一個第三方j(luò)ar包cglib

package 動態(tài)代理子類;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import 動態(tài)代理黑馬.Rent12;
import 增加日志功能.UserService;
import 增加日志功能.UserServiceImpl;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * @author YZY
 * @date 2020/3/31 - 20:33
 */
public class Client {
    public static void main(final String[] args) {
        final House1 house1 = new House1();
        house1.setHouseName("無名公寓");
/*動態(tài)代理子類需要第三方的jar包cglib
*   使用Enhancer的create方法
        create方法的參數(shù):
        class:字節(jié)碼
            用于指定被代理類的字節(jié)碼稳析,固定寫法

    callback:用于提供增強的代碼
            讓我們寫如何代理洗做。通常情況下都是匿名內(nèi)部類,但不是必須
            一般寫的是該接口的子接口實現(xiàn)類:MethodInterceptor*/
//       相比于代理接口彰居,代理子類少了一個參數(shù)诚纸,getInterfaces(),因為直接代理子類陈惰,就不需要子類的接口了
//        這里就直接選擇子類類型就行了
      House1 house1Proxy = (House1) Enhancer.create(house1.getClass(), new MethodInterceptor() {
            /*前三個參數(shù)和代理接口的參數(shù)一樣
            * methodProxy:當(dāng)前執(zhí)行方法的代理對象
            * 其他內(nèi)容就和代理接口一模一樣*/
            @Override
            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                if ("rent".equals(method.getName())) {
                    System.out.println("動態(tài)代理接口");
                }
                return method.invoke(house1, args);
            }
      });
        house1Proxy.rent();
    }
}

3.33 動態(tài)代理相比于靜態(tài)代理的優(yōu)勢:

靜態(tài)代理代理的是一個業(yè)務(wù)畦徘,而動態(tài)代理繼承的是接口,可以代理一類業(yè)務(wù)抬闯,范圍范圍更廣井辆,應(yīng)用更加靈活


4 AOP

使用AOP需要導(dǎo)包

<dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.4</version>
        </dependency>

4.1 第一種方式:使用spring的API接口

配置復(fù)雜但是功能強大

先創(chuàng)建繼承接口的類

public class methodBeforeLog implements MethodBeforeAdvice {
    @Override
    /*method:方法
    args:參數(shù)
    target:目標(biāo)對象*/
    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println(target.getClass().getName()+"的"+method.getName()+"被執(zhí)行了");
    }
}
package log;
import org.springframework.aop.AfterReturningAdvice;
import java.lang.reflect.Method;
public class afterReturnLog implements AfterReturningAdvice {
    @Override
//    returnValue:返回值
    public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
        System.out.println("執(zhí)行了"+target.getClass().getName()+"返回的結(jié)果是"+returnValue);
    }
}

配置文件:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--配置bean-->
<bean id="userService" class="service.userService1Impl"></bean>
    <bean id="beforeLog" class="log.methodBeforeLog"></bean>
    <bean id="afterLog" class="log.afterReturnLog"></bean>

    <!--1.使用原生spring API注入-->
<!--配置AOP:需要導(dǎo)入AOP 的約束-->
    <aop:config>
    <!--需要一個切入點:即去哪個地方執(zhí)行(去userServiceImpl下的所有方法*,的所有位置(..))-->
        <aop:pointcut id="pointcut" expression="execution(* service.userService1Impl.*(..))"/>

        <!--執(zhí)行環(huán)繞-->
<!--        把beforelog這個類連接到切入點-->
        <aop:advisor advice-ref="beforeLog" pointcut-ref="pointcut"/>
        <aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/>
</aop:config>

</beans>

4.2 第二種方式:自定義java類實現(xiàn)AOP

配置簡單但是功能少

先創(chuàng)建一個自定義類

package diy;
public class diyPointcut {

    public void MethodBeforeAdvice(){
        System.out.println("方法執(zhí)行前");
    }
    public void AfterReturningAdvice(){
        System.out.println("方法返回后");
    }
}

然后寫入配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--    2.自定義類-->
    <!--配置bean-->
    <bean id="userService" class="service.userService1Impl"></bean>
    <bean id="log" class="log.diyPointcut"></bean>
<!--        aop編寫范圍-->
        <aop:config>
            <!--    切點可以在切面里面也可以在切面外面溶握,在外面的話一定要在切面的前面(aop約束規(guī)定)-->
            <aop:pointcut id="pointcut" expression="execution(* service.userService1Impl.*(..))"/>
<!--            自定義切面杯缺,切面是個類,ref引用你要的類-->
            <aop:aspect ref="log">
<!--            通知-->
                <!--這里就可以自定義在什么時候切入睡榆,
                    aop:brfore代表執(zhí)行前-->
                <aop:before method="MethodBeforeAdvice" pointcut-ref="pointcut"/>
                <aop:after-returning method="AfterReturningAdvice" pointcut-ref="pointcut"/>
            </aop:aspect>
        </aop:config>
</beans>

4.3 第三種方式:注解

xml文件中添加bean和AOP注解的語句夺谁,否則不會生效

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd">
    <bean id="annotation" class="log.AnnotationPointcut"/>
    <bean id="userService" class="service.userService1Impl"/>
<!--    開啟AOP注解-->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>

在編寫通知注解

package log;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
/**
 * @author YZY
 * @date 2020/4/2 - 17:37
 */
// AOP注解
@Aspect    //標(biāo)志這個類成切面
public class AnnotationPointcut {

//    前置通知
    @Before("execution(* service.userService1Impl.*(..))")
    public void MethodBeforeAdvice(){
        System.out.println("Before");
    }

       /*環(huán)繞通知,功能最強大肉微,可以自定義操作
        它可以算是spring框架給我們提供一種手動控制通知(增強)方法的方式,你可以手動在自定義通知(增強)方式
    ProceedingJoinPoint 連接點蜡塌,可以從切入點里獲取信息*/
    @Around("execution(* service.userService1Impl.*(..))")
    public void Around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        try{
        System.out.println("around before");
//        獲取簽名
        Signature signature = proceedingJoinPoint.getSignature();
        System.out.println("signature:"+signature);
//        執(zhí)行
        Object proceed = proceedingJoinPoint.proceed();
        System.out.println("around after");
        }catch (Exception e){
            System.out.println("around throwing");
        }finally {
            System.out.println("around finnal");
        }
    }

//  返回通知碉纳,如果拋出異常不會通知
    @AfterReturning("execution(* service.userService1Impl.*(..))")
    public void AfterReturningAdvice(){
        System.out.println("AfterReturning");
    }
    //  異常通知
    @AfterThrowing("execution(* service.userService1Impl.*(..))")
    public void Throwing(){
        System.out.println("AfterThrowing");
    }
//  最終通知,結(jié)果不關(guān)心是否異常
    @After("execution(* service.userService1Impl.*(..))")
    public void After(){
        System.out.println("After");
    }
}

最后觀察輸出結(jié)果發(fā)現(xiàn)通知順序是有問題的馏艾,而上面提到環(huán)繞通知可以手動控制通知方式劳曹,所以建議使用環(huán)繞通知來處理通知事件

圖片.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末奴愉,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子铁孵,更是在濱河造成了極大的恐慌锭硼,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,185評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蜕劝,死亡現(xiàn)場離奇詭異檀头,居然都是意外死亡,警方通過查閱死者的電腦和手機岖沛,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評論 3 393
  • 文/潘曉璐 我一進(jìn)店門暑始,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人婴削,你說我怎么就攤上這事廊镜。” “怎么了唉俗?”我有些...
    開封第一講書人閱讀 163,524評論 0 353
  • 文/不壞的土叔 我叫張陵嗤朴,是天一觀的道長。 經(jīng)常有香客問我虫溜,道長雹姊,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,339評論 1 293
  • 正文 為了忘掉前任吼渡,我火速辦了婚禮容为,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘寺酪。我一直安慰自己坎背,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,387評論 6 391
  • 文/花漫 我一把揭開白布寄雀。 她就那樣靜靜地躺著得滤,像睡著了一般。 火紅的嫁衣襯著肌膚如雪盒犹。 梳的紋絲不亂的頭發(fā)上懂更,一...
    開封第一講書人閱讀 51,287評論 1 301
  • 那天,我揣著相機與錄音急膀,去河邊找鬼沮协。 笑死,一個胖子當(dāng)著我的面吹牛卓嫂,可吹牛的內(nèi)容都是我干的慷暂。 我是一名探鬼主播,決...
    沈念sama閱讀 40,130評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼晨雳,長吁一口氣:“原來是場噩夢啊……” “哼行瑞!你這毒婦竟也來了奸腺?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,985評論 0 275
  • 序言:老撾萬榮一對情侶失蹤血久,失蹤者是張志新(化名)和其女友劉穎突照,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體氧吐,經(jīng)...
    沈念sama閱讀 45,420評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡讹蘑,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,617評論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了副砍。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片衔肢。...
    茶點故事閱讀 39,779評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖豁翎,靈堂內(nèi)的尸體忽然破棺而出角骤,到底是詐尸還是另有隱情,我是刑警寧澤心剥,帶...
    沈念sama閱讀 35,477評論 5 345
  • 正文 年R本政府宣布邦尊,位于F島的核電站,受9級特大地震影響优烧,放射性物質(zhì)發(fā)生泄漏蝉揍。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,088評論 3 328
  • 文/蒙蒙 一畦娄、第九天 我趴在偏房一處隱蔽的房頂上張望又沾。 院中可真熱鬧,春花似錦熙卡、人聲如沸杖刷。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,716評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽滑燃。三九已至,卻和暖如春颓鲜,著一層夾襖步出監(jiān)牢的瞬間表窘,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,857評論 1 269
  • 我被黑心中介騙來泰國打工甜滨, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留乐严,地道東北人。 一個月前我還...
    沈念sama閱讀 47,876評論 2 370
  • 正文 我出身青樓衣摩,卻偏偏與公主長得像麦备,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,700評論 2 354

推薦閱讀更多精彩內(nèi)容