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());
}
}
測試結果如圖: