cglib helloworld

来源:互联网 发布:爱奇艺软件没弹幕 编辑:程序博客网 时间:2024/06/04 19:39

什么是cglib?
cglib is a powerful, high performance and quality Code Generation Library, It is used to extend JAVA classes and implements interfaces at runtime. 
This library is free software, freely reusable for personal or commercial purposes.


谁都用了cglib?
Open source projects use cglib and used by cglib:
"The Byte Code Engineering Library (formerly known as JavaClass) is intended to give users a convenient possibility to analyze, create, and manipulate (binary) Java class files (those ending with .class)." Used by cglib for Class file format manipulation.
" XORM is an extensible object-relational mapping layer for Java applications. It provides interface-based persistence to RDBMSs while allowing developers to focus on the object model, not the physical layer." Uses cglib to generate persistent classes.
" Hibernate is a powerful, ultra-high performance object/relational persistence and query service for Java. Hibernate lets you develop persistent objects following common Java idiom, including association, inheritance, polymorphism, composition and the Java collections framework." Uses cglib to generate proxies for persistent classes.
" The Java Class File Editor allows you to read / modify java .class files, either on disk or while loading classes at runtime. The project grew out of the Generic Delegator, which creates new classes on the fly, allowing you to dynamically implement a group of interfaces by forwarding them to a shim" Both cglib and JCFE provide dynamic proxy implementation
" Voruta reduces JDBC code in application, it makes code more readable and safe, SQL procedures and queries are mapped to JAVA methods using custom javadoc tags and dynamic code generation at runtime. It needs no custom build tools or external files" Uses cglib to generate method implementations.
" Nanning Aspects is a simple yet scaleable aspect-oriented framework for Java."
" Spring is a J2EE application framework based on code published in Expert One-on-One J2EE Design and Development http://www.wrox.com/books/1861007841.htm by Rod Johnson."
" The iBATIS Database Layer takes a different approach to solving the Object Relational mapping problem --it avoids it altogether!"
" ASM is a Java bytecode manipulation framework. It offers similar functionalities as BCEL or SERP, but is much more smaller and faster than these tools."
" Proxool is a Java connection pool."


可以用来做什么?


·CGLIB and JAVA Security:
可以为java的二进制class文件进行访问授权。可以识别代码签名者和代码库URL(JAR或类文件),它可以是本地或从网络上下载。
通过CGLIB生成的类,不存在配置文件和JVM启动时间的差异,所有的生成类通过cglib拥有相同的签名和codebase,可以用在WS或RMI安全管理其中。
默认的安全配置文件在java.policy中。如:
        grant codeBase "file:${user.dir}/jars/cglib.jar"{
            permission java.security.AllPermission; 
         };
        
·CGLIB和Java序列化 :
可以通过代理来拦截序列化相关的writeReplace和readResolve方法,来做一些事情。
(序列化实现readResolve方法的作用 http://blog.csdn.net/partner4java/article/details/7058741)


·Access the generated byte[] array directly:
demo:

  Enhancer e = new Enhancer();      e.setSuperclass(...);    // etc.      e.setStrategy(new DefaultGeneratorStrategy() {         protected byte[] transform(byte[] b) {           // do something with bytes here    }  });  Object obj = e.create();

hook:

  e.setStrategy(new DefaultGeneratorStrategy() {    protected ClassGenerator transform(ClassGenerator cg) {      return new TransformingGenerator(cg,        new AddPropertyTransformer(new String[]{ "foo" },                                   new Class[]{ Integer.TYPE }));    }  });

·Avoiding StackOverflowError:

     Object intercept( Object proxy, Method method,                       MethodProxy fastMethod, Object args[] )throws Throwable{        //ERROR         System.out.println(proxy.toString());        //ERROR         return fastMethod.invoke(proxy,args);          }

·优化代理:
Filter unused methods with CallbackFilter and use light Callback version if possible. It can help to avoid hash lookup on method object if you use per method interceptors too.
     

helloworld

场景:
我们会在下面的场景中逐步添加cglib的helloworld示例。
(CURD的基本操作,并模拟工厂,然后客户端调用)
然后我们会利用实现demo1日志记录,demo2权限拦截(指定拦截规则),demo3懒加载(如果用过hibernate就知道这个常用的方式)

package cglib.partner4java;/** * 被代理的对象 * @author partner4java * */public class TableDAO {public void create(){System.out.println("create() is running!");}public void query(){System.out.println("query() is running!");}public void delete(){System.out.println("delete() is running!");}}package cglib.partner4java;/** * 简单模拟工厂 * @author partner4java * */public class TableDAOFactory {private static TableDAO tableDAO = new TableDAO();public static TableDAO getInstance() {return tableDAO;}}package cglib.partner4java;/** * 客户端调用 *  * @author partner4java *  */public class Client {public static void main(String[] args) {TableDAO dao = TableDAOFactory.getInstance();doMethod(dao);}private static void doMethod(TableDAO dao) {dao.create();dao.query();dao.delete();//后台打印://create() is running!//query() is running!//delete() is running!}}



jdk的动态代理一般如下:

/** * 动态代理对象 * @author partner4java * */  public class LogHandler implements InvocationHandler {        private Object delegate;            public Object bind(Object delegate){          this.delegate = delegate;          return Proxy.newProxyInstance(delegate.getClass().getClassLoader(),                   delegate.getClass().getInterfaces(), this);      }      /**      * 代理对象,这里面还可以改变原有的方法      */      public Object invoke(Object proxy, Method method, Object[] args)              throws Throwable {          Object result = null;          try {              System.out.println("添加日志");              result = method.invoke(delegate, args);          } catch (Exception e) {              e.printStackTrace();          }                    return null;      }    }  

Demo1:简单log记录


第一步:cglib也需要实现一个类似于InvocationHandler的方法封装(implements MethodInterceptor)

package cglib.partner4java;import java.lang.reflect.Method;import net.sf.cglib.proxy.MethodInterceptor;import net.sf.cglib.proxy.MethodProxy;/** * 方法拦截 *  * @author partner4java *  */public class MethodExtend implements MethodInterceptor {private String name;public MethodExtend(String name) {super();this.name = name;}public Object intercept(Object obj, Method method, Object[] args,MethodProxy proxy) throws Throwable {System.out.println("do log " + method.getName());return proxy.invokeSuper(obj, args);}}

第二步:实现类似于Proxy.newProxyInstance,工厂(new Enhancer())

/** * 代理工厂 *  * @author partner4java *  */public class TableProxyDAOFactory {public static TableDAO getAuthInstance(MethodExtend methodExtend) {Enhancer enhancer = new Enhancer();enhancer.setSuperclass(TableDAO.class);enhancer.setCallback(methodExtend);return (TableDAO) enhancer.create();}}

第三步:就可以调用第二步返回的TableDao,和正常的调用没有任何区别

/** * 代理客户端 *  * @author partner4java *  */public class ProxyClient {public static void main(String[] args) {TableDAO dao = TableProxyDAOFactory.getAuthInstance(new MethodExtend("张三"));doMethod(dao);System.out.println("-----");dao = TableProxyDAOFactory.getAuthInstance(new MethodExtend("李四"));doMethod(dao);}private static void doMethod(TableDAO dao) {dao.create();dao.query();dao.delete();}}

后台打印:
do log create
create() is running!
do log query
query() is running!
do log delete
delete() is running!
-----
do log create
create() is running!
do log query
query() is running!
do log delete
delete() is running!


这样我们就做了一个log日志系统




Demo2:我们要做一个权限拦击
第一步:拦截业务实现 implements MethodInterceptor
基本和jdk的动态代理一样,在方法调用的时候可以加一些判断通过反射

public class MethodExtend implements MethodInterceptor {private String name;public MethodExtend(String name) {super();this.name = name;}public Object intercept(Object obj, Method method, Object[] args,MethodProxy proxy) throws Throwable {if (!"张三".equals(name)) {System.out.println(method.getName() + "你没有权限!");return null;}return proxy.invokeSuper(obj, args);}}

第二步:拦截谁(implements CallbackFilter)
我们要知道拦截谁啊,不可能所有的方法都拦截过滤一下,总还是要有规则的

/** * 拦截器(选择要执行setCallbacks里的哪个Callback) *  * @author partner4java *  */public class MethodExtendFilter implements CallbackFilter {public int accept(Method method) {if (!"delete".equalsIgnoreCase(method.getName())) {return 1;}return 0;}}

第三步:修改工厂(new Enhancer())
以前是只是告诉生成器一个MethodInterceptor,现在我们还要告诉他一个CallbackFilter

public class TableProxyDAOFactory {public static TableDAO getAuthInstance(MethodExtend methodExtend) {Enhancer enhancer = new Enhancer();enhancer.setSuperclass(TableDAO.class);// enhancer.setCallback(methodExtend);enhancer.setCallbacks(new Callback[] { methodExtend, NoOp.INSTANCE });enhancer.setCallbackFilter(new MethodExtendFilter());return (TableDAO) enhancer.create();}}

第四步:调用工厂返回

public class ProxyClient {public static void main(String[] args) {TableDAO dao = TableProxyDAOFactory.getAuthInstance(new MethodExtend("张三"));System.out.println("执行者张三");doMethod(dao);System.out.println("-----");dao = TableProxyDAOFactory.getAuthInstance(new MethodExtend("李四"));System.out.println("执行者李四");doMethod(dao);}private static void doMethod(TableDAO dao) {dao.create();dao.query();dao.delete();}}

后台打印:
执行者张三
create() is running!
query() is running!
delete() is running!
-----
执行者李四
create() is running!
query() is running!
delete你没有权限!


也就正如规则:if (!"张三".equals(name)) 里面定义的张三才有权限,然后if (!"delete".equalsIgnoreCase(method.getName())),只拦截了delete方法

demo3:懒加载
第一步:实现一个懒加载生成(implements LazyLoader)

public class MethodLazy implements LazyLoader {private String name;public MethodLazy(String name) {super();this.name = name;}public Object loadObject() throws Exception {System.out.println("loadObject");HelloEntity entity = new HelloEntity();entity.setName(name);return entity;}}

第二步:让Dao返回一个代理

public class TableDAO {public HelloEntity get(String name){System.out.println("get");Enhancer enhancer = new Enhancer();enhancer.setSuperclass(HelloEntity.class);enhancer.setCallback(new MethodLazy(name));return (HelloEntity) enhancer.create();}}

第三步:调用

public class Client2 {public static void main(String[] args) {TableDAO dao = new TableDAO();HelloEntity entity = dao.get("hello world");System.out.println("====have get entity===");System.out.println("get name:" + entity.getName());}}

后台打印:
get
HelloEntity cons
====have get entity===
loadObject
HelloEntity cons
get name:hello world


可以看出,当调用entity的时候,才执行的loadObject(),第一次返回的只是一个“假象”。


MethodInterceptor:
General-purpose Enhancer callback which provides for "around advice".
extends Callback
唯一的接口方法--intercept
All generated proxied methods call this method instead of the original method. 
The original method may either be invoked by normal reflection using the Method object, or by using the MethodProxy (faster).


这个类的基本意思就是供Enhancer回调,当调用类的方法时,不是调用原方法,而是调用intercept。




Enhancer:
翻译上为增强。也就是我们最常用的增强类,你告诉他需要增强什么类,以什么样的方式增强,增强什么方法等。


CallbackFilter:
也不知道咋说,就是accept决定调用Callback数组里的第几个。


原创粉丝点击