一、动态代理:
1.含义:
在程序运行期间JVM根据需要通过反射等机制动态地创建代理类及其代理对象。
2.注意:
1、代理类是在程序运行期间创建,可以在classpath目录(在Eclipse中,Java工程中的bin目录;Web工程中的build目录)中看到该文件,
2、代理类和委托类的关系是在程序运行时确定的。
3.动态代理优点:
1、静态代理在程序执行前需手动创建代理类,如果需要很多代理类,每一个都手动创建不仅浪费时间,而且可能产生大量重复性代码,此时我们就可以采用动态代理。
2、动态代理通过InvocationHandler接口invoke方法或MethodInterceptor接口intercept方法为被代理对象中的方法增加额外功能,这种方式比静态代理中通过代理类逐一为被代理对象中的方法增加额外功能,更加的灵活。
二、JDK动态代理
代码分析
CalculatorService类中:
package com.jd.calculator;
public class CalculatorService implements ICalculatorService {
@Override
public int add(int a, int b) {
int result = a+b;
return result;
}
@Override
public int sub(int a, int b) {
int result = a-b;
return result;
}
@Override
public int mul(int a, int b) {
int result = a*b;
return result;
}
@Override
public int div(int a, int b) {
int result = a/b;
return result;
}
}
ICalculatorService接口:
package com.jd.calculator;
public interface ICalculatorService {
int add(int a,int b);
int sub(int a,int b);
int mul(int a,int b);
int div(int a,int b);
}
CalculatorService类中:
package com.jd.calculator;
public class CalculatorService implements ICalculatorService {
@Override
public int add(int a, int b) {
int result = a+b;
return result;
}
@Override
public int sub(int a, int b) {
int result = a-b;
return result;
}
@Override
public int mul(int a, int b) {
int result = a*b;
return result;
}
@Override
public int div(int a, int b) {
int result = a/b;
return result;
}
}
ICalculatorService接口:
package com.jd.calculator;
public interface ICalculatorService {
int add(int a,int b);
int sub(int a,int b);
int mul(int a,int b);
int div(int a,int b);
}
Test类中:
package com.jd.test;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import com.jd.calculator.CalculatorService;
import com.jd.calculator.ICalculatorService;
public class Test {
//动态(程序运行时实现和目标类相同接口的java类)代理(相当于中介)
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 {
System.out.println(proxy.getClass().getName());//①
System.out.println(method.getDeclaringClass().getName());
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]+"]");
//通过反射,因为多态所以实际上调用的是目标类中的add方法
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类,
}//Test.class.getClassLoader()是一个类加载器
public static void main(String[] args) {
//打印动态类,因为生成的动态类不能在磁盘中存在
//故使用这行代码让他显示出.class文件
//再用Java反编译器把.class文件转为.java文件
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
//创建一个目标类,给全局变量calculatorService赋值
Test test = new Test(new CalculatorService());
//获取代理对象,上转型对象
ICalculatorService calculatorService = (ICalculatorService) test.get();
//与①处的对象实质为同一个对象,即都为动态对象,故执行结果相同
System.out.println(calculatorService.getClass().getName());
//多态,表面上调用的是接口中的add方法,实际上调用的是目标类中的add方法
int result = calculatorService.add(1, 1);
System.out.println("-->"+result);
}
}
代码分析:
1、CalculatorService类为目标类,CalculatorService类中的方法为目标方法
2、CalculatorService是ICalculatorService的接口实现类,实现接口中的方法
3、Test类中运行后
首先执行main方法中的代码:
①打印动态类(执行完后刷新工程会出现一个com.sun.proxy的文件夹)得到
②创建一个目标类,给全局变量赋值
③test.get(),执行流跳转到get()方法
④执行get()方法,执行流进而转到newProxyInstance()方法
⑤按顺序执行下图
⑥动态类对象创建后,执行$Proxy0
类中的构造方法($Proxy0类继承自Proxy类且是ICalculatorService接口的实现类)
public $Proxy0(InvocationHandler invocationhandler)
{
//将参数(匿名内部类h传入),调用父类(Proxy)中的Proxy(InvocationHandler h)构造方法
super(invocationhandler);
}
⑦父类中的构造方法
⑧calculatorService.add(1, 1)调用目标类中的add方法
$Proxy0类中:
public final int add(int i, int j)
{
try
{//下面的this指的是calculatorService对象
return ((Integer)super.h.invoke(this, m4, new Object[] {//super.h指的是父类中的全局变量h,此处指匿名内部类h
Integer.valueOf(i), Integer.valueOf(j)
//super.h.invoke(this, m4, new Object[] {Integer.valueOf(i), Integer.valueOf(j)}执行完以后放回的是一个Object对象,强制类型转换为Integer型
})).intValue();
}
catch(Error _ex) { }
catch(Throwable throwable)
{
throw new UndeclaredThrowableException(throwable);
}
}
private static Method m4;
static //类加载的时候执行,m4为ICalculatorService接口中的add方法
{
try
{
m4 = Class.forName("com.jd.calculator.ICalculatorService").getMethod("add", new Class[] {
Integer.TYPE, Integer.TYPE
});
}
catch(NoSuchMethodException nosuchmethodexception)
{
throw new NoSuchMethodError(nosuchmethodexception.getMessage());
}
catch(ClassNotFoundException classnotfoundexception)
{
throw new NoClassDefFoundError(classnotfoundexception.getMessage());
}
}
⑨输出结果“2”
代码优化
//再创建一个ProxyFactory类,以实现代码的复用
package com.jd.calculator;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import com.jd.test.Test;
public class ProxyFactory {
public static Object getFactory(CalculatorService calculatorService) {
return Proxy.newProxyInstance(Test.class.getClassLoader(), new Class[] {ICalculatorService.class}, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String name = method.getName();
System.out.println(calculatorService.getClass().getName()+":The "+name+" method begins.");
System.out.println(calculatorService.getClass().getName()+":Parameters of the "+name+" method: ["+args[0]+","+args[1]+"]");
Object result = method.invoke(calculatorService, args);
System.out.println(calculatorService.getClass().getName()+":Result of the "+name+" method:"+result);
System.out.println(calculatorService.getClass().getName()+":The "+name+" method ends.");
return result;
}
});
}
}
Test类:
package com.jd.test;
import com.jd.calculator.CalculatorService;
import com.jd.calculator.ICalculatorService;
import com.jd.calculator.ProxyFactory;
public class Test {
//动态(程序运行时实现和目标类相同接口的java类)代理()
public static void main(String[] args) {
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
ICalculatorService calculatorService = (ICalculatorService) ProxyFactory.getFactory(new CalculatorService());//获取代理对象
int result = calculatorService.add(1, 1);
System.out.println("-->"+result);
}
}
三、CGLib动态代理
1.将下图的两个包拷入
2.代码(执行过程与JDK中的动态代理类似)
package com.jd.test;
import java.lang.reflect.Method;
import com.jd.calculator.CalculatorService;
import com.jd.calculator.ICalculatorService;
import com.jd.calculator.ProxyFactory;
import net.sf.cglib.proxy.Callback;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
public class Test{
static Callback callback = new MethodInterceptor() {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
String name = method.getName();
System.out.println(obj.getClass().getName()+":The "+name+" method begins.");
System.out.println(obj.getClass().getName()+":Parameters of the "+name+" method: ["+args[0]+","+args[1]+"]");
Object result = proxy.invokeSuper(obj, args);//获取目标类中的方法
System.out.println(obj.getClass().getName()+":Result of the "+name+" method:"+result);
System.out.println(obj.getClass().getName()+":The "+name+" method ends.");
return null;
}
};
private static Object get() {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(CalculatorService.class);
enhancer.setCallback(callback);
return enhancer.create();//创建动态代理类
}
public static void main(String[] args) {
CalculatorService calculatorService = (CalculatorService)get();//获取代理对象
int result = calculatorService.add(1, 1);
}
}
3.执行结果
四、JDK动态代理与CGLib动态代理区别
1、JDK动态代理基于接口实现,所以实现JDK动态代理,必须先定义接口;CGLib动态代理基于类实现;
2、JDK动态代理机制是委托机制,委托hanlder调用原始实现类方法,被代理类和代理类是同级关系;CGLib则使用继承机制,被代理类和代理类是继承关系,所以代理类是可以赋值给被代理类的,如果被代理类有接口,那么代理类也可以赋值给接口。