代理模式 – cglib代理
目录
cglib代理
在使用的是静态代理和动态代理都需要目标对象是一个实现了接口的目标对象,当目标对象可能只是一个单独的对象,并没有实现任何的接口,那如何进行代理? 需要使用cglib代理
Cglib代理是什么?
Cglib代理,也叫做子类代理,它是在内存中构件一个子类对象,从而实现对目标对象的功能拓展。 cglib包的底层是通过使用一个小而快的字节码处理框架ASM来转换字节码并生成新的类,不鼓励直接只使用ASM,因为它要求你必须对JVM内部结构,包括class文件的格式和指令集都很熟悉。
如何实现呢?
在Java中要想实现cglib代理机制,需要org.springframework.cglib.proxy.MethodInterceptor接口和 org.springframework.cglib.proxy.Enhancer 类的支持
例子-常规
代码:
问候 Greet
public interface Greet {
void say(String name);
}
问候实现 GreetIml
public class GreetImpl implements Greet {
@Override
public void say(String name) {
System.out.println("Hi! " + name);
}
}
商店 Shop
public interface Shop {
void sell(String wares);
}
商店实现 ShopImpl
public class ShopImpl implements Shop {
@Override
public void sell(String foodName) {
System.out.println("sell the " + foodName);
}
}
cglib代理 CGLibProxy
public class CGLibProxy implements MethodInterceptor {
public <T> T getProxy(Class<T> cls) {
return (T) Enhancer.create(cls, (Callback) this);
}
// CGLib 给我们提供的是方法级别的代理,也可以理解为为对方法的拦截
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
before();
Object result = methodProxy.invokeSuper(obj, args);
after();
return result;
}
private void before() {
System.out.println("Before");
}
private void after() {
System.out.println("After");
}
}
在cglib代理类中,实现MethodInterceptor 的接口,调用 methodProxy.invokeSuper(obj, args)
测试:,
public class TestCglib {
public static void main(String[] args) throws Exception {
CGLibProxy cgLibProxy = new CGLibProxy();
System.out.println("========== greet proxy ==========");
Greet greetProxy = cgLibProxy.getProxy(GreetImpl.class);
greetProxy.say("cglib");
System.out.println("========== shop proxy ==========");
Shop shopProxy = cgLibProxy.getProxy(ShopImpl.class);
shopProxy.sell(" potato chips");
}
}
结果:
========== greet proxy ==========
Before
Hi! cglib
After
========== shop proxy ==========
Before
sell the potato chips
After
例子-单例模式
代码:
cglli代理 CGLibProxySingle
public class CGLibProxySingle implements MethodInterceptor {
private static class CGLibProxySingleHandler {
private static CGLibProxySingle staticInnerSingle = new CGLibProxySingle();
};
private CGLibProxySingle() {
}
public static CGLibProxySingle getInstance() {
return CGLibProxySingleHandler.staticInnerSingle;
}
public <T> T getProxy(Class<T> cls) {
return (T) Enhancer.create(cls, (Callback) this);
}
// CGLib 给我们提供的是方法级别的代理,也可以理解为为对方法的拦截
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
before();
Object result = methodProxy.invokeSuper(obj, args);
after();
return result;
}
private void before() {
System.out.println("Before");
}
private void after() {
System.out.println("After");
}
}
结合单例模式的静态内部类的引用
测试:
public class TestCglibSingle {
public static void main(String[] args) throws Exception {
System.out.println("========== greet proxy ==========");
Greet greetProxy = CGLibProxySingle.getInstance().getProxy(GreetImpl.class);
greetProxy.say("cglib singleton");
System.out.println("========== shop proxy ==========");
Shop shopProxy = CGLibProxySingle.getInstance().getProxy(ShopImpl.class);
shopProxy.sell("fried chicken");
}
}
结果:
========== greet proxy ==========
Before
Hi! cglib singleton
After
========== shop proxy ==========
Before
sell the fried chicken
After
总结:
当目标对象可能只是一个单独的对象,并没有实现任何的接口,这个时候需要cglib代理方式,即使用目标对象子类的方式实现代理.
动态代理和cgli代理进行比较:
1,对象不同:
Java动态代理只能够对接口进行代理,不能对普通的类进行代理(因为所有生成的代理类的父类为Proxy,Java类继承机制不允许多重继承);
CGLIB能够代理普通类;
2,实现方式不同:
Java动态代理使用Java原生的反射API进行操作,在生成类上比较高效;
CGLIB使用ASM框架直接对字节码进行操作,在类的执行过程中比较高效