springAop 環繞通知MethodInterceptor實現對結果進行緩存的計算器

Aop原理

SpringAop 原理就是動態代理

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

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

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

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

SpringAop的配置方式

三種配置方式

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

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

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

Advice類型

SpringAop支持五種類型的通知(增強)
在這裏插入圖片描述
注意:多個Advice之間不允許有耦合,即多個Advice之間不允許有業務交叉。

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

配置方式:

基本用法: 添加jar包

 <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>

1:配置Advice通知

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

package springaop06.advice;

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

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * package_name:springaop06.advice
 *
 * @author:徐亞遠 Date:2020/2/20 13:22
 * 項目名:springDemo01
 * Description:TODO
 * Version: 1.0
 **/

public class CacheAdvice implements MethodInterceptor {
    //定義一個緩存
    Map<Key, Object> cache = new HashMap<>();

    /**
     * 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();
        Key key = new Key();
        key.setMethod(method);
        key.setArgs(args);
        key.setTarget(target);
        //判斷是否執行過這個方法
        if (cache.containsKey(key)) {
            //如果執行過直接返回值
            return cache.get(key);
        }
        System.out.println("methodName:"+method.getName()+" "+"args:"+Arrays.toString(args)+" "+"target"+target);
        Object proceed = invocation.proceed();
        //如果沒有執行過這個方法把它加入到緩存中將結果加入到緩存中
        cache.put(key, proceed);
        return proceed;
    }
}

自定義Key

package springaop06.advice;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Objects;

/**
 * package_name:springaop06.key
 *
 * @author:徐亞遠 Date:2020/2/20 13:42
 * 項目名:springDemo01
 * Description:自定義Key,判斷方法是否被執行過的三要素:method args target
 * Version: 1.0
 **/

public class Key {
    private Method method;
    private Object[] args;
    private Object target;

    //判斷Key的唯一性重寫hashCode()和equals()方法
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Key key = (Key) o;
        return Objects.equals(method, key.method) &&
                Arrays.equals(args, key.args) &&
                Objects.equals(target, key.target);
    }

    @Override
    public int hashCode() {

        int result = Objects.hash(method, target);
        result = 31 * result + Arrays.hashCode(args);
        return result;
    }

    public Method getMethod() {
        return method;
    }

    public void setMethod(Method method) {
        this.method = method;
    }

    public Object[] getArgs() {
        return args;
    }

    public void setArgs(Object[] args) {
        this.args = args;
    }

    public Object getTarget() {
        return target;
    }

    public void setTarget(Object target) {
        this.target = target;
    }
}

對結果計算的接口

package springaop06.service;


/**
 * package_name:springaop06.service
 *
 * @author:徐亞遠 Date:2020/2/20 13:26
 * 項目名:springDemo01
 * Description:TODO
 * Version: 1.0
 **/
public interface CacheService {
    int add(int a,int b);
    double del(int a,int b);
}

對結果進行計算的實現類

package springaop06.service.impl;

import springaop06.service.CacheService;

/**
 * package_name:springaop06.service.impl
 *
 * @author:徐亞遠 Date:2020/2/20 13:27
 * 項目名:springDemo01
 * Description:TODO
 * Version: 1.0
 **/

public class CacheServiceImpl implements CacheService {
    @Override
    public int add(int a, int b) {
        System.out.println("cacheServiceImpl  add();");
        return a+b;
    }

    @Override
    public double del(int a, int b) {
        System.out.println("cacheServiceImpl  del()");
        return a-b;
    }
}

配置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">
    <!--springaop 1.x配置-->
    <!--目標類實例-->
    <bean id="cacheServiceTarget" class="springaop06.service.impl.CacheServiceImpl"/>

    <!--配置通知-->
    <bean id="cacheAdvice" class="springaop06.advice.CacheAdvice"/>

    <!--配置advisor-->
    <bean id="cacheAdvisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
        <!--配置通知-->
        <property name="advice" ref="cacheAdvice"/>
        <!--配置切點-->
        <property name="mappedNames">
            <list>
                <value>add</value>
                <value>del</value>
            </list>
        </property>
    </bean>
    <!--配置代理-->
    <bean id="cacheService" class="org.springframework.aop.framework.ProxyFactoryBean">
        <!--配置目標類實例-->
        <property name="target" ref="cacheServiceTarget"/>
        <!--配置目標實例接口列表-->
        <property name="interfaces">
            <list>
                <value>springaop06.service.CacheService</value>
            </list>
        </property>
        <!--配置交叉業務-->
        <property name="interceptorNames">
            <list>
                <value>cacheAdvisor</value>
            </list>
        </property>
    </bean>
</beans>

書寫測試類

package springaop06.controller;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import springaop06.service.CacheService;

/**
 * package_name:springaop06.controller
 *
 * @author:徐亞遠 Date:2020/2/20 13:23
 * 項目名:springDemo01
 * Description:TODO
 * Version: 1.0
 **/

public class CacheTest {
    public static void main(String [] args){
        ApplicationContext ac = new ClassPathXmlApplicationContext("aop06/spring.xml");
      CacheService cacheService = (CacheService) ac.getBean("cacheService");
        System.out.println(cacheService.add(2,4 ));
        System.out.println(cacheService.add(2,4 ));
        System.out.println(cacheService.add(4,2 ));
        System.out.println(cacheService.add(4,4 ));
        System.out.println("=========================");
        System.out.println(cacheService.del(4,5 ));
        System.out.println(cacheService.del(4,5 ));
        System.out.println(cacheService.del(5,5 ));
        System.out.println(cacheService.del(5,6 ));
      System.out.println(cacheService.getClass());
    }
}

測試結果如圖:
在這裏插入圖片描述

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