持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第1天,点击查看活动详情
Spring AOP前奏
代理模式
-
代理模式:比如房屋中介、房屋App等都是代理。
-
我们(目标对象)与中介(代理对象)不能相互转换,因为是平级关系。
为什么需要代理?
-
需求:实现【加减乘除】计算器类
- 在加减乘除方法中,添加日志功能【在计算之前,记录日志。在计算之后,显示结果。】
-
实现后发现问题如下
- 日志代码比较分散,可以将代码提取到日志类中。
- 日志代码比较混乱,非核心代码与核心业务代码书写一处。
-
总结:我们不期望在核心业务代码中书写日志代码。
-
此时:使用代理模式解决问题:
【先将日志代码横向提取到日志类中,再动态织入回到业务代码中】
-
手动实现动态代理步骤
注意:代理对象与实现类【目标对象】是“兄弟”关系,不能相互转换
-
实现方式
- 基于接口实现动态代理: JDK动态代理
- 基于继承实现动态代理: Cglib、Javassist动态代理
-
基于接口实现动态代理的具体步骤:
-
创建类(比如
MyProxy)【为了创建代理对象的工具类】 -
提供属性【目标对象,也就是实现类】
-
提供方法(比如
getProxyObject())【创建代理对象】实现动态代理关键步骤
-
一个类:Proxy
- 概述:Proxy代理类的基类【类似Object】
- 作用:newProxyInstance():创建代理对象
-
一个接口:InvocationHandler
- 概述:实现【动态织入效果】关键接口
- 作用:invoke(),执行invoke()实现动态织入效果
-
-
提供有参构造器【避免目标对象为空】
-
package com.atguigu.beforeaop;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* MyProxy为获取代理对象的工具类。
*/
public class MyProxy {
/**
* 目标对象【目标客户】
*/
private Object target;
public MyProxy(Object target){
this.target = target;
}
/**
* 获取目标对象的,代理对象
* @return
*/
public Object getProxyObject(){
Object proxyObj = null;
/**
第一个参数:类加载器【ClassLoader loader】,目标对象的类加载器
第二个参数:目标对象实现接口:Class<?>[] interfaces,目标对象实现所有接口
第三个参数:InvocationHandler (动态织入的关键方法)
*/
//创建类加载器
ClassLoader classLoader = target.getClass().getClassLoader();
//代理对象要知道目标对象实现了什么样的接口
Class<?>[] interfaces = target.getClass().getInterfaces();
//创建代理对象
proxyObj = Proxy.newProxyInstance(classLoader, interfaces, new InvocationHandler() {
//执行invoke()实现动态织入效果
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//获取方法名【目标对象】
String methodName = method.getName();
//执行目标方法之前,添加日志
MyLogging.beforeMethod(methodName,args);
//获取目标对象的目标方法。
Object rs = method.invoke(target, args);
//执行目标方法之后,添加日志
MyLogging.afterMethod(methodName,rs);
return rs;
}
});
return proxyObj;
}
//不推荐以下方法:使用匿名内部类
// class invocationImpl implements InvocationHandler{
// }
}
@Test
public void testBeforeAop(){
// int add = calc.add(1, 2);
// System.out.println("add = " + add);
//目标对象
Calc calc = new CalcImpl();
//代理工具类
MyProxy myProxy = new MyProxy(calc);
//获取代理对象,与目标对象CalcImpl不能相互转换,两者是兄弟关系。
Calc calcProxy = (Calc)myProxy.getProxyObject();
//使用代理对象执行方法
// int add = calcProxy.add(1, 2);
int div = calcProxy.div(2, 1);
}
\