前言
按照代理类的创建时期,代理类可分为两种:
–静态代理类:由程序员创建或由特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。
–动态代理类:在程序运行时,运用反射机制动态创建而成。
而动态代理又有cglib代理和jdk代理之分。
适用范围:
1、如果目标对象实现了接口,一般情况下采用JDK的动态代理
2、如果目标对象实现了接口,可以强制使用CGLIB实现AOP
3、如果目标对象没有实现了接口,必须采用CGLIB库
区别:
1、JDK动态代理利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。只能对实现了接口的类生成代理,而不能针对类。
2、CGLIB动态代理利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。是针对类实现代理在子类中覆盖指定类的方法。因为是继承,所以该类或方法最好不要声明成final 。
JDK代理
java.lang.reflect包中的Proxy类和InvocationHandler接口提供了生成动态代理类的能力。
Proxy类
Proxy类提供了创建动态代理类及其的实例的静态方法:
(1)getProxyClass()静态方法负责创建动态代理类,它的完整定义如下:
/**
*loader:指定动态代理类的类加载器
*interfaces:指定动态代理类需要实现的所有接口
*/
public static Class<?> getProxyClass(ClassLoader loader, Class<?>[] interfaces) throws IllegalArgumentException
(2)newProxyInstance()静态方法负责创建动态代理类的实例,它的完整定义如下:
/**
*loader:指定动态代理类的类加载器
*interfaces:指定动态代理类需要实现的所有接口
*handler:指定与动态代理类关联的 InvocationHandler对象
*/
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler handler) throws IllegalArgumentException
以下两种方式都创建了实现Foo接口的动态代理类的实例:
/**** 方式一 ****/
//创建InvocationHandler对象
InvocationHandler handler = new MyInvocationHandler(...);
//创建动态代理类
Class proxyClass = Proxy.getProxyClass(
Foo.class.getClassLoader(), new Class[] { Foo.class });
//创建动态代理类的实例
Foo foo = (Foo) proxyClass.
getConstructor(new Class[] { InvocationHandler.class })
.newInstance(new Object[] { handler });
/**** 方式二 ****/
//创建InvocationHandler对象
InvocationHandler handler = new MyInvocationHandler(...);
//直接创建动态代理类的实例
Foo foo = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),
new Class[] { Foo.class },
handler);
InvocationHandler接口
InvocationHandler接口为方法调用接口,它声明了负责调用任意一个方法的invoke()方法:
/**
*proxy:指定动态代理类实例
*method:指定被调用的方法
*args:指定被调用方法传递的参数
*invoke()方法的返回值表示被调用方法的返回值
*/
Object invoke(Object proxy,Method method,Object[] args) throws Throwable
示例
接口类和目标类
//接口类
public interface ISomeInterface {
public String doSomething(String arg);
}
//持有方法的目标类
public class TargetClass implements ISomeInterface {
public TargetClass() {
}
@Override
public String doSomething(String arg) {
System.out.println("正在执行doSomthing()方法");
return "["+arg+"]";
}
public String dealSomething(String arg) {
System.out.println("正在执行dealSomthing()方法");
return "{"+arg+"}";
}
}
JDK代理类
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class JDKProxy {
public JDKProxy() {
}
@SuppressWarnings("unchecked")
public static <T> T getProxy(T target) {
Class<?> klass = target.getClass();
ClassLoader classLoader = klass.getClassLoader();
Class<?>[] interfaces = klass.getInterfaces();
return (T)Proxy.newProxyInstance(classLoader, interfaces,
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("前置拦截");
Object result = method.invoke(target, args);
System.out.println("后置拦截");
return result;
}
});
}
}
测试类
import gw.proxy.jdk.core.JDKProxy;
import gw.proxy.some.ISomeInterface;
import gw.proxy.some.TargetClass;
public class JDKTest {
public static void main(String[] args) {
TargetClass target = new TargetClass();
//参数target为被代理的对象
ISomeInterface some = JDKProxy.getProxy(target);
//some.doSomething("abcd")通过代理对象来调用实现的接口中的方法
String str = some.doSomething("abcd");
System.out.println(str);
}
}
运行结果:
CGLib代理
CGLib代理是第三方库提供的动态代理,是基于子类的动态代理
要实现CGLib动态代理必须实现MethodInterceptor(方法拦截器)接口,并且通过Enhancer类中的create()方法创建代理对象
MethodInterceptor(方法拦截器)接口
public interface MethodInterceptor extends Callback{
/**
*obj:cglib生成的代理对象
*method:被代理对象的方法
*args:方法的参数
*proxy:方法代理
*/
public Object intercept(Object obj, Method method, Object[] args,MethodProxy proxy) throws Throwable;
}
示例
cglib代理类
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
//代理类
public class CGLibProxy {
@SuppressWarnings("unchecked")
public static <T> T getProxy(T target){
Class<?> klass = target.getClass();
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(klass);//设置需要继承的类
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object object, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("前置拦截");
Object result = method.invoke(target, args);
System.out.println("后置拦截");
return result;
}
});
return (T) enhancer.create();
}
}
Enhancer可以用来动态的生成一个类,这个类可以继承指定的一个类,实现指定的一些接口。同时,Enhancer在生成一个类之前需要指定一个Callback,当类方法调用时,方法的执行被分配给这个Callback,MethodInterceptor是一个使用比较多的继承自Callback的接口,它只有一个方法声明。
测试类:
import gw.proxy.cglib.core.CGLibProxy;
import gw.proxy.some.TargetClass;
public class CGLibTest {
public static void main(String[] args) {
TargetClass target = new TargetClass();
TargetClass targetProxy = CGLibProxy.getProxy(target);
String str = targetProxy.doSomething("abcd");
System.out.println(str);
}
}
运行结果:
总之,jdk创建对象的速度远大于cglib,这是由于cglib创建对象时需要操作字节码。cglib执行速度略大于jdk,所以比较适合单例模式。
参考博文:
https://www.cnblogs.com/sandaman2019/p/12636727.html
https://www.jianshu.com/p/46d092bb737d
https://blog.csdn.net/flyfeifei66/article/details/81481222
https://www.cnblogs.com/hujunzheng/p/5134478.html?utm_source=tuicool&utm_medium=referral