springAop環繞通知 MethodInterceptor詳解 實現小案例模擬統計登錄花費時間和解析

Aop原理

SpringAop 原理就是動態代理

對於實現接口的目標類使用的是jdk動態代理

對於沒有實現任何接口的目標類,使用的是cglib的動態代理

代理類是程序在運行期間由JVM根據反射等機制動態生成的自動生成代理類和代理對象。

所謂動態就是指在程序運行前不存在代理類的字節碼文件。

SpringAop的配置方式

三種配置方式

一:SpringAop1.x 使用ProxyFactoryBean手動配置

二:SpringAop2.x 基於命名控件的配置

三:Annotation 基於註解的配置(推薦)

Advice類型

SpringAop支持五種類型的通知(增強)

在這裏插入圖片描述
注意:多個Advice之間不允許有耦合,即多個Advice之間不允許有業務交叉。

(1):SpringAop1.x 使用ProxyFactoryBean 手動代理

配置方式:

基本用法: 添加jar包

<dependencies>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.11</version>
            <scope>test</scope>
        </dependency>
        <!--ioc01-core-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
        </dependency>
        <!--ioc01-bean-->
        <!-- https://mvnrepository.com/artifact/org.springframework/spring-beans -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
        </dependency>
        <!--ioc01-context-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
        </dependency>
        <!--ioc01-expression-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-expression</artifactId>
        </dependency>
        <!--Aop依賴-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
        </dependency>
        <!--cglib技術-->
        <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
        </dependency>
    </dependencies>

1:配置Advice通知

1定義增強類,實現相應的接口

package springaop04.advice;

import org.aopalliance.intercept.Joinpoint;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

import java.lang.reflect.Method;

/**
 * package_name:springaop04.advice
 *
 * @author:徐亞遠 Date:2020/2/19 18:38
 * 項目名:springDemo01
 * Description:環繞通知 統計登錄執行時間
 * Version: 1.0
 **/

public class AroundAdvice implements MethodInterceptor {
    private Long time;

    public Long getTime() {
        return time;
    }

    public void setTime(Long time) {
        this.time = time;
    }

    /**
     * Implement this method to perform extra treatments before and
     * after the invocation. Polite implementations would certainly
     * like to invoke {@link Joinpoint#proceed()}.
     *
     * @param invocation the method invocation joinpoint
     * @return the result of the call to {@link Joinpoint#proceed()};
     * might be intercepted by the interceptor
     * @throws Throwable if the interceptors or the target object
     *                   throws an exception
     */
    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        //方法
        Method method = invocation.getMethod();
        //參數
        Object[] args = invocation.getArguments();
        //目標對象
        Object target = invocation.getThis();

        //執行業務方法前
        System.out.println("環繞通知");
        long startTime = System.currentTimeMillis();
        System.out.println("方法執行前的時間:"+startTime+"ms");
        //執行業務邏輯 返回值表示執行業務方法後返回的結果
        Object procee = invocation.proceed();
        //執行業務方法後
        long endTime = System.currentTimeMillis();
        System.out.println("方法執行後的時間:"+endTime+"ms");
        System.out.println("方法執行花費的時間:"+(endTime-startTime)+"ms");
        if (endTime-startTime > time){
            System.out.println("給管理員發送信息");
        }
        return procee;
    }
}

登錄接口的代碼

package springaop04.service;


/**
 * package_name:springaop01.service
 *
 * author:徐亞遠 Date:2020/2/18 18:29
 * 項目名:springDemo01
 * Description:
 **/
public interface UserService {

    /**
     * @Author : 徐亞遠
     * @Date : 2020/2/18 20:34
     * @param username
     * @param password
     * @Description :
     */
    void login(String username, String password);
}

登錄接口的實現類

package springaop04.service.impl;

import springaop04.service.UserService;

/**
 * package_name:springaop01.service.impl
 * Author:徐亞遠
 * Date:2020/2/18 18:29
 * 項目名:springDemo01
 * Desription:
 **/
public class UserServlceImpl implements UserService {


    /**
     * @param password
     * @param username
     * @Author : 徐亞遠
     * @Date : 2020/2/18 21:03
     * @Description :
     */

    @Override
    public void login(String username, String password) {

        System.out.println("loginUserServiceImpl登錄方法執行:" + username + "    " + password);
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

配置sping.xml

<!--配置環繞通知-->
    <bean id="aroundAdvice" class="springaop04.advice.AroundAdvice">
        <property name="time" value="3000"/>
    </bean>

2:配置目標類實例

<!--配置目標實例-->
    <bean id="userServiceTarget" class="springaop04.service.impl.UserServlceImpl"/>

3:配置Advosior**

定義切入點,配置位置信息,指定那些類的哪些方法需要被執行Aop。

使用NameMathodPointcutAdvisor根據方法名匹配切入點

Advisor是Pointcut和Advice的配置器,Pointcut+Advice=Advisor 織入的過程

<!--配置advisor-->
    <bean id="aroundAdvisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
        <!--配置通知-->
        <property name="advice" ref="aroundAdvice"/>
        <!--配置切點-->
        <property name="mappedNames">
            <list>
                <value>login</value>
            </list>
        </property>
    </bean>

配置代理

使用ProxyFactoryBean配置代理

<!--配置代理-->

    <bean id="userService" class="org.springframework.aop.framework.ProxyFactoryBean">
        <!--配置目標實例-->
        <property name="target" ref="userServiceTarget"/>
        <!--配置目標實例參數-->
        <property name="interfaces">
            <list>
                <value>springaop04.service.UserService</value>
            </list>
        </property>
        <!--交叉業務-->
        <property name="interceptorNames">
            <list>
                <value>aroundAdvisor</value>
            </list>
        </property>
    </bean>

spring.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">

    <!--配置目標實例-->
    <bean id="userServiceTarget" class="springaop04.service.impl.UserServlceImpl"/>
    <!--配置環繞通知-->
    <bean id="aroundAdvice" class="springaop04.advice.AroundAdvice">
        <property name="time" value="3000"/>
    </bean>
    <!--配置advisor-->
    <bean id="aroundAdvisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
        <!--配置通知-->
        <property name="advice" ref="aroundAdvice"/>
        <!--配置切點-->
        <property name="mappedNames">
            <list>
                <value>login</value>
            </list>
        </property>
    </bean>
    <!--配置代理-->

    <bean id="userService" class="org.springframework.aop.framework.ProxyFactoryBean">
        <!--配置目標實例-->
        <property name="target" ref="userServiceTarget"/>
        <!--配置目標實例參數-->
        <property name="interfaces">
            <list>
                <value>springaop04.service.UserService</value>
            </list>
        </property>
        <!--交叉業務-->
        <property name="interceptorNames">
            <list>
                <value>aroundAdvisor</value>
            </list>
        </property>
    </bean>


</beans>

書寫測試類

package springaop04.controller;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import springaop04.service.UserService;

/**
 * package_name:springaop04.controller
 *
 * @author:徐亞遠 Date:2020/2/19 18:54
 * 項目名:springDemo01
 * Description:TODO
 * Version: 1.0
 **/

public class AroundTest {
    public static void main(String [] args){
        ApplicationContext ac = new ClassPathXmlApplicationContext("aop04/spring.xml");
      UserService userService = (UserService) ac.getBean("userService");

      userService.login("root","root" );
        System.out.println(userService.getClass());
    }
}

執行結果如圖:
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章