`
finux
  • 浏览: 200278 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

cglib学习

    博客分类:
  • Java
阅读更多

工作读框架的代码时常遇到cglib的东东,初看会有点摸不着头脑,打断点debug才发觉得cglib很强大。

回到家把源码下下来,呵呵,还带有sample code,下载地址见cglib sourceforge

下面是sample code:

1. Bean.java

 

package samples;

import java.beans.*;
/**
 *
 * @author  baliuka
 */
public abstract class Bean implements java.io.Serializable{
	
    String sampleProperty;
    
  abstract public void addPropertyChangeListener(PropertyChangeListener listener); 
   
  abstract public void removePropertyChangeListener(PropertyChangeListener listener);
   
   public String getSampleProperty(){
      return sampleProperty;
   }
   
   public void setSampleProperty(String value){
      this.sampleProperty = value;
   }
   
   public String toString(){
     return "sampleProperty is " + sampleProperty;
   }
    
}
 

2. Beans.java

 

package samples;

import java.beans.*;
import java.lang.reflect.*;
import net.sf.cglib.proxy.*;

/**
 *
 * @author  baliuka
 */
public class Beans implements MethodInterceptor {
    
    private PropertyChangeSupport propertySupport;
   
    public void addPropertyChangeListener(PropertyChangeListener listener) {
        
        propertySupport.addPropertyChangeListener(listener);
        
    }
    
    public void removePropertyChangeListener(PropertyChangeListener listener) {
        propertySupport.removePropertyChangeListener(listener);
    }
    
    public static  Object newInstance( Class clazz ){
        try{
            Beans interceptor = new Beans();
            Enhancer e = new Enhancer();
            e.setSuperclass(clazz);
            e.setCallback(interceptor);
            Object bean = e.create();
            interceptor.propertySupport = new PropertyChangeSupport( bean );
            return bean;
        }catch( Throwable e ){
            e.printStackTrace();
            throw new Error(e.getMessage());
        }
        
    }
    
    static final Class C[] = new Class[0];
    static final Object emptyArgs [] = new Object[0];


    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        Object retValFromSuper = null;
        try {
            if (!Modifier.isAbstract(method.getModifiers())) {
                retValFromSuper = proxy.invokeSuper(obj, args);
            }
        } finally {
            String name = method.getName();
            if( name.equals("addPropertyChangeListener")) {
                addPropertyChangeListener((PropertyChangeListener)args[0]);
            }else if ( name.equals( "removePropertyChangeListener" ) ){
                removePropertyChangeListener((PropertyChangeListener)args[0]);
            }
            if( name.startsWith("set") &&
                args.length == 1 &&
                method.getReturnType() == Void.TYPE ){
            
                char propName[] = name.substring("set".length()).toCharArray();
            
                propName[0] = Character.toLowerCase( propName[0] );
                propertySupport.firePropertyChange( new String( propName ) , null , args[0]);
            
            }
        }
        return retValFromSuper;
    }
    
    public static void main( String args[] ){
        
        Bean  bean =  (Bean)newInstance( Bean.class );
        
        bean.addPropertyChangeListener(
        new PropertyChangeListener(){
            public void propertyChange(PropertyChangeEvent evt){
                System.out.println(evt);
            }
        }
        );
        
        bean.setSampleProperty("TEST");
        
        
    }
}
 

javac然后java下,执行结果如下:

 

java.beans.PropertyChangeEvent[source=sampleProperty is TEST]

 

没想到能够正确跑起来呀,可是samples.Bean明明不是abstract么?呵呵。。。挺有意思,看来cglib会自己帮你实现一些方法。

 

使用cglib很大一点不就是希望能够对方法进行截拦么,可是目前samples.Bean是使用默认的构造器,那么就不能避免其他的同学直接new samples.Bean(),这样的话,还是达不到截拦的效果。ok,于是乎我把samples.Bean的构建器显示的声明为private,仅仅对samples.Bean.java做如下调整:

 

public abstract class Bean implements java.io.Serializable{
	
	private Bean() { }
	
	/**
	 * ... ...
	 */
}

经过这么一调整,再次javac,发现没啥问题,接着进行javac samples.Beans,哦哦发现报错罗:

 

java.lang.IllegalArgumentException: No visible constructors in class samples.Bean
	at net.sf.cglib.proxy.Enhancer.filterConstructors(Enhancer.java:531)
	at net.sf.cglib.proxy.Enhancer.generateClass(Enhancer.java:448)
	at net.sf.cglib.core.DefaultGeneratorStrategy.generate(DefaultGeneratorStrategy.java:25)
	at net.sf.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:216)
	at net.sf.cglib.proxy.Enhancer.createHelper(Enhancer.java:377)
	at net.sf.cglib.proxy.Enhancer.create(Enhancer.java:285)
	at samples.Beans.newInstance(Beans.java:33)
	at samples.Beans.main(Beans.java:76)
Exception in thread "main" java.lang.Error: No visible constructors in class samples.Bean
	at samples.Beans.newInstance(Beans.java:38)
	at samples.Beans.main(Beans.java:76)

嘻嘻。。。看到了么,No visible constructors in class samples.Bean... 看来构建器不能声明为private呀,samples.Bean的构建器应该至少让samples.Beans可见吧。

 

好的,难道一定需要参数为空的默认构建器么,再修改下看看:

 

public abstract class Bean implements java.io.Serializable{
	
	public Bean(Object arg) { }
	
	/**
	 * ...
	 */
}

这把再执行下,又出现Error罗,呵呵...

 

java.lang.IllegalArgumentException: Superclass has no null constructors but no arguments were given
	at net.sf.cglib.proxy.Enhancer.emitConstructors(Enhancer.java:721)
	at net.sf.cglib.proxy.Enhancer.generateClass(Enhancer.java:499)
	at net.sf.cglib.core.DefaultGeneratorStrategy.generate(DefaultGeneratorStrategy.java:25)
	at net.sf.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:216)
	at net.sf.cglib.proxy.Enhancer.createHelper(Enhancer.java:377)
	at net.sf.cglib.proxy.Enhancer.create(Enhancer.java:285)
	at samples.Beans.newInstance(Beans.java:33)
	at samples.Beans.main(Beans.java:76)
Exception in thread "main" java.lang.Error: Superclass has no null constructors but no arguments were given
	at samples.Beans.newInstance(Beans.java:38)
	at samples.Beans.main(Beans.java:76)

看来必须得给一个参数为空的默认构建器才行呀~

 

初次学习cglib,总结下下:

1. 对于被代理的类可以声明为abstract,cglib会帮你实现abstract方法,这个看起来很智能呀,呵呵。。。后续再看个究竟;

2. 对于被代理的类,必须要给出一个参数为空的构建器(即默认的constractor);

3. 该默认的constractor建议不要声明为private,毕竟,按照刚刚的方式来操作是会抛Error的哦;

 

对于第3点,把samples.Beans放在samples.Bean里面作为一个内部类,不知会是啥情况呀,呵呵。。。有点晚了,明儿再试试看~睡觉去罗

 

 

 

 

 

 

 

 

 

0
1
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics