目标: 通过加减乘除的这个案例理解AOP
掌握: 未使用AOP时的代码和使用了AOP编程的代码
概念
AOP是面向切面编程。全称:Aspect Oriented Programming
面向切面编程指的是:程序是运行期间,动态地将某段代码插入到原来方法代码的某些位置中。这就叫面向切面编程。
1. 一个简单计算数功能加日记案例理解AOP的工作
package top.starrylsi.caculate;
public interface Caculate {
public int add(int x,int y);
public int sum(int x,int y);
public int mul(int x, int y);
public int div(int x,int y);
}
package top.starrylsi.caculate;
public class Caculator implements Caculate{
@Override
public int add(int x, int y) {
// TODO Auto-generated method stub
return x+y;
}
@Override
public int sum(int x, int y) {
// TODO Auto-generated method stub
return x-y;
}
@Override
public int mul(int x, int y) {
// TODO Auto-generated method stub
return x*y;
}
@Override
public int div(int x, int y) {
// TODO Auto-generated method stub
return x/y;
}
}
1.1 原始方法统一日记处理
- 把日记的内容封装到一个类去中集中处理。
- 缺点:这种方式的不足之处是,每有一个需要加日记的类,都需要到类的代码中去添加日记功能代码。无法做到所有对象都统一处理。
1. 编写一个日记处理工具类
package top.starrylsi.utils;
import java.util.Arrays;
public class LogUtils {
public static void logBefore(String method,Object ...params) {
System.out.println("方法"+method+"参数�:"+Arrays.toString(params));
}
public static void logAfter(String method,Object result) {
System.out.println("方法"+method+"结果:"+result);
}
}
2. 修改原来Calculator中的日记代码
@Override
public int add(int x, int y) {
LogUtils.logBefore("add",x,y);
int result = x +y;
LogUtils.logBefore("add",x,y);
return result;
}
1.2 使用jdk代理实现日记
解释: 通过反射创建了一个新的caculate对象,里面有原本的功能也加了额外的功能((Caculate)Proxy.newProxyInstance(loader, interfaces, new JDKProxyHandler(caculate));)
优点:这种方式已经解决我们前面所有日记需要的问题。非常的灵活。而且可以方便的在后期进行维护和升级。
缺点:当然使用jdk动态代理,需要有接口。如果没有接口。就无法使用jdk动态代理。
思路:完成代理我们是使用了两个类(top.starrylsi.proxy下的 JDKProxyFactory,JDKProxyHandler),JDKProxyFactory用来生成代理对象的.JDKProxyHandler是JDKProxyFactory中的一个参数,是专门用来实现操作逻辑的.
1. 编写 JDKProxyFactory代码
- 关键点1: Proxy.newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h))
- 关键点2: 调用JDKProxyHandler
package top.starrylsi.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import top.starrylsi.caculate.Caculate;
public class JDKProxyFactory {
public static Caculate getProxy(Caculate caculate) {
//1. 获取被代理类的类加载器
ClassLoader loader = caculate.getClass().getClassLoader();
//2. 获取被代理对象的父接口
Class<?> [] interfaces = caculate.getClass().getInterfaces();
//3. 创建代理对象
return (Caculate)Proxy.newProxyInstance(loader, interfaces, new JDKProxyHandler(caculate));
}
}
2. 编写 JDKProxyHandler代码 (top.starrylsi.proxy)
- 关键: 实现InvocationHandler的方法
package top.starrylsi.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import top.starrylsi.caculate.Caculate;
import top.starrylsi.utils.LogUtils;
public class JDKProxyHandler implements InvocationHandler{
private Caculate caculate;
public JDKProxyHandler(Caculate caculate) {
this.caculate = caculate;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//1. 获取方法名
String methdName = method.getName();
//2. 调用日志
LogUtils.logBefore(methdName, args);
//3. 调用方法 并获取返回值
Object result = method.invoke(caculate, args);
//4. 调用日志之后的功能
LogUtils.logAfter(methdName, result);
return null;
}
}
3. 测试
关键点: 知道如何调用
// 调用的关键点
private Caculate caculateProxy = JDKProxyFactory.getProxy(caculate);
package top.starrylsi.test;
import org.junit.jupiter.api.Test;
import top.starrylsi.caculate.Caculate;
import top.starrylsi.caculate.Caculator;
import top.starrylsi.proxy.JDKProxyFactory;
class CaculateTests {
private Caculate caculate = new Caculator();
private Caculate caculateProxy = JDKProxyFactory.getProxy(caculate);
@Test
public void testCaculator() {
int result = caculate.add(5, 10);
System.out.println(result);
}
@Test
public void testProxy() {
caculateProxy.add(2, 4);
}
}
评论 (0)