cglib代理主要通过对字节码的操作,为对象引入间接级别,以控制对象的访问,cglib相对于java动态代理更加强大,因为JDK动态代理有一个致命的缺陷,如果要代理一个普通类,没有接口,那么java动态代理就没法使用了。
在开始学习之前我们先简单的看一下
public class SampleClass {
public void test(){ //被代理对象
System.out.println("hello world");
}
public static void main(String[] args) {
//Enhancer : 增强
Enhancer enhancer=new Enhancer(); //创建一个增强因子对象
enhancer.setSuperclass(SampleClass.class); //设置代理类
enhancer.setCallback(new MethodInterceptor() { //设置代理回调方法
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("befor method run...");
Object result=methodProxy.invokeSuper(o,objects);
System.out.println("after method run...");
return result;
}
});
SampleClass sampleClass= (SampleClass) enhancer.create();
sampleClass.test();
}
}
在上面的程序中,我们引入了Enhance和MethodInterceptor
Enhancer可能是CGLIB中最常用的一个类,和JDK动态代理不同的是,Enhancer即能够代理普通的class,也能够代理接口
ENhance创建一个被代理对象的子类并且拦截所有的方法调用(包括从Object中继承的toString和hashCode)Enhancer不能够
拦截final方法。例如Object.getClass()方法,这是由于java的方法语义决定的,基于同样的道理Enhancer也不能对final类
进行代理操作,这也是Hibernate为什么不能持久化final class的原因。
下面我们来分别看看不同的方法,首先是
FIxedValue()
先来看看其例子
public class SampleClass {
public String test(String input){ //被代理对象
return "hello world";
}
public static void main(String[] args) {
//Enhancer : 增强
Enhancer enhancer=new Enhancer(); //创建一个增强因子对象
enhancer.setSuperclass(SampleClass.class); //设置代理类
enhancer.setCallback(new FixedValue() {
@Override
public Object loadObject() throws Exception {
return "Hello cglib";
}
});
SampleClass sampleClass= (SampleClass) enhancer.create();
System.out.println(sampleClass.test(null)); //Hello cglib
System.out.println(sampleClass.toString()); //Hello cglib
System.out.println(sampleClass.getClass()); //class cglib.SampleClass$$EnhancerByCGLIB$$ceb0270f
System.out.println(sampleClass.hashCode()); //Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Number
}
}
从输出中我们可以看到hashCode()抛出了异常,原因在于其期望的是一个int类型的值,而得到的是String类型的值
Enhancer.setSuperclass用来设置父类型,从toString方法中可以看出cglib生成的类为被代理类的一个子类,形如:cglib.SampleClass$$EnhancerByCGLIB$$ceb0270f
Enhancer.createClass() 用来创建字节码,然后用字节码动态的生成增强的对象。(具体用法需要考察)
也可以使用一个 InvocationHandler 作为回调,然后使用invoke来代替直接访问类的方法但是此处必须注意死循环,因为invoke中调用的任何原代理方法,均会重新代理待invoke方法中,如下:
public class SampleClass {
public String test(String input){
return "hello world";
}
public static void main(String[] args) {
Enhancer enhancer=new Enhancer();
enhancer.setSuperclass(SampleClass.class);
enhancer.setCallback(new InvocationHandler() {
@Override
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
System.out.println("before....");
Object result=method.invoke(o, objects);
System.out.println("after....");
return result;
}
});
SampleClass sampleClass= (SampleClass) enhancer.create();
System.out.println(sampleClass.test(null));
}
}
结果如下:
省略至少1000个before....
before....
before....
before....
before....
before....
before....
before....
before....
before....
before....
before....
before....
before....
before....
Exception in thread "main" net.sf.cglib.proxy.UndeclaredThrowableException: java.lang.reflect.InvocationTargetException-->null
at cglib.SampleClass$$EnhancerByCGLIB$$12d2f200.test(<generated>)
at cglib.SampleClass.main(SampleClass.java:32)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:134)
Caused by: java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at cglib.SampleClass$1.invoke(SampleClass.java:25)
... 7 more
Caused by: net.sf.cglib.proxy.UndeclaredThrowableException: java.lang.reflect.InvocationTargetException-->null
at cglib.SampleClass$$EnhancerByCGLIB$$12d2f200.test(<generated>)
... 12 more
Caused by: java.lang.reflect.InvocationTargetException
为了避免死循环,我们可以使用MethodInterceptor
有时我们想针对特定的方法进行拦截,则可以使用CallbackFilter
public class SampleClass {
public String test(String input){
return "hello world";
}
public static void main(String[] args) {
Enhancer enhancer=new Enhancer();
enhancer.setSuperclass(SampleClass.class);
CallbackHelper callbackHelper=new CallbackHelper(SampleClass.class,new Class[0]) {
@Override
protected Object getCallback(Method method) {
if(method.getDeclaringClass()!=Object.class && method.getReturnType()==String.class){
return new MethodInterceptor() {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("befor.....");
Object result=methodProxy.invokeSuper(o,objects);
System.out.println("after.....");
return result;
}
};
}else{
return NoOp.INSTANCE; //NoOp.INSTANCE cglib定义好的不做任何事情的拦截器。
}
}
};
enhancer.setCallbackFilter(callbackHelper);
enhancer.setCallbacks(callbackHelper.getCallbacks());
SampleClass proxy = (SampleClass) enhancer.create();
System.out.println(proxy.test(null));
}
}
上面:首先定义了一个CallbackHelper 该helper返回一个方法拦截器,然后在将CallbackHelper 设置到enhancer中,之后再将CallbackHelper 的回调方法设置到Callbacks中
再来看一下cglib的不可变bean ImmutableBean
首先定义一个简单bean
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;
}
}
写一个测试类
public class SampleClass {
public static void main(String[] args) {
SampleBean bean=new SampleBean();
bean.setValue("hello world");
//immutable : 不可改变的 --> immutableBean 不可修改的bean
SampleBean immutableBean= (SampleBean) ImmutableBean.create(bean);
System.out.println(immutableBean.getValue()); //hello world
bean.setValue("hello world again");
System.out.println(immutableBean.getValue()); //hello world again
immutableBean.setValue("hello cglib"); //Exception in thread "main" java.lang.IllegalStateException: Bean is immutable
/**
* 通过上面的例子可以看出,Cglib的不可变bean,是指代理的对象不能修改被代理bean中的属性值,
* 但是被代理对象可以自行修改属性的值。
*/
}
}
再来看看cglib的生产bean对象 BeanGenerator
例子如下:
public class SampleClass {
public static void main(String[] args)throws Exception{
//Generator : 生产
BeanGenerator beanGenerator=new BeanGenerator();
beanGenerator.addProperty("value",String.class); //给bean追加一个value属性
Object myBean=beanGenerator.create(); //创造该bean
Method setter=myBean.getClass().getMethod("setValue",String.class);
setter.invoke(myBean,"hello cglib");
Method getter=myBean.getClass().getMethod("getValue");
System.out.println(getter.invoke(myBean)); //hello cglib
/**
* 对于cglib生产对象这一块不是很理解
* Method setter=myBean.getClass().getMethod("setValue",String.class)
* 的意思应该是获取噶bean里面的setValue方法,但是在此之前myBean里面并没有setValue这个方法
* 莫非是在设置属性的时候就自动的按照javaBean的规范生成了这些方法吗?
*/
}
}
在来看看cglib的属性复制 BeanCopier 能够将一个bean里面的属性复制到另一个bean中需要保证两个bean具有相同的方法
例子:
public class OtherSampleBean {
private String value1111;
public String getValue() {
return value1111;
}
public void setValue(String value) {
this.value1111 = value;
}
}
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;
}
}
public class SampleClass {
public static void main(String[] args)throws Exception{
//Copier : 复印机
BeanCopier copier=BeanCopier.create(SampleBean.class,OtherSampleBean.class,
false); //设置为true,则使用converter
SampleBean myBean=new SampleBean();
myBean.setValue("hello cglib");
OtherSampleBean otherSampleBean=new OtherSampleBean();
copier.copy(myBean,otherSampleBean,
null);//如果上文设置为true,则传入converter指明进行怎么转换
System.out.println(otherSampleBean.getValue()); //hello cglib
/**
* 上面的例子是将myBean里面的value值复制到了otherSampleBean中
*/
}
}
再来看看 BulkBean
public class SampleClass {
public static void main(String[] args)throws Exception{
/**
* Bulk : 散装
* 相对于BeanCopier而言,BulkBean将copy的动作拆分为
* getPropertyValues和setPropertyValues两个方法,允许自定义处理属性
*
* 使用注意:
* 1. 避免每次进行BulkBean.create创建对象,一般将其声明为static的
* 2. 应用场景:针对特定属性的get,set操作,一般适用通过xml配置注入和注出的属性,
* 运行时才确定处理的Source,Target类,只需要关注属性名即可。
*
* 对于下面的例子,并么有发现有什么应用场景
*/
BulkBean bulkBean=BulkBean.create(SampleBean.class,
new String[]{"getValue"},
new String[]{"setValue"},
new Class[]{String.class});
SampleBean bean=new SampleBean();
bean.setValue("Hello Wolrd");
Object[] propertyValues=bulkBean.getPropertyValues(bean);
System.out.println(propertyValues.length); //1
System.out.println(propertyValues[0]); //Hello Wolrd
bulkBean.setPropertyValues(bean,new Object[]{"Hello cglib"}); //因为设置函数可以需要多个值,因而是一个数组
System.out.println(bean.getValue()); //Hello cglib
}
}
再来看看BeanMap 也就是将javaBean转化为map的方法
public class SampleClass {
public static void main(String[] args)throws Exception{
BeanGenerator generator=new BeanGenerator();
generator.addProperty("username",String.class);
generator.addProperty("password",String.class);
Object bean= generator.create();
Method setUsername=bean.getClass().getMethod("setUsername",String.class);
Method setPassword=bean.getClass().getMethod("setPassword",String.class);
setUsername.invoke(bean,"admin");
setPassword.invoke(bean,"pwd");
//public abstract class BeanMap implements Map 可以看到其实现了Map接口
BeanMap map=BeanMap.create(bean);
System.out.println(map.get("username")); //admin
System.out.println(map.get("password")); //pwd
}
}
再来看看KeyFactory 该类用来动态生成接口的实例,接口只需要包含一个newInstance方法,返回一个Object,KeyFactory为构造出来的实例动态生成Object.equals 和
hashCode(),同时确保相同参数构造出来的实例为单例(必须有一个newInstance方法否则会报错)
public class SampleClass {
interface SampleKeyFactory{
Object newInstance(String first,int second);
}
public static void main(String[] args)throws Exception{
SampleKeyFactory keyFactory= (SampleKeyFactory) KeyFactory.create(SampleKeyFactory.class);
Object key1=keyFactory.newInstance("foo",42);
Object key2=keyFactory.newInstance("foo",42);
System.out.println(key1.equals(key2)); //ture
}
}
再来看看Mixin Minix能够让我们将多个对象整合到一个对象中去,前提是这些对象必须是接口的实现。
public class MinixInterface {
interface Interface1{
String first();
}
interface Interface2{
String second();
}
class Class1 implements Interface1{
@Override
public String first() {
return "first";
}
}
class Class2 implements Interface2{
@Override
public String second() {
return "second";
}
}
interface MixinInterface extends Interface1,Interface2{
}
@Test
public void testMixin() throws Exception{
Mixin mixin=Mixin.create(new Class[]{Interface1.class,Interface2.class,MixinInterface.class},new Object[]{new Class1(),new Class2()});
MixinInterface mixinDelegate= (MixinInterface) mixin;
System.out.println(mixinDelegate.first()); //first
System.out.println(mixinDelegate.second()); //second
}
}
再来看看 String switcher :用来模拟一个String到int类型的Map类型如果在Java7以后的版本中,类似一个switch语句
public class MinixInterface {
@Test
public void testStringSwitch() throws Exception{
String[] strings=new String[]{"one","two"};
int[] values=new int[]{10,20};
StringSwitcher stringSwitcher=StringSwitcher.create(strings,values,true);
System.out.println(stringSwitcher.intValue("one"));//10
System.out.println(stringSwitcher.intValue("two"));//20
}
}
再来看看Interface Maker :正如其名字一样 是用来创建接口的
@Test
public void testInterfaceMarker() throws Exception{
Signature signature=new Signature("foo", Type.DOUBLE_TYPE,new Type[]{Type.INT_TYPE});
InterfaceMaker interfaceMaker=new InterfaceMaker();
interfaceMaker.add(signature,new Type[0]);
Class iface=interfaceMaker.create();
System.out.println(iface.getMethods().length); //1
System.out.println(iface.getMethods()[0].getName()); //foo
System.out.println(iface.getMethods()[0].getReturnType()); //double
}
再来看看 Method delegate:其主要用来对方法进行代理
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;
}
}
public class MinixInterface {
interface BeanDelegate{
String getValueFromDelegate();
}
@Test
public void testMethodDelegate() throws Exception{
SampleBean bean=new SampleBean();
bean.setValue("hello cglib");
/**
* 关于Method.create的参数说明:
* 1. 第二个参数为即将被代理的方法
* 2. 第一个参数必须是一个无参数构造的bean。因此MethodDelegate.create并不是你想象的那么有用
* 3. 第三个参数为只含有一个方法的接口。当这个接口中的方法被调用的时候,将会调用第一个参数所指向bean的第二个参数方法
* 缺点:
* 1. 为每一个代理类创建了一个新的类,这样可能会占用大量的永久代堆内存
* 2. 你不能代理需要参数的方法
* 3. 如果你定义的接口中的方法需要参数,那么代理将不会工作,并且也不会抛出异常;如果你的接口中方法需要其他的返回类型,那么将抛出IllegalArgumentException
*/
BeanDelegate delegate= (BeanDelegate) MethodDelegate.create(bean,"getValue",BeanDelegate.class);
System.out.println(delegate.getValueFromDelegate()); //hello cglib
}
}
再来看看多重代理 MulticastDelegate
1. 多重代理和方法代理差不多,都是将代理类方法的调用委托给被代理类。使用前提是需要一个接口,以及一个类实现了该接口
2. 通过这种interface的继承关系,我们能够将接口上方法的调用分散给各个实现类上面去。
3. 多重代理的缺点是接口只能含有一个方法,如果被代理的方法拥有返回值,那么调用代理类的返回值为最后一个添加的被代理类的方法返回值
public interface DelegatationProvider {
void setValue(String value);
}
public class MinixInterface {
class SimpleMulticastBean implements DelegatationProvider{
private String value;
@Override
public void setValue(String value) {
this.value=value;
}
public String getValue(){
return value;
}
}
@Test
public void testMulticastDelegate() throws Exception{
MulticastDelegate multicastDelegate = MulticastDelegate.create(DelegatationProvider.class);
SimpleMulticastBean first = new SimpleMulticastBean(); //实现接口对象1
SimpleMulticastBean second = new SimpleMulticastBean(); //实现接口对象2
multicastDelegate = multicastDelegate.add(first); //加入到多重代理
multicastDelegate = multicastDelegate.add(second); //加入到多重代理
DelegatationProvider provider = (DelegatationProvider) multicastDelegate; //代理转化为接口
provider.setValue("Hello world"); //代理中修改值
System.out.println(first.getValue()); //Hello world //被代理对象的值都被修改
System.out.println(second.getValue()); //Hello world
}
}
再连看看对构造函数的代理Constructor delegate
为了对构造函数进行代理,我们需要一个接口,这个接口只含有一个Object newInstance(…)方法,用来调用相应的构造函数
public interface SampleBeanConstructorDelegate {
Object newInstance(String value);
}
被代理类
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;
}
}
测试类
public class MinixInterface {
@Test
public void testConstructorDelegate() throws Exception{
SampleBeanConstructorDelegate constructorDelegate= (SampleBeanConstructorDelegate)
ConstructorDelegate.create(SampleBean.class, SampleBeanConstructorDelegate.class);
SampleBean bean= (SampleBean) constructorDelegate.newInstance("Hello world");
System.out.println(bean.getClass()); //class cglib.SampleBean
System.out.println(bean.getValue()); //Hello world
}
}
最后再来看看fastClass : 作用对Class对象进行特定的处理,比如通过数组保存Method引用,因此FastClass
引出了一个index下标的新概览,比如getIndex(String name,Class[] parameterTypes)就是以前获取method的方法
通过数组存储method constructor等class信息从而将原先的反射调用,转化为class.index的直接调用,从而体现FastClass
测试对象
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;
}
}
测试类
public class MinixInterface {
@Test
public void testFastClass() throws Exception{
FastClass fastClass=FastClass.create(SampleBean.class); //通过SampleBean的Class创建fastClass
FastMethod fastMethod=fastClass.getMethod("getValue",new Class[0]); //由于getValue不需要参数因而传入长度为0的数组对象
SampleBean bean =new SampleBean(); //创建SampleBean对象
bean.setValue("hello world"); //设置对象的值
System.out.println(fastMethod.invoke(bean,new Object[0])); //hello world //调用该对象的getValue方法
}
}
注:以上文章参考的是一篇博客的内容,由于是很早之前找到的,然后复制到了自己的笔记本上,尝试了好久都没有找到原文,十分感谢源博主的分享。