目录
动态代理的介绍
动态代理是一种在运行时动态地创建代理对象,动态地处理代理方法调用的机制。实际上它是一种代理机制。代理可以看做是对调用目标的一个封装,直接通过代理来实现对目标代码的调用。
动态代理优点
1、静态代理在程序执行前需手动创建代理类,如果需要很多代理类,每一个都手动创建不仅浪费时间,而且可能产生大量重复性代码,此时我们就可以采用动态代理。
2、动态代理通过InvocationHandler接口invoke方法或MethodInterceptor接口intercept方法为被代理对象中的方法增加额外功能,这种方式比静态代理中通过代理类逐一为被代理对象中的方法增加额外功能,更加的灵活。
动态代理的实现方式
动态代理主要有两种实现方式,一种是JDK动态代理,一种是CGLIB字节码机制。
1、JDK动态代理
程序执行时使用java.lang.reflect包中Proxy类与InvocationHandler接口动态地生成一个实现代理接口的匿名代理类及其对象,无论调用代理对象哪个方法,最终都会执行invoke方法。
2、CGLib动态代理
程序执行时通过ASM(开源的Java字节码编辑库,操作字节码)jar包动态地为被代理类生成一个代理子类,通过该代理子类创建代理对象,由于存在继承关系,所以父类不能使用final修饰。
3、JDK动态代理与CGLib动态代理区别
- JDK动态代理基于接口实现,所以实现JDK动态代理,必须先定义接口;CGLib动态代理基于类实现;
- JDK动态代理机制是委托机制,委托hanlder调用原始实现类方法;CGLib则使用继承机制,被代理类和代理类是继承关系,所以代理类是可以赋值给被代理类的,如果被代理类有接口,那么代理类也可以赋值给接口。
JDK动态代理的实现与源码分析
下面我们通过一个具体实例来分析jdk动态代理的实现过程:
接口类:
public interface ICalculatorService {
int add(int a,int b);
}
接口实现类:
public class CalculatorService implements ICalculatorService {
@Override
public int add(int a, int b) {
int result = a+b;
}
}
测试类:
public class Test {
CalculatorService calculatorService;//目标类
public Test(CalculatorService calculatorService) {//构造方法
this.calculatorService = calculatorService;
}
//匿名内部类
InvocationHandler h = new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String name = method.getName();
System.out.println(this.getClass().getName()+":The "+name+" method begins.");
System.out.println(this.getClass().getName()+":Parameters of the "+name+" method: ["+args[0]+","+args[1]+"]");
Object result = method.invoke(calculatorService, args);//目标方法
System.out.println(this.getClass().getName()+":Result of the "+name+" method:"+result);
System.out.println(this.getClass().getName()+":The "+name+" method ends.");
return result;
}
};
public Object get() {//返回动态代理类的实例化对象
return Proxy.newProxyInstance(Test.class.getClassLoader(), new Class[] {ICalculatorService.class}, h);//产生一个动态class类,
}
public static void main(String[] args) {
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
Test test = new Test(new CalculatorService());
ICalculatorService calculatorService = (ICalculatorService) test.get();//获取代理对象
System.out.println(calculatorService.getClass().getName());
int result = calculatorService.add(1, 1);//调用动态类的add方法
System.out.println("-->"+result);
}
}
执行过程分析:
(1)ICalculatorService calculatorService = (ICalculatorService) test.get();//调用get方法,获取代理对象
分析:①动态代理对象生成:Proxy.newProxyInstance(Test.class.getClassLoader(), new Class[] {ICalculatorService.class}, h);
②查看Proxy类的newProxyInstance方法,从生成对象方法中,我们看到三个关键的地方:
- Class<?> cl = getProxyClass0(loader, intfs);//得到动态代理类
- final Constructor<?> cons = cl.getConstructor(constructorParams);//得到动态代理类相应的构造方法
- return cons.newInstance(new Object[]{h});//将InvocationHandler h传入代理对象中,返回一个由cons构造方法生成的动态代理类实例
(2)int result = calculatorService.add(1, 1);//调用动态代理对象的add方法
动态代理类的构造方法:将InvocationHandler h传入代理对象中
public $Proxy0(InvocationHandler invocationhandler)
{
super(invocationhandler);
}
动态代理类的add方法:
public final int add(int i, int j)
{
try
{
return ((Integer)super.h.invoke(this, m3, new Object[] {
Integer.valueOf(i), Integer.valueOf(j)
})).intValue();
}
catch(Error _ex) { }
catch(Throwable throwable)
{
throw new UndeclaredThrowableException(throwable);
}
}
分析:调用匿名内部类对象的invoke方法,其中参数this指此动态代理对象calculatorService,m3是指方法add,最后一个参数为方法add的参数i、j,执行匿名内部类对象的invoke方法:
InvocationHandler h = new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String name = method.getName();
System.out.println(this.getClass().getName()+":The "+name+" method begins.");
System.out.println(this.getClass().getName()+":Parameters of the "+name+" method: ["+args[0]+","+args[1]+"]");
Object result = method.invoke(calculatorService, args);//目标方法
//calculatorService调用CalculatorService中的add方法,返回int值?
System.out.println(this.getClass().getName()+":Result of the "+name+" method:"+result);
System.out.println(this.getClass().getName()+":The "+name+" method ends.");
return result;
}
};
其中Object result = method.invoke(calculatorService, args);指调用CalculatorService类的calculatorService对象的相应add方法,返回两数之和:
public class CalculatorService implements ICalculatorService {
@Override
public int add(int a, int b) {
int result = a+b;
return result;
}
至此,程序运行结束,运行结果如下:
com.jd.test.Test$1:The add method begins.
com.jd.test.Test$1:Parameters of the add method: [1,1]
com.jd.test.Test$1:Result of the add method:2
com.jd.test.Test$1:The add method ends.
-->2