java-动态代理(CGLib、JDK动态代理)
CGLIB
什么是CGLIb
- CGLIB通过ASM来转换字节码并生成新的类。
- 它可以实现在运行过程中,扩展java类或者实现java接口。
- 它是对ASM的包装,简化了 开发难度。
CGLib是如何工作的
- 通过继承指定的类,在派生类中重写非final方法。
- 在生成代码的时候,通过反射获取被代理方法的Method对象,并同时生成被代理方法的代理对象。
- 在重写被代理方法时:根据回调过滤器选择具体的CallBack
Callback
回调过滤器
- 继承并重写CallBackFilter类的accept方法,该方法接受一个Method对象
- 函数中的int返回值,表示CallBack数组的索引位置。
- 过滤器相当于绑定了方法的CallBack的映射关系。
public class TargetMethodCallbackFilter implements CallbackFilter {
/**
* 过滤方法
* 返回的值为数字,代表了Callback数组中的索引位置,要到用的Callback
*/
@Override
public int accept(Method method) {
if(method.getName().equals("method1")){
System.out.println("filter method1 ==0");
return 0;
}
if(method.getName().equals("method2")){
System.out.println("filter method2 ==1");
return 1;
}
if(method.getName().equals("method3")){
System.out.println("filter method3 ==2");
return 2;
}
return 0;
}
}
public class TestCglib {
public static void main(String args[]) {
Enhancer enhancer =new Enhancer();
enhancer.setSuperclass(TargetObject.class);
CallbackFilter callbackFilter = new TargetMethodCallbackFilter();
/**
* (1)callback1:方法拦截器
(2)NoOp.INSTANCE:这个NoOp表示no operator,即什么操作也不做,代理类直接调用被代理的方法不进行拦截。
(3)FixedValue:表示锁定方法返回值,无论被代理类的方法返回什么值,回调方法都返回固定值。
*/
Callback noopCb=NoOp.INSTANCE;
Callback callback1=new TargetInterceptor();
Callback fixedValue=new TargetResultFixed();
Callback[] cbarray=new Callback[]{callback1,noopCb,fixedValue};
//设置数组而不是单个回调
//enhancer.setCallback(new TargetInterceptor());
enhancer.setCallbacks(cbarray);
enhancer.setCallbackFilter(callbackFilter);
TargetObject targetObject2=(TargetObject)enhancer.create();
System.out.println(targetObject2);
System.out.println(targetObject2.method1("mmm1"));
System.out.println(targetObject2.method2(100));
System.out.println(targetObject2.method3(100));
System.out.println(targetObject2.method3(200));
}
}
1、FixedValue(固定值)
- 不需要执行代理逻辑,返回固定值
/*****
* 该callback相当于重写了相应的函数实现。并不会调用原函数
*/
public class FixValueCallback implements FixedValue {
/*****
* 被代理方法的指定函数将会无条件的返回改object,动态的变更返回值
* @return
* @throws Exception
*/
public Object loadObject() throws Exception {
System.out.println("this is fixvalue callback ..... overwrite the code....");
return true;
}
}
//产生的代码样例
public final void methodForFixValue() {
FixedValue var10000 = this.CGLIB$CALLBACK_5;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_5;
}
//直接调用了FixValue callback的loadObject,相当于重写逻辑
var10000.loadObject();
}
2、InvocationHandler
- invoke方法中没有传入被代理对象本身
- 防止无限循环调用的方式是,method方法传入的动态类型是基类(被代理对象),基类中的方法不会再调用invoke方法。
public class InvocationHandlerCallback implements InvocationHandler {
/*****
* invocationHandler的invoke方法传入的method和proxy都是代理本身对象
* 切忌重复调用,会循环调用
* @param proxy 代理类本身
* @param method 被代理类的内部的方法
* @param args 参数
* @return
* @throws Throwable
*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("invocationHandlerCallback Before....");
//proxy.getClass().getSuperclass().newInstance()获取父类对象
//这个父类对象也可以在CallBack的构造函数中传入
method.invoke(proxy.getClass().getSuperclass().newInstance(),args);
//会无限循环,原因:动态类型指向了代理类,在代理中还会调用invoke
//method.invoke(proxy,args);
System.out.println("invocationHandlerCallback after....");
return null;
}
}
//产生的代码样例
public final void methodForInvocationHandler() {
try {
InvocationHandler var10000 = this.CGLIB$CALLBACK_4;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_4;
}
//调用InvocationHandler相应的invoke实现
var10000.invoke(this, CGLIB$methodForInvocationHandler$4, new Object[0]);
} catch (Error | RuntimeException var1) {
throw var1;
} catch (Throwable var2) {
throw new UndeclaredThrowableException(var2);
}
}
3、LazyLoader
- 代理对象内部维护了一个被代理对象的引用,当需要访问被代理对象时,会在同步方法内判断该引用是否为空。
- 如果为空,则会调用懒加载器生成被代理对象。
- LazyLoader仅会在第一次访问被代理对象时调用,如果没有访问被代理对象,则不会产生该对象,实现懒加载。
- 注意:懒加载是指被代理对象的懒加载,而不是被代理对象内部属性的懒加载。内部使用了synchronized,可能会存在性能问题
/****
*
* 延迟加载初始化
* 类似于spring prototype的singleton ,在第一次调用的时候进行初始化,并且将此实例存储起来,之后都将返回改实例
* 可参考资料:
* https://shensy.iteye.com/blog/1881277
*/
public class LazyLoaderCallback implements LazyLoader {
public Object loadObject() throws Exception {
CallbackBean callbackBean = new CallbackBean();
return callbackBean;
}
}
//产生的代码样例
public final String getKey() {
//获取被代理对象,并调用父类方法
return ((PropertyBean)this.CGLIB$LOAD_PRIVATE_0()).getKey();
}
private final synchronized Object CGLIB$LOAD_PRIVATE_0() {
Object var10000 = this.CGLIB$LAZY_LOADER_0;
if (var10000 == null) {
LazyLoader var10001 = this.CGLIB$CALLBACK_0;
if (var10001 == null) {
CGLIB$BIND_CALLBACKS(this);
var10001 = this.CGLIB$CALLBACK_0;
}
var10000 = this.CGLIB$LAZY_LOADER_0 = var10001.loadObject();
}
return var10000;
}
Hibernate例子
-
实体类
public class PropertyBean { private String key; private Object value; public String getKey() { return key; } public void setKey(String key) { this.key = key; } public Object getValue() { return value; } public void setValue(Object value) { this.value = value; } @Override public String toString() { return "PropertyBean [key=" + key + ", value=" + value + "]" +getClass(); } } -
延迟加载器
public class ConcreteClassLazyLoader implements LazyLoader { /** * 对需要延迟加载的对象添加代理,在获取该对象属性时先通过代理类回调方法进行对象初始化。 * 在不需要加载该对象时,只要不去获取该对象内属性,该对象就不会被初始化了(在CGLib的实现中只要去访问该对象内属性的getter方法, * 就会自动触发代理类回调)。 */ @Override public Object loadObject() throws Exception { System.out.println("before lazyLoader..."); PropertyBean propertyBean = new PropertyBean(); propertyBean.setKey("zghw"); propertyBean.setValue(new TargetObject()); System.out.println("after lazyLoader..."); return propertyBean; } } -
生成代理对象
//返回一个PropertyBean对象,不过这个对象是PropertyBean的代理对象 //当访问代理对象的属性时(即调用GETTER),会触发被代理对象的初始化,调用loadObject方法返回真正的被代理对象 private PropertyBean createPropertyBean() { /** * 使用cglib进行懒加载 对需要延迟加载的对象添加代理,在获取该对象属性时先通过代理类回调方法进行对象初始化。 * 在不需要加载该对象时,只要不去获取该对象内属性,该对象就不会被初始化了(在CGLib的实现中只要去访问该对象内属性的getter方法, * 就会自动触发代理类回调)。 */ Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(PropertyBean.class); PropertyBean pb = (PropertyBean) enhancer.create(PropertyBean.class, new ConcreteClassLazyLoader()); return pb; }
4、Dispatcher
- 实现Dispatcher接口,要求实现loadObject方法,返回期望的代理类。值的一提的是,loadobject方法在每次调用被拦截方法的时候都会被调用一次
/****
* 与lazy不同的是,每一次调用代理方法的时候,都会调用一次Dispatcher的loadObject获取对象
* 而lazy则会缓存下来。
*/
public class DispatcherCallBack implements Dispatcher {
public Object loadObject() throws Exception {
CallbackBean callbackBean = new CallbackBean();
return callbackBean;
}
}
//CGLIB产生的代码
public final void methodForDispatcher() {
Dispatcher var10000 = this.CGLIB$CALLBACK_3;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_3;
}
//每次都调用一次loadObject,获取对象,并调用对象的相应方法
//这样的实现,相当于loadObject可以很灵活的返回相应的实现类或者子类
((CallbackBean)var10000.loadObject()).methodForDispatcher();
}
5、MethodInterceptor
public class MyMethodInterceptor implements MethodInterceptor{
/**
* sub:cglib生成的代理对象
* method:被代理对象方法
* objects:方法入参
* methodProxy: 代理方法
*/
@Override
public Object intercept(Object sub, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("======插入前置通知======");
//method.invoke(sub,args);
//invokeSuper会调用sub的基类的方法
Object object = methodProxy.invokeSuper(sub, objects);
System.out.println("======插入后者通知======");
return object;
}
}
//CGLib生成的代码
public final void methodForInterceptor() {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_1;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_1;
}
if (var10000 != null) {
//调用callback的intercept方法,用于实现拦截
var10000.intercept(this, CGLIB$methodForInterceptor$1$Method, CGLIB$emptyArgs, CGLIB$methodForInterceptor$1$Proxy);
} else {
super.methodForInterceptor();
}
}
6、NoOp
- 通过接口声明了一个单例对象,该代理不对被代理类执行任何操作
样例
业务类
public class HelloService {
public HelloService() {
System.out.println("HelloService构造");
}
/**
* 该方法不能被子类覆盖,Cglib是无法代理final修饰的方法的
*/
final public String sayOthers(String name) {
System.out.println("HelloService:sayOthers>>"+name);
return null;
}
public void sayHello() {
System.out.println("HelloService:sayHello");
}
}
MethodInterceptor
public class MyMethodInterceptor implements MethodInterceptor{
/**
* sub:cglib生成的代理对象
* method:被代理对象方法
* objects:方法入参
* methodProxy: 代理方法
*/
@Override
public Object intercept(Object sub, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("======插入前置通知======");
//method.invoke(sub,args);
Object object = methodProxy.invokeSuper(sub, objects);
System.out.println("======插入后者通知======");
return object;
}
}
method.invoke(sub,args)
- sub代表的是动态生成的代理类,也就是说invoke方法参数实际的实际类型为代理类
- 代理类的重写方法会调用拦截器的方法,导致死循环
生成CGLIB代理对象调用目标方法
public class Client {
public static void main(String[] args) {
// 代理类class文件存入本地磁盘方便我们反编译查看源码
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D:\\code");
// 通过CGLIB动态代理获取代理对象的过程
Enhancer enhancer = new Enhancer();
// 设置enhancer对象的父类
enhancer.setSuperclass(HelloService.class);
// 设置enhancer的回调对象
enhancer.setCallback(new MyMethodInterceptor());
// 创建代理对象
HelloService proxy= (HelloService)enhancer.create();
// 通过代理对象调用目标方法
proxy.sayHello();
}
}
源码解析
反编译后代码
public class HelloService$$EnhancerByCGLIB$$be45efdd extends HelloService implements Factory {
private boolean CGLIB$BOUND;
public static Object CGLIB$FACTORY_DATA;
private static final ThreadLocal CGLIB$THREAD_CALLBACKS;
private static final Callback[] CGLIB$STATIC_CALLBACKS;
//外部传递进来的拦截器
private MethodInterceptor CGLIB$CALLBACK_0;
private static Object CGLIB$CALLBACK_FILTER;
private static final Method CGLIB$sayHello$0$Method;
private static final MethodProxy CGLIB$sayHello$0$Proxy;
private static final Object[] CGLIB$emptyArgs;
private static final Method CGLIB$equals$1$Method;
private static final MethodProxy CGLIB$equals$1$Proxy;
private static final Method CGLIB$toString$2$Method;
private static final MethodProxy CGLIB$toString$2$Proxy;
private static final Method CGLIB$hashCode$3$Method;
private static final MethodProxy CGLIB$hashCode$3$Proxy;
private static final Method CGLIB$clone$4$Method;
private static final MethodProxy CGLIB$clone$4$Proxy;
static void CGLIB$STATICHOOK1() {
CGLIB$THREAD_CALLBACKS = new ThreadLocal();
CGLIB$emptyArgs = new Object[0];
Class var0 = Class.forName("com.jpeony.spring.proxy.cglib.HelloService$$EnhancerByCGLIB$$be45efdd");
Class var1;
Method[] var10000 = ReflectUtils.findMethods(new String[]{"equals", "(Ljava/lang/Object;)Z", "toString", "()Ljava/lang/String;", "hashCode", "()I", "clone", "()Ljava/lang/Object;"}, (var1 = Class.forName("java.lang.Object")).getDeclaredMethods());
CGLIB$equals$1$Method = var10000[0];
CGLIB$equals$1$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/Object;)Z", "equals", "CGLIB$equals$1");
CGLIB$toString$2$Method = var10000[1];
CGLIB$toString$2$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/String;", "toString", "CGLIB$toString$2");
CGLIB$hashCode$3$Method = var10000[2];
CGLIB$hashCode$3$Proxy = MethodProxy.create(var1, var0, "()I", "hashCode", "CGLIB$hashCode$3");
CGLIB$clone$4$Method = var10000[3];
CGLIB$clone$4$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/Object;", "clone", "CGLIB$clone$4");
CGLIB$sayHello$0$Method = ReflectUtils.findMethods(new String[]{"sayHello", "()V"}, (var1 = Class.forName("com.jpeony.spring.proxy.cglib.HelloService")).getDeclaredMethods())[0];
CGLIB$sayHello$0$Proxy = MethodProxy.create(var1, var0, "()V", "sayHello", "CGLIB$sayHello$0");
}
final void CGLIB$sayHello$0() {
super.sayHello();
}
//代理类动态重写的方法
public final void sayHello() {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
if (var10000 != null) {
var10000.intercept(this, CGLIB$sayHello$0$Method, CGLIB$emptyArgs, CGLIB$sayHello$0$Proxy);
} else {
super.sayHello();
}
}
final boolean CGLIB$equals$1(Object var1) {
return super.equals(var1);
}
public final boolean equals(Object var1) {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
if (var10000 != null) {
Object var2 = var10000.intercept(this, CGLIB$equals$1$Method, new Object[]{var1}, CGLIB$equals$1$Proxy);
return var2 == null ? false : (Boolean)var2;
} else {
return super.equals(var1);
}
}
final String CGLIB$toString$2() {
return super.toString();
}
public final String toString() {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
return var10000 != null ? (String)var10000.intercept(this, CGLIB$toString$2$Method, CGLIB$emptyArgs, CGLIB$toString$2$Proxy) : super.toString();
}
final int CGLIB$hashCode$3() {
return super.hashCode();
}
public final int hashCode() {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
if (var10000 != null) {
Object var1 = var10000.intercept(this, CGLIB$hashCode$3$Method, CGLIB$emptyArgs, CGLIB$hashCode$3$Proxy);
return var1 == null ? 0 : ((Number)var1).intValue();
} else {
return super.hashCode();
}
}
final Object CGLIB$clone$4() throws CloneNotSupportedException {
return super.clone();
}
protected final Object clone() throws CloneNotSupportedException {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
return var10000 != null ? var10000.intercept(this, CGLIB$clone$4$Method, CGLIB$emptyArgs, CGLIB$clone$4$Proxy) : super.clone();
}
public static MethodProxy CGLIB$findMethodProxy(Signature var0) {
String var10000 = var0.toString();
switch(var10000.hashCode()) {
case -508378822:
if (var10000.equals("clone()Ljava/lang/Object;")) {
return CGLIB$clone$4$Proxy;
}
break;
case 1535311470:
if (var10000.equals("sayHello()V")) {
return CGLIB$sayHello$0$Proxy;
}
break;
case 1826985398:
if (var10000.equals("equals(Ljava/lang/Object;)Z")) {
return CGLIB$equals$1$Proxy;
}
break;
case 1913648695:
if (var10000.equals("toString()Ljava/lang/String;")) {
return CGLIB$toString$2$Proxy;
}
break;
case 1984935277:
if (var10000.equals("hashCode()I")) {
return CGLIB$hashCode$3$Proxy;
}
}
return null;
}
public HelloService$$EnhancerByCGLIB$$be45efdd() {
CGLIB$BIND_CALLBACKS(this);
}
public static void CGLIB$SET_THREAD_CALLBACKS(Callback[] var0) {
CGLIB$THREAD_CALLBACKS.set(var0);
}
public static void CGLIB$SET_STATIC_CALLBACKS(Callback[] var0) {
CGLIB$STATIC_CALLBACKS = var0;
}
private static final void CGLIB$BIND_CALLBACKS(Object var0) {
HelloService$$EnhancerByCGLIB$$be45efdd var1 = (HelloService$$EnhancerByCGLIB$$be45efdd)var0;
if (!var1.CGLIB$BOUND) {
var1.CGLIB$BOUND = true;
Object var10000 = CGLIB$THREAD_CALLBACKS.get();
if (var10000 == null) {
var10000 = CGLIB$STATIC_CALLBACKS;
if (var10000 == null) {
return;
}
}
var1.CGLIB$CALLBACK_0 = (MethodInterceptor)((Callback[])var10000)[0];
}
}
public Object newInstance(Callback[] var1) {
CGLIB$SET_THREAD_CALLBACKS(var1);
HelloService$$EnhancerByCGLIB$$be45efdd var10000 = new HelloService$$EnhancerByCGLIB$$be45efdd();
CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
return var10000;
}
public Object newInstance(Callback var1) {
CGLIB$SET_THREAD_CALLBACKS(new Callback[]{var1});
HelloService$$EnhancerByCGLIB$$be45efdd var10000 = new HelloService$$EnhancerByCGLIB$$be45efdd();
CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
return var10000;
}
public Object newInstance(Class[] var1, Object[] var2, Callback[] var3) {
CGLIB$SET_THREAD_CALLBACKS(var3);
HelloService$$EnhancerByCGLIB$$be45efdd var10000 = new HelloService$$EnhancerByCGLIB$$be45efdd;
switch(var1.length) {
case 0:
var10000.<init>();
CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
return var10000;
default:
throw new IllegalArgumentException("Constructor not found");
}
}
public Callback getCallback(int var1) {
CGLIB$BIND_CALLBACKS(this);
MethodInterceptor var10000;
switch(var1) {
case 0:
var10000 = this.CGLIB$CALLBACK_0;
break;
default:
var10000 = null;
}
return var10000;
}
public void setCallback(int var1, Callback var2) {
switch(var1) {
case 0:
this.CGLIB$CALLBACK_0 = (MethodInterceptor)var2;
default:
}
}
public Callback[] getCallbacks() {
CGLIB$BIND_CALLBACKS(this);
return new Callback[]{this.CGLIB$CALLBACK_0};
}
public void setCallbacks(Callback[] var1) {
this.CGLIB$CALLBACK_0 = (MethodInterceptor)var1[0];
}
static {
CGLIB$STATICHOOK1();
}
}
样例
被代理对象
public class CallbackBean {
public void methodForDispatcher(){
System.out.println("methodForDispatcher...");
}
public void methodForFixValue(){
System.out.println("methodForFixValue...");
}
public void methodForInvocationHandler(){
System.out.println("methodForInvocationHandler...");
}
public void methodForLazy(){
System.out.println("methodForLazy...");
}
public void methodForInterceptor(){
System.out.println("methodForInterceptor...");
}
public void methodForNoop(){
System.out.println("methodForNoop...");
}
}
反编译分析
Dispatcher
public final void methodForDispatcher() {
Dispatcher var10000 = this.CGLIB$CALLBACK_3;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_3;
}
//每次都调用一次loadObject,获取对象,并调用对象的相应方法
//这样的实现,相当于loadObject可以很灵活的返回相应的实现类或者子类
((CallbackBean)var10000.loadObject()).methodForDispatcher();
}
FixedValue
public final void methodForFixValue() {
FixedValue var10000 = this.CGLIB$CALLBACK_5;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_5;
}
//直接调用了FixValue callback的loadObject,相当于重写逻辑
var10000.loadObject();
}
InvocationHandler
public final void methodForInvocationHandler() {
try {
InvocationHandler var10000 = this.CGLIB$CALLBACK_4;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_4;
}
//调用InvocationHandler相应的invoke实现
var10000.invoke(this, CGLIB$methodForInvocationHandler$4, new Object[0]);
} catch (Error | RuntimeException var1) {
throw var1;
} catch (Throwable var2) {
throw new UndeclaredThrowableException(var2);
}
}
LazyLoader
public final void methodForLazy() {
//CGLIB$LOAD_PRIVATE_2在proxy初始化的时候初始化一次,并维护了该成员
//与Dispatcher不同,每次调用都是运用proxy成员变量进行调用
((CallbackBean)this.CGLIB$LOAD_PRIVATE_2()).methodForLazy();
}
MethodInterceptor
public final void methodForInterceptor() {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_1;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_1;
}
if (var10000 != null) {
//调用callback的intercept方法,用于实现拦截
var10000.intercept(this, CGLIB$methodForInterceptor$1$Method, CGLIB$emptyArgs, CGLIB$methodForInterceptor$1$Proxy);
} else {
super.methodForInterceptor();
}
}
CGLib问题集合
内存溢出
- 如果不使用缓存,将导致创建多个代理类,使方法区溢出
- 解决方式:enhancer.setUseCache(true);
API
Enhancer
- 和Proxy不同的是,Enhancer既能够代理普通的class,也能够代理接口。
- Enhancer创建一个被代理对象的子类并且拦截所有的方法调用(包括从Object中继承的toString和hashCode方法)。
- Enhancer不能够拦截final方法,例如Object.getClass()方法,这是由于Java final方法语义决定的。基于同样的道理,Enhancer也不能对fianl类进行代理操作。这也是Hibernate为什么不能持久化final class的原因。
Enhancer enhancer = new Enhancer();
enhancer.setUseCache(true);
enhancer.setSuperclass(PropertyBean.class);
PropertyBean pb = (PropertyBean) enhancer.create(PropertyBean.class,
new MyMethodInterceptor());
pb.getKey();
问题toString、hashCode报错
- CGLib会代理toString、hashCode等方法,如果CallBack的返回值不满足原函数要求可能报错,例如:
- FixedValue返回的是固定值,导致不会返回基类的hashCode;
- MethodInterceptor拦截方法后,修改了返回值。
- 解决方式:视具体情况,为toString、hashCode等方法添加执行的CallBack。
被代理对象有多个构造函数
- 先通过Enhancer获取class对象,并获取到构造器。
- 构造器在newInstance方法中通过参数类型、顺序去匹配具体的构造器。
- 但生成的构造函数不会调用CallBack
只对特定的方法执行代理
-
设置CallbackFilter,CallbackFilter中对于不执行代理的方法返回NoOp.INSTANCE
-
Enhancer enhancer = new Enhancer(); CallbackHelper callbackHelper = new CallbackHelper(PropertyBean.class, new Class[0]) { @Override protected Object getCallback(Method method) { if(method.getDeclaringClass() != Object.class && method.getReturnType() == String.class){ return new FixedValue() { @Override public Object loadObject() throws Exception { return "Hello cglib"; } }; }else{ return NoOp.INSTANCE; } } }; enhancer.setCallbackFilter(callbackHelper); enhancer.setCallbacks(callbackHelper.getCallbacks()); -
也可以直接实现CallbackFilter接口
ImmutableBean
- ImmutableBean允许创建一个原来对象的包装类,
- 这个包装类是不可变的,任何改变底层对象的包装类操作都会抛出IllegalStateException。
- 包装类不可变,但被代理对象可变。
POJO
public class SampleBean {
private String value;
public SampleBean() {
}
public SampleBean(String value) {
this.value = value;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
Test
@Test(expected = IllegalStateException.class)
public void testImmutableBean() throws Exception{
//创建被代理对象
SampleBean bean = new SampleBean();
bean.setValue("Hello world");
//创建代理
SampleBean immutableBean = (SampleBean) ImmutableBean.create(bean); //创建不可变类
Assert.assertEquals("Hello world",immutableBean.getValue());
bean.setValue("Hello world, again"); //可以通过底层对象来进行修改
Assert.assertEquals("Hello world, again", immutableBean.getValue());
immutableBean.setValue("Hello cglib"); //直接修改将throw exception
}
Bean generator
- 在运行过程中创建类
- 可以设置类的基类、添加属性(同时添加get、set方法)
@Test
public void testBeanGenerator() throws Exception{
BeanGenerator beanGenerator = new BeanGenerator();
beanGenerator.addProperty("value",String.class);//添加属性
Object myBean = beanGenerator.create();
Method setter = myBean.getClass().getMethod("setValue",String.class);
setter.invoke(myBean,"Hello cglib");
Method getter = myBean.getClass().getMethod("getValue");
Assert.assertEquals("Hello cglib",getter.invoke(myBean));
}
JDK动态代理
- Proxy根据类加载器和接口数组生成接口的实现类,在实现的方法中调用InvocationHandler的invoke方法。
- 在invoke方法中可以执行业务逻辑,(可以装配不同的实现类)

使用样例
-
1、创建一个接口
public interface HelloService { void sayHello(); } -
第二步,实现接口
public class HelloServiceImpl implements HelloService { @Override public void sayHello() { System.out.println("HelloService:sayHello"); } } -
代理类:实现InvocationHandler
public class HelloServiceIvtHandler implements InvocationHandler { public HelloService helloService; public void HelloServiceIvtHandler(HelloService helloService){ this.helloService=helloService; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { method.invoke(helloService,args); return null; } } -
使用
public class Main { public static void main(String[] args) { HelloService helloService = new HelloServiceImpl(); //创建调用器,并装配被代理对象。具体什么时候装配被代理对象视具体情况而定。 InvocationHandler handler = new HelloServiceIvtHandler(helloService); //根据上述对象创建新对象 HelloService helloServiceProxy = (HelloService) Proxy.newProxyInstance( helloService.getClass().getClassLoader(), helloService.getClass().getInterfaces(), handler); //调用 helloServiceProxy.sayHello(); } }
Proxy.newProxyInstance
public static Object newProxyInstance(ClassLoader loader,//用哪个类加载器去加载代理对象
Class<?>[] interfaces,//动态代理类需要实现的接口
InvocationHandler h//动态代理方法在执行时,会调用h里面的invoke方法去执行
)
throws IllegalArgumentException
源码分析
-
newProxyInstance
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException { Objects.requireNonNull(h); //1、获取目标接口的克隆对象 final Class<?>[] intfs = interfaces.clone(); final SecurityManager sm = System.getSecurityManager(); if (sm != null) { checkProxyAccess(Reflection.getCallerClass(), loader, intfs); } //2、根据接口:生成代理类对象 Class<?> cl = getProxyClass0(loader, intfs); //使用指定的调用处理程序获取代理类的构造函数对象 try { if (sm != null) { checkNewProxyPermission(Reflection.getCallerClass(), cl); } // final Constructor<?> cons = cl.getConstructor(constructorParams); final InvocationHandler ih = h; //3、如果Class作用域为私有,通过 setAccessible 支持访问 if (!Modifier.isPublic(cl.getModifiers())) { AccessController.doPrivileged(new PrivilegedAction<Void>() { public Void run() { cons.setAccessible(true); return null; } }); } //4、获取Proxy Class构造函数,创建Proxy代理实例。 return cons.newInstance(new Object[]{h}); } catch (IllegalAccessException|InstantiationException e) { throw new InternalError(e.toString(), e); } catch (InvocationTargetException e) { Throwable t = e.getCause(); if (t instanceof RuntimeException) { throw (RuntimeException) t; } else { throw new InternalError(t.toString(), t); } } catch (NoSuchMethodException e) { throw new InternalError(e.toString(), e); } }
局限性
- 只能对该类所实现接口中定义的方法进行代理
浙公网安备 33010602011771号