cglib介绍
CGLIB包的底层是通过使用一个小而快的字节码处理框架ASM,来转换字节码并生成新的类。除了CGLIB包,脚本语言例如Groovy和BeanShell,也是使用ASM来生成java的字节码。JDK动态代理只能代理实现了接口有类,而cglib没有这个限制。
cglib代理原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理。
使用方法:
public interface PersonBean { String getName(); void setName(String name); } //没有实现PersonBean接口 public class PersonBean2 { private String name; public String getName() { // TODO Auto-generated method stub return this.name; } public void setName(String name) { // TODO Auto-generated method stub this.name = name; } }
public class ProxyByCGLIB implements MethodInterceptor{ private Enhancer enhancer = new Enhancer(); /** * 获得代理 * @param clazz 目标对象类 * @return 代理对象 */ public Object getProxy(Class clazz) { enhancer.setSuperclass(clazz); //设置需要创建子类的类 enhancer.setCallback(this); return enhancer.create(); //通过字节码技术动态创建子类实例 } @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { // TODO Auto-generated method stub System.out.println("dynamic invoke begin..."); Object result= proxy.invokeSuper(obj, args); // 通过代理类调用父类中的方法 System.out.println("before dynamic end..."); return result; } } public class ProxyByCGLIBTest { /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub ProxyByCGLIB proxyByCGLIB = new ProxyByCGLIB(); PersonBeanImpl proxy = (PersonBeanImpl) proxyByCGLIB.getProxy(PersonBeanImpl.class); proxy.setName("aaa"); System.out.println(proxy.getName()); } }
cglib源码
1、通过AbstractClassGenerator类的create()生成代理类字节码,并加载到JVM中,类似JDK动态代理生成过程
protected Object create(Object key) { try { Class gen = null; synchronized (source) { ClassLoader loader = getClassLoader(); Map cache2 = null; cache2 = (Map)source.cache.get(loader); if (cache2 == null) { cache2 = new HashMap(); cache2.put(NAME_KEY, new HashSet()); source.cache.put(loader, cache2); } else if (useCache) { Reference ref = (Reference)cache2.get(key); gen = (Class) (( ref == null ) ? null : ref.get()); } if (gen == null) { Object save = CURRENT.get(); CURRENT.set(this); try { this.key = key; if (attemptLoad) { try { gen = loader.loadClass(getClassName()); } catch (ClassNotFoundException e) { // ignore } } if (gen == null) {
//生成字节码,并加载到JVM byte[] b = strategy.generate(this); String className = ClassNameReader.getClassName(new ClassReader(b)); getClassNameCache(loader).add(className); gen = ReflectUtils.defineClass(className, b, loader); } if (useCache) { cache2.put(key, new WeakReference(gen)); } return firstInstance(gen); } finally { CURRENT.set(save); } } } return firstInstance(gen); } catch (RuntimeException e) { throw e; } catch (Error e) { throw e; } catch (Exception e) { throw new CodeGenerationException(e); } }