简单介绍下动态代理的基本用法详细的后面补充
AOP(Aspect Orient Program, 面向切面编程)
面向切面编程,可以将一些系统性相关的编程工作(如日志,验证,事务等),独立实现,然后通过切面切入进系统。
非面向切片变成会导致的问题:
代码混乱: 每个方法在处理核心逻辑时还必须兼顾其他多个关注点.
代码分散: 以日志需求为例, 只是为了满足这个单一需求, 就不得不在多个模块里多次重复相同的日志代码. 如果日志需求发生变化, 必须修改所有模块
面向切面的简图
例如,要编写个计算器,实现加减的功能,在每次调用方法前后都打印出日志,若在方法体里面写的话,需要修改的话要把所有方法的日志都修改,我们可以通过一个代理对象去代理这个计算器,每次想用计算器的方法时,让代理先打印出来日志,再调用被代理对象(计算器)的方法,再打印出日志.通过代理对象动态地调用被代理对象(计算器)的方法,叫做动态代理
•Proxy类 它也是所有动态代理类的父类., java.lang.reflect.Proxy
常用方法
static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces, InvocationHandler h)通过静态方法创建一个代理对象,通常情况下,该代理对象是被代理对象实现的接口的类型,或者其他的接口的类型
参数1,类加载器,要跟被代理对象使用的相同的类加载器,参数2,接口类型的Class的数组,如代理对象只需要实现被代理对象实现的接口, 可以写成 target.getClass().getInterfaces(),其中target是被代理对象,参数3 InvocationHandler是个接口,参数3是该接口的实现,常使用匿名内部类的方式
InvocationHandler接口 java.lang.reflect,只有一个抽象方法
invoke(Object proxy, Method method, Object[] args)执行被代理对象的方法
参数1,Object类型的proxy,指的是正在被返回的那个代理对象,通常不用这个参数,不然容易出现栈溢出
参数2,代理对象正在调用的方法,参数3代理对象调用方法时传入的参数
下面来示例下:
计算器接口
public interface Calculator {
public int add(int a,int b);
public int sub(int a,int b);
}
实现类:
public class MathCalculator implements Calculator {
@Override
public int add(int a, int b) {
int i =a+b;
return i;
}
@Override
public int sub(int a, int b) {
int i=a-b;
return i;
}
}
需要实现的功能是在每次调用add或者sub的前后各输出一句话,定义InvocationHandler实现类有点困难,使用匿名内部类
package proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;
public class TestCal {
public static void main(String[] args) {
//创建被代理对象
final MathCalculator mc = new MathCalculator();
//创建代理对象,返回被代理对象接口的类型
//3个参数,1代理对象的类加载器,2,代理对象要实现的接口的Class数组
//3new InvocationHandler实例,匿名内部类
Object proxy = Proxy.newProxyInstance(mc.getClass().getClassLoader(), mc.getClass().getInterfaces(),
new InvocationHandler() {
//重写invoke方法,参数1,不用它,参数2,代理对象调用的方法,参数3,方法需要传入的参数
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("hello " + method.getName() + " parameter is: " + Arrays.asList(args));
Object result = method.invoke(mc, args);// 第一个参数,被代理类的对象.第二个参数,args
System.out.println("world" + " the result is " + result);
return result;
}
});
Calculator cal = (Calculator) proxy;
cal.add(10, 20);
cal.sub(10, 60);
}
}
out:
hello add parameter is: [10, 20]
30
world the result is 30
hello sub parameter is: [10, 60]
-50
world the result is -50