JDK1.3之后,Java提供了动态代理的技术,允许开发者在运行期间创建接口的代理实例。

一、首先我们进行JDK动态代理的演示。

现在我们有一个简单的业务接口Saying,如下:

package testAOP;
public interface Saying {
public void sayHello(String name);    
public void talking(String name);
}

一个简单的实现类SayingImpl,如下:

package testAOP;
public class SayingImpl implements Saying {
@Override
public void sayHello(String name) {
// TODO Auto-generated method stub
System.out.println(name + ":大家好啊!");
}
@Override
public void talking(String name) {
// TODO Auto-generated method stub
System.out.println(name + ":我的意思是,我们要努力建设和谐社会!");
}
}

我们要实现的是,在sayHello和talking之前和之后分别动态植入处理。

JDK动态代理主要用到java.lang.reflect包中的两个类:Proxy和InvocationHandler.

InvocationHandler是一个接口,通过实现该接口定义横切逻辑,并通过反射机制调用目标类的代码,动态的将横切逻辑和业务逻辑编织在一起。

Proxy利用InvocationHandler动态创建一个符合某一接口的实例,生成目标类的代理对象。

如下,我们创建一个InvocationHandler实例:

package testAOP;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method; public class MyInvocationHandler implements InvocationHandler { private Object target;
MyInvocationHandler(Object target){
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
//目标方法前执行
System.out.println("——————————————————————————");
System.out.println("下一位请登台发言!");
//目标方法调用
Object obj = method.invoke(target, args);
//目标方法后执行
System.out.println("大家掌声鼓励!");
return obj;
}
}

下面是测试:

package testAOP;

import java.lang.reflect.Proxy;

public class JDKProxyTest {

    public static void main(String[] args) {
// 希望被代理的目标业务类
Saying target = new SayingImpl();
// 将目标类和横切类编织在一起
MyInvocationHandler handler = new MyInvocationHandler(target);
// 创建代理实例
Saying proxy = (Saying) Proxy.newProxyInstance(
target.getClass().getClassLoader(),//目标类的类加载器
target.getClass().getInterfaces(),//目标类的接口
handler);//横切类
proxy.sayHello("小明");
proxy.talking("小丽");
}
}

运行情况如下:

——————————————————————————
下一位请登台发言!
小明:大家好啊!
大家掌声鼓励!
——————————————————————————
下一位请登台发言!
小丽:我的意思是,我们要努力建设和谐社会!
大家掌声鼓励!

使用JDK动态代理有一个很大的限制,就是它要求目标类必须实现了对应方法的接口,它只能为接口创建代理实例。我们在上文测试类中的Proxy的newProxyInstance方法中可以看到,该方法第二个参数便是目标类的接口。如果该类没有实现接口,这就要靠cglib动态代理了。

CGLib采用非常底层的字节码技术,可以为一个类创建一个子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,并顺势植入横切逻辑。

二、接下来我们进行cglib动态代理的演示。

首先我们需要导包,我用的包是cglib-nodep-2.1_3.jar。

我们首先创建一个代理创建器CglibProxy:

package testAOP.cglib;

import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy; public class CglibProxy implements MethodInterceptor{ Enhancer enhancer = new Enhancer();
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("——————————————————————————");
System.out.println("下一位请登台发言!");
//目标方法调用
Object result = proxy.invokeSuper(obj, args);
//目标方法后执行
System.out.println("大家掌声鼓励!");
return result;
}
}

然后进行测试:

package testAOP.cglib;

import testAOP.Saying;
import testAOP.SayingImpl; public class CglibProxyTest { public static void main(String[] args) {
CglibProxy proxy = new CglibProxy();
//通过动态生成子类的方式创建代理类
Saying target = (Saying) proxy.getProxy(SayingImpl.class);
target.sayHello("小明");
target.talking("小丽");
}
}

结果与JDK动态代理没有任何区别。

CGLib动态代理能代理类和接口,但是不能代理final类,也是有一定局限性。

JDK动态代理和CGLib动态代理都是运行时增强,通过将横切代码植入代理类的方式增强。与此不同的是AspectJ,它能够在通过特殊的编译器在编译时期将横切代码植入增强,这样的增强处理在运行时候更有优势,因为JDK动态代理和CGLib动态代理每次运行都需要增强。

JDK动态代理和CGLib动态代理简单演示的更多相关文章

  1. java的静态代理、jdk动态代理和cglib动态代理

    Java的代理就是客户端不再直接和委托类打交道,而是通过一个中间层来访问,这个中间层就是代理.使用代理有两个好处,一是可以隐藏委托类的实现:二是可以实现客户与委托类之间的解耦,在不修改委托类代码的情况 ...

  2. jdk动态代理和cglib动态代理底层实现原理详细解析(cglib动态代理篇)

    代理模式是一种很常见的模式,本文主要分析cglib动态代理的过程 1. 举例 使用cglib代理需要引入两个包,maven的话包引入如下 <!-- https://mvnrepository.c ...

  3. 代理模式之静态代理,JDK动态代理和cglib动态代理

    代理模式,顾名思义,就是通过代理去完成某些功能.比如,你需要购买火车票,不想跑那么远到火车站售票窗口买,可以去附近的火车票代售点买,或者到携程等第三方网站买.这个时候,我们就把火车站叫做目标对象或者委 ...

  4. 基于JDK动态代理和CGLIB动态代理的实现Spring注解管理事务(@Trasactional)到底有什么区别。

    基于JDK动态代理和CGLIB动态代理的实现Spring注解管理事务(@Trasactional)到底有什么区别. 我还是喜欢基于Schema风格的Spring事务管理,但也有很多人在用基于@Tras ...

  5. Spring -- <tx:annotation-driven>注解基于JDK动态代理和CGLIB动态代理的实现Spring注解管理事务(@Trasactional)的区别。

    借鉴:http://jinnianshilongnian.iteye.com/blog/1508018 基于JDK动态代理和CGLIB动态代理的实现Spring注解管理事务(@Trasactional ...

  6. Spring <tx:annotation-driven>注解 JDK动态代理和CGLIB动态代理 区别。

    基于JDK动态代理和CGLIB动态代理的实现Spring注解管理事务(@Trasactional)到底有什么区别. 我还是喜欢基于Schema风格的Spring事务管理,但也有很多人在用基于@Tras ...

  7. jdk动态代理和cglib动态代理的区别

    一.原理区别: java动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理. 而cglib动态代理是利用asm开源包,对代理对象类的class文件 ...

  8. jdk 动态代理和 cglib 动态代理

    原理区别: java动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理. 而cglib动态代理是利用asm开源包,对代理对象类的class文件加载 ...

  9. 动态代理:jdk动态代理和cglib动态代理

    /** * 动态代理类:先参考代理模式随笔,了解代理模式的概念,分为jdk动态代理和cglib,jdk动态代理是通过实现接口的方式创建代理类的,cglib是通过继承类的方式实现的代理类的 * jdk动 ...

随机推荐

  1. 软件光栅化渲染器Augustus计划

    在看完Real-Time Rendering后,我决定动手实现一个软件的光栅化渲染器.我就称它为Augustus计划吧. 计划使用MFC和GDI+来做它的UI.可以访问GitHub来查看它的源代码.

  2. Mac OS X 删除文件快捷键

    今天发现自己还不知道怎么快捷的删除文件,网上找了下相关的资料. 原来删除文件的快捷键是:command+delete(把文件放到废纸篓),对于我这种笔记本用户,确实方便很多哈 还有一个命令也挺有用的: ...

  3. Java开发第一步:JDK 7 安装及配置

    JDK 7 安装及配置1. 打开网页http://www.oracle.com 下载对应平台的合适 JDK. 2. 双击下载的 exe,如 jdk-7u7-windows-i586.exe.3. 进入 ...

  4. 利用PHPMailer 来完成PHP的邮件发送

    翻起之前的代码看了一下,还是发表到这里,以后容易查找. 以下的两个文件在这里下载 http://download.csdn.net/detail/u013085496/9673828 也可以直接上gi ...

  5. 组内Linq培训记录

    注: 由于该培训是在组内分享,先写成了Word,而word中的代码都以截图方式呈现了,而在博客园不能很方便的粘贴截图进来,所以我用插入代码的方式加进来,如果文中说“如下图”或“如下图代码”,那么就直接 ...

  6. 使用Gradle构建构建一个Java Web工程及持续集成环境Jenkins配置

    安装Eclipse插件——Buildship 什么是Buildship? Buildship能方便我们通过Eclipse IDE创建和导入Gradle工程,同时还能执行Gradle任务. Eclips ...

  7. C语言基本类型之long long int

    大家都知道int在linux系统下默认是占4个字节,数值表示范围是:-2147483648~2147483647.即使是无符号unsigned int类型表示范围:0-4294967295,大约42亿 ...

  8. Seafile内部云盘

    软件列表 软件 版本 备注 centos 6.4 x86_64 64位系统 mysql mysql5.5.49 本机使用 python 2.7 seafile 依赖python pip 8.1.2 安 ...

  9. docker-5 docker仓库

    docker部署环境:CentOS release 6.5 (Final) Docker配置文件:/etc/sysconfig/docker  重要参数解释: -H 表示Docker Daemon绑定 ...

  10. 将u盘的文件复制到虚拟机上的linux系统上面—》文件挂载(文字+图解)

    虚拟机中操作系统.CentOs(无图形界面) 没有图形界面的linux,我也没有配置网络,现在需要把文件复制到linux系统上面,我这里就使用了u盘挂载的方式,获得了U盘中的文件. 1.VMware中 ...