`
liwanchun_xd
  • 浏览: 120758 次
  • 来自: ...
文章分类
社区版块
存档分类
最新评论

JDK动态代理与开源CGlib实现动态代理

阅读更多
大家都清楚Spring的AOP方面工作是很优秀,但是其内在的基础的东西,还是有一大部分不太了解的,其AOP大量用了ThreadLocal,这一个在前面已做了介绍了,还有一个比较重要的怎样用动态代理组装成AOP.

说到动态代理,有两种情况,第一种是有接口的情况下,你可以选择为jdk自带的动态代理的方式来编写程序,但你想要为一个实在的类编写动态代理的方式的话,这时候就必须选择一些开源的lib包啦.spring和hibernate选择了同样的CGlib包,具体表现在:Hibernate主要是利用cglib生成pojo的子类并override get方法来实现lazy loading机制,Spring则是利用cglib来实现动态代理。

接下来我们就来看看动态代理这两个情况是怎样实现的吧.其实通过demo是比较容易理解一样东西的.所以打算写一个简单的例子来表达我的意思,大家都知道JavaEye社区可以发新帖子,可以修改自己的帖子,所以我们定义下面的一个接口.
Java代码
package lighter.<SPAN class=hilite1>java</SPAN>eye.com;  
 
public interface <SPAN class=hilite1>Java</SPAN>EyeForum {  
    void postTopic(int topicId);  
 
    void editTopic(int topicId);  


package lighter.iteye.com;

public interface JavaEyeForum {
void postTopic(int topicId);

void editTopic(int topicId);
}

当然,有接口啦,我们自然而然的为它写一个实现的类,作为演示并没有实质性的代码的:
Java代码
package lighter.<SPAN class=hilite1>java</SPAN>eye.com;  
 
public class <SPAN class=hilite1>Java</SPAN>EyeForumImpl implements <SPAN class=hilite1>Java</SPAN>EyeForum {  
    public void postTopic(int topicId) {  
        System.out.println("发布帖子,帖子的ID号为:"+topicId);  
    }  
    public void editTopic(int topicId) {  
        System.out.println("编辑帖子,帖子的ID号为:"+topicId);  
    }  


package lighter.iteye.com;

public class JavaEyeForumImpl implements JavaEyeForum {
public void postTopic(int topicId) {
System.out.println("发布帖子,帖子的ID号为:"+topicId);
}
public void editTopic(int topicId) {
System.out.println("编辑帖子,帖子的ID号为:"+topicId);
}
}
因为一般情况下,你发布帖子和编辑要处在事务范围之内(假设的),所以我们新写下面的一个功能类TransactionManager,想让在postTopic和editTopic方法前后分别调用下面的beginTransaction和endTransaction方法.
Java代码
package lighter.<SPAN class=hilite1>java</SPAN>eye.com;  
 
public class TransactionManager {  
    public static void beginTransaction(String methodName){  
        System.out.println(methodName + "开始事务管理!");  
    }     
    public static void endTransaction(String methodName){  
        System.out.println(methodName + "事务管理结束!\n");  
    }  


package lighter.iteye.com;

public class TransactionManager {
public static void beginTransaction(String methodName){
System.out.println(methodName + "开始事务管理!");
}
public static void endTransaction(String methodName){
System.out.println(methodName + "事务管理结束!\n");
}
}

剩下的问题就是,我们用方式把TransactionManager里面的两个方法织入到JavaEyeForumImpl类里面方法的合适的位置,很简单地,我们只需要写一个处理的Handler类,如下:
Java代码
package lighter.<SPAN class=hilite1>java</SPAN>eye.com;  
 
import <SPAN class=hilite1>java</SPAN>.lang.reflect.InvocationHandler;  
import <SPAN class=hilite1>java</SPAN>.lang.reflect.Method;  
 
public class TransactionHandler implements InvocationHandler {  
    private Object target;  
    public TransactionHandler(Object target) {  
        this.target = target;  
    }  
    public Object invoke(Object proxy, Method method, Object[] args)throws Throwable {  
        TransactionManager.beginTransaction(method.getName());  
        Object obj = method.invoke(target, args);  
        TransactionManager.endTransaction(method.getName());  
        return obj;  
    }  


package lighter.iteye.com;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class TransactionHandler implements InvocationHandler {
private Object target;
public TransactionHandler(Object target) {
this.target = target;
}
public Object invoke(Object proxy, Method method, Object[] args)throws Throwable {
TransactionManager.beginTransaction(method.getName());
Object obj = method.invoke(target, args);
TransactionManager.endTransaction(method.getName());
return obj;
}
}
在上面的类中的invoke方法中,"Object obj = method.invoke(target, args);"前后的语句指定调用前该前做,调用后该做什么.
接下来,就是写一个测试类啦
Java代码
package lighter.<SPAN class=hilite1>java</SPAN>eye.com;  
 
import <SPAN class=hilite1>java</SPAN>.lang.reflect.Proxy;  
public class TestDynamicProxy {  
    public static void main(String[] args) {  
        <SPAN class=hilite1>Java</SPAN>EyeForum target = new <SPAN class=hilite1>Java</SPAN>EyeForumImpl();  
        TransactionHandler handler = new TransactionHandler(target);  
        <SPAN class=hilite1>Java</SPAN>EyeForum proxy = (<SPAN class=hilite1>Java</SPAN>EyeForum) Proxy.newProxyInstance(target  
                .getClass().getClassLoader(),target.getClass().getInterfaces(), handler);  
        proxy.postTopic(100);  
        proxy.editTopic(999);  
    }  


package lighter.iteye.com;

import java.lang.reflect.Proxy;
public class TestDynamicProxy {
public static void main(String[] args) {
JavaEyeForum target = new JavaEyeForumImpl();
TransactionHandler handler = new TransactionHandler(target);
JavaEyeForum proxy = (JavaEyeForum) Proxy.newProxyInstance(target
.getClass().getClassLoader(),target.getClass().getInterfaces(), handler);
proxy.postTopic(100);
proxy.editTopic(999);
}
}
测试类,请仔细看 Proxy.newProxyInstance这一个方法的第二个参数必须指定target.getClass().getInterfaces()这一个接口后,动态代理才能起效. 这是为什么说平时我们说jdk 中的动态代理有时候比较麻烦,那是还要指定特定的接口的原因.
测试代码运行结果如下:

引用
postTopic 开始事务管理!
发布帖子,帖子的ID号为:100
postTopic事务管理结束!

editTopic 开始事务管理!
编辑帖子,帖子的ID号为:999
editTopic事务管理结束!


接下来我们来看看怎样用CGLib来生成动态代理,首先把TestDynamicProxy.java和TransactionHandler.java两个类删除掉,免得影响视线嘛,呵呵;然后再新建一个CglibProxy代理类.
Java代码
package lighter.<SPAN class=hilite1>java</SPAN>eye.com;  
 
import <SPAN class=hilite1>java</SPAN>.lang.reflect.Method;  
import net.sf.<SPAN class=hilite4>cglib</SPAN>.proxy.Enhancer;  
import net.sf.<SPAN class=hilite4>cglib</SPAN>.proxy.MethodInterceptor;  
import net.sf.<SPAN class=hilite4>cglib</SPAN>.proxy.MethodProxy;  
/** 
* net.sf.<SPAN class=hilite4>cglib</SPAN>.proxy.Enhancer和MethodInterceptor在<SPAN class=hilite4>CGLib</SPAN>中负责完成代理对象创建和方法截获处理, 
* 产生的是目标类的子类而不是通过接口来实现方法拦截的,Enhancer主要是用于构造<SPAN class=hilite2>动态代理</SPAN>子类来实现拦截,MethodInterceptor(扩展了 
* Callback接口)主要用于实现around advice(AOP中的概念) 
*/ 
public class <SPAN class=hilite4>Cglib</SPAN>Proxy implements MethodInterceptor {  
    private Enhancer enhancer = new Enhancer();  
    public Object getProxy(Class clazz) {  
        enhancer.setSuperclass(clazz);  
        enhancer.setCallback(this);  
        return enhancer.create();  
    }  
    public Object intercept(Object obj, Method method, Object[] args,MethodProxy proxy) throws Throwable {  
        String methodName = obj.getClass().getName()+"."+method.getName();  
        TransactionManager.beginTransaction(methodName);  
        Object result = proxy.invokeSuper(obj, args);  
        TransactionManager.endTransaction(methodName);  
        return result;  
    }  


package lighter.iteye.com;

import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
/**
* net.sf.cglib.proxy.Enhancer和MethodInterceptor在CGLib中负责完成代理对象创建和方法截获处理,
* 产生的是目标类的子类而不是通过接口来实现方法拦截的,Enhancer主要是用于构造动态代理子类来实现拦截,MethodInterceptor(扩展了
* Callback接口)主要用于实现around advice(AOP中的概念)
*/
public class CglibProxy implements MethodInterceptor {
private Enhancer enhancer = new Enhancer();
public Object getProxy(Class clazz) {
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
return enhancer.create();
}
public Object intercept(Object obj, Method method, Object[] args,MethodProxy proxy) throws Throwable {
String methodName = obj.getClass().getName()+"."+method.getName();
TransactionManager.beginTransaction(methodName);
Object result = proxy.invokeSuper(obj, args);
TransactionManager.endTransaction(methodName);
return result;
}
}

然后,我们再写一个测试类如下:
Java代码
package lighter.<SPAN class=hilite1>java</SPAN>eye.com;  
 
public class Test<SPAN class=hilite4>CGLib</SPAN>Proxy {  
    public static void main(String[] args) {  
        <SPAN class=hilite4>Cglib</SPAN>Proxy proxy = new <SPAN class=hilite4>Cglib</SPAN>Proxy();  
        <SPAN class=hilite1>Java</SPAN>EyeForum forum = (<SPAN class=hilite1>Java</SPAN>EyeForum)proxy.getProxy(<SPAN class=hilite1>Java</SPAN>EyeForumImpl.class);  
        forum.postTopic(999);  
        forum.editTopic(999);  
    }  


package lighter.iteye.com;

public class TestCGLibProxy {
public static void main(String[] args) {
CglibProxy proxy = new CglibProxy();
JavaEyeForum forum = (JavaEyeForum)proxy.getProxy(JavaEyeForumImpl.class);
forum.postTopic(999);
forum.editTopic(999);
}
}
测试的结果如下:

引用
lighter.iteye.com.JavaEyeForumImpl$$EnhancerByCGLIB$$155ad1e9.postTopic 开始事务管理!
发布帖子,帖子的ID号为:999
lighter.iteye.com.JavaEyeForumImpl$$EnhancerByCGLIB$$155ad1e9.postTopic事务管理结束!

lighter.iteye.com.JavaEyeForumImpl$$EnhancerByCGLIB$$155ad1e9.editTopic 开始事务管理!
编辑帖子,帖子的ID号为:999
lighter.iteye.com.JavaEyeForumImpl$$EnhancerByCGLIB$$155ad1e9.editTopic事务管理结束!

分享到:
评论

相关推荐

    基于java的企业级应用开发:JDK动态代理.ppt

    CGLIB代理 通过前面的学习可知,JDK的动态代理用起来非常简单,但它是有局限性的,使用动态代理的对象必须实现一个或多个接口。 那么,如何代理没有实现接口的类? CGLIB代理 CGLIB(Code Generation Library)是一...

    java6string源码-dynamic-proxy:利用ASM、CGLIB、ByteBuddy、Javassist和JDKDynamicP

    接下来,让我们看一些实现动态代理的例子。 1.2 创建调用者 首先,让我们定义一个接口。 public interface EchoService { String echo(String message); } 通过使用运行时代码生成技术,您可以在不定义Class的情况下...

    JAVA动态编译

    Java的动态编译知识,真真在实际开发中并不是经常遇到。...对掌握jdk的动态代理模式,还有比如CGLIB,Spring 的AOP的原理就很有帮助。这样我们在学习其他一些开源框架的时候就能够知其然也知其所以然。

    javasnmp源码-java_review:复习资料

    JDK动态代理和cgLib动态代理 ​ ​ ​ sprin创建bean过程 ​ ​ SpringMVC常用注解 ​ springMVC处理请求流程/工作流程 ​ ​ SpringMVC @RequestParam,@PathParam,@PathVariable等注解区别 ​ ...

    javanetty源码-java:jdk、guava、netty等源码阅读

    java netty 源码 项目由一下几个部分组成: ...java.lang.reflect,java动态代理,cglib代理,静态代理,三种代理模式; java集合类; java.util.concurrent; 3.netty: io基础,bio,nio,aio; netty服务端客户端demo;

    specs2-core_2.11-3.8.5-20161004203431-50e99f0.zip

    kryo-serializers.zip,额外的kryo(http://kryo.googlecode.com)标准jdk类型(例如currency、jdk代理)和一些外部lib(例如joda time、cglib代理、wicket)的序列化程序。更多kryo序列化程序

    SSH 框架所需JAR包

    6.cglib-nodep-2.1_3.jar(支持cglib动态代理的包) 如果用BasicDataSource来配置数据库连接,还要加入2个包: 7.commons-pool.jar 8.commons-dbcp.jar Hibernate需要的jar包: 1.hibernate3.jar(hibernate的核心jar...

    SSH 项目 整合jar包

    6.cglib-nodep-2.1_3.jar(支持cglib动态代理的包) 如果用BasicDataSource来配置数据库连接,还要加入2个包: 7.commons-pool.jar 8.commons-dbcp.jar 三、Hibernate需要的jar包: 1.hibernate3.jar(hibernate的...

    web项目常用jar包及说明.zip

    6.cglib-nodep-2.1_3.jar(支持cglib动态代理的包) 如果用BasicDataSource来配置数据库连接,还要加入2个包: 7.commons-pool.jar 8.commons-dbcp.jar Hibernate需要的jar包: 1.hibernate3.jar(hibernate的核心...

    Spring.3.x企业应用开发实战(完整版).part2

    6.2.3 CGLib动态代理 6.2.4 AOP联盟 6.2.5 代理知识小结 6.3 创建增强类 6.3.1 增强类型 6.3.2 前置增强 6.3.3 后置增强 6.3.4 环绕增强 6.3.5 异常抛出增强 6.3.6 引介增强 6.4 创建切面 6.4.1 切点类型 6.4.2 切面...

    Spring3.x企业应用开发实战(完整版) part1

    6.2.3 CGLib动态代理 6.2.4 AOP联盟 6.2.5 代理知识小结 6.3 创建增强类 6.3.1 增强类型 6.3.2 前置增强 6.3.3 后置增强 6.3.4 环绕增强 6.3.5 异常抛出增强 6.3.6 引介增强 6.4 创建切面 6.4.1 切点类型 6.4.2 切面...

    java开发常用jar包

    代码生成工具 Hibernate用它在运行时扩展 Java类和实现,同cglib包 slf4j-api-1.5.8.jar和slf4j-log4j12-1.5.0.jar hibernate使用的一个日志系统 spring.jar spring核心包 spring-security-core-2.0.4.jar 和 ...

Global site tag (gtag.js) - Google Analytics