简介:通过环绕增强类缓存目标对象执行结果,所表达的意思是:通过代理类代理执行目标对象的方法时,将执行结果存储到定义的缓存中(这里用HashMap来定义缓存对象),当再次执行相同的方法时(即方法名、方法参数、和目标对象都相同),不会再从目标对象(被代理对象)中过行代码,而是直接从缓存中(HashMap)取出,这样,加快了代码整体的运行速度。以缓存计算结果为例,具体实现代码示例如下:
一、定义接口及实现接口
(一) 定义接口,这里定义的接口用于最基本的计算
public interface CalcService {
int addNumber(int a,int b);
int minNumber(int a,int b);
}
(二) 实现接口
public class CalcServiceImpl implements CalcService {
@Override
public int addNumber(int a, int b) {
System.out.println("开始执行加法计算:");
return a + b;
}
@Override
public int minNumber(int a, int b) {
System.out.println("开始执行减法计算:");
return a-b;
}
}
二、定义用于缓存的环绕增强类(重点)
public class BeforeAndAfterAdvice implements MethodInterceptor {
// TODO: 2021/6/28 这个地方定义了一个缓存
Map<CalcServiceKey, Object> map = new HashMap<>();
@Override
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
Method method = methodInvocation.getMethod();
Object[] arguments = methodInvocation.getArguments();
Object aThis = methodInvocation.getThis();
CalcServiceKey calcServiceKey = new CalcServiceKey();
calcServiceKey.setMethod(method);
calcServiceKey.setTarget(aThis);
calcServiceKey.setArgs(arguments);
// TODO: 2021/6/28 如果存在全部一样的Key,则直接返回对象,从而跳远了目标对象方法的很执行!
if (map.containsKey(calcServiceKey)) {
System.out.println("直接从Map集合中读取!!");
return map.get(calcServiceKey);
}
System.out.println("将继续执行目标对象中的方法!");
// TODO: 2021/6/28 执行目标对象代码
Object proceed = methodInvocation.proceed();
// TODO: 2021/6/28 如果在Map集合中没有存在的key,则将key和值都放进去
map.put(calcServiceKey, proceed);
return proceed;
}
}
三、定义用于存放方法结构信息、参数信息和目标对象信息的对象(重点)
HashMap可以自动判断存放到HashMap集合的数据键值(Key)是否相同,而做为通过字节码操作工作类生成的代理类字节码,要判断调用的方法、参数和目标对象是否相同,就必须 自定义一个类,用于存放这三者的信息。同时必须重写hashcode()和euqeals()方法,当存放到HashMap集合中时,用于比较是否存在相同的键值。这个用于存放方法结构信息,参数信息和目标对象的自定义类示例代码如下:
public class CalcServiceKey {
private Method method;
private Object[] args;
private Object target;
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;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
CalcServiceKey that = (CalcServiceKey) o;
return Objects.equals(method, that.method) &&
Arrays.equals(args, that.args) &&
Objects.equals(target, that.target);
}
@Override
public int hashCode() {
int result = Objects.hash(method, target);
result = 31 * result + Arrays.hashCode(args);
return result;
}
}
四、配置xml核心配置文件,在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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- TODO:1.生成目标对象实例 -->
<bean id="calcserviceimpl" class="aop1.impl.CalcServiceImpl"/>
<!-- TODO:2.生成环绕增强类实例 -->
<bean id="calcserviceadvice" class="aop1.advice.BeforeAndAfterAdvice"/>
<!-- TODO:明定增强类实例映射到的切入点 -->
<bean id="calcserviceadvisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
<property name="advice" ref="calcserviceadvice"/>
<property name="mappedNames">
<list>
<value>*</value>
</list>
</property>
</bean>
<!-- TODO:生成代理对象实例 -->
<bean id="calcserviceproxybean" class="org.springframework.aop.framework.ProxyFactoryBean" lazy-init="false">
<property name="target" ref="calcserviceimpl"/>
<property name="interfaces">
<list>
<value>aop1.CalcService</value>
</list>
</property>
<property name="interceptorNames">
<list>
<value>calcserviceadvisor</value>
</list>
</property>
</bean>
</beans>
五、测试运行
@Test
public void test25() {
ApplicationContext ac = new ClassPathXmlApplicationContext("aop1/aop1.xml");
CalcService calcserviceproxybean = (CalcService) ac.getBean("calcserviceproxybean");
System.out.println(calcserviceproxybean.addNumber(20, 30));
System.out.println(calcserviceproxybean.addNumber(20, 30));
}