动态代理应用广泛,Spring,Struts等框架很多功能是通过动态代理,或者进一步封装来实现的。

常见的动态代理模式实现有Java API提供的动态代理和第三方开源类库CGLIB动态代理。

Java API提供的动态代理是基于类反射实现的,用到的类有:

java.lang.reflect.InvocationHandler;

java.lang.reflect.Method;

java.lang.reflect.Proxy;

其实现是通过Proxy类的newProxyInstance()方法产生代理对象。自定义动态代理类需要实现InvocationHandler接口,该接口只有一个invoke()方法。

CGLIB是通过生成java 字节码从而动态的产生代理对象,因此需要字节码解析处理的依赖asm类库,字节码动态生成的代理对象实际上是继承了真实主题类的。这种实现方式需要导入cglib和asm的类库。下面用到的例子是cglib-2.2.2.jar, asm-3.3.1.jar。cglib使用了MethodInterceptor,其中的方法是intercept(),这是拦截的概念,很容易就想到了Struts2的拦截器。

比较之下,Java API提供的动态代理需要面向接口,产生代理对象,因此真实主题实现类必须实现了接口才可以。而CGLIB不需要面向接口,可以代理简单类,但由于动态代理对象是继承真实主题实现类的,因此要求真实主题实现类不能是final的。

下面是实现的例子。

首先,为了看到动态代理可以根据不同类动态产生不同代理的效果,我们新建两个接口,及其实现类。

package leon.aj.dynproxy.target;

public interface Hello {
public String sayHello(String name);
}

实现类:

package leon.aj.dynproxy.target;

public class HelloImpl implements Hello {
@Override
public String sayHello(String name) {
String s = "Hello, "+name;
System.out.println(this.getClass().getName()+"->"+s);
return s;
}
}

另一接口和实现类:

package leon.aj.dynproxy.target;

public interface UserDao {
public boolean login(String username,String password);
}
package leon.aj.dynproxy.target;

public class UserDaoImpl implements UserDao {
@Override
public boolean login(String username, String password) {
String user = "("+username+","+password+")";
System.out.println(this.getClass().getName()+"-> processing login:"+user);
return true;
}
}

应用Java API实现的动态代理类:

package leon.aj.dynproxy.java;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy; public class JavaDynProxy implements InvocationHandler{
private Object target;
public Object getProxyInstance(Object target){
this.target = target;
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(), this);
} @Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object result = null;
System.out.println("before target method...");
result = method.invoke(target, args);
System.out.println("after target method...");
return result;
}
}

测试:

package leon.aj.dynproxy.java;

import leon.aj.dynproxy.target.Hello;
import leon.aj.dynproxy.target.HelloImpl;
import leon.aj.dynproxy.target.UserDao;
import leon.aj.dynproxy.target.UserDaoImpl; public class TestJavaProxy {
public static void main(String[] args) {
JavaDynProxy proxy = new JavaDynProxy();
Hello hello = (Hello)proxy.getProxyInstance(new HelloImpl());
String s = hello.sayHello("Leon");
System.out.println(s); UserDao userDao = (UserDao) proxy.getProxyInstance(new UserDaoImpl());
userDao.login("Leon", "1234");
System.out.println(userDao.getClass().getName());
}
}

下面是采用cglib实现的例子:

package leon.aj.dynproxy.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 {
private Object target; public Object getProxyInstance(Object target) {
this.target = target;
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(this.target.getClass());
enhancer.setCallback(this); // call back method
return enhancer.create(); // create proxy instance
} @Override
public Object intercept(Object target, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("before target method...");
Object result = proxy.invokeSuper(target, args);
System.out.println("after target method...");
return result;
}
}

测试类:

package leon.aj.dynproxy.cglib;

import leon.aj.dynproxy.target.Hello;
import leon.aj.dynproxy.target.HelloImpl;
import leon.aj.dynproxy.target.UserDaoImpl; public class TestCiglib {
public static void main(String[] args) {
CglibProxy proxy = new CglibProxy();
Hello hello = (Hello) proxy.getProxyInstance(new HelloImpl());
System.out.println(hello.sayHello("Leon"));
UserDaoImpl userDao = (UserDaoImpl) proxy.getProxyInstance(new UserDaoImpl());
userDao.login("Leon", "1234");
System.out.println(userDao.getClass().getSuperclass());//看动态代理实例的父类
}
}

java动态代理和cglib动态代理的更多相关文章

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

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

  2. JDK动态代理和CGLib动态代理简单演示

    JDK1.3之后,Java提供了动态代理的技术,允许开发者在运行期间创建接口的代理实例. 一.首先我们进行JDK动态代理的演示. 现在我们有一个简单的业务接口Saying,如下: package te ...

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

随机推荐

  1. Linux字符设备驱动

    一.字符设备基础 字符设备 二.字符设备驱动与用户空间访问该设备的程序三者之间的关系 三.字符设备模型 1.Linux内核中,使用 struct cdev 来描述一个字符设备 动态申请(构造)cdev ...

  2. Vim的设置和使用——编程者

    一.第一个插件:Ctags 当我们看到一个陌生的变量或者函数,我们总想知道它的含义,因此,快速找到它的定义很重要.Ctags插件中的"Ctrl+]"快捷键就可以做到. 二.教你高效 ...

  3. 关于MyEclipse查看底层源码出现source not found的问题(MyEclipse、Eclipse配置JAD)

    一.MyEclipse 第一步:      下载jad.exe文件:jad下载地址 eclipse插件:net.sf.jadclipse_版本号.jar下载地址一 net.sf.jadclipse_版 ...

  4. Python函数对象

    秉承着一切皆对象的理念,我们再次回头来看函数(function).函数也是一个对象,具有属性(可以使用dir()查询).作为对象,它还可以赋值给其它对象名,或者作为参数传递. lambda函数 在展开 ...

  5. C#。3 循环

    循环:可以反复执行某段代码,直到不满足循环条件为止. 一.循环的四要素:初始条件.循环条件.状态改变.循环体. 1.初始条件:循环最开始的状态. 2.循环条件:在什么条件下进行循环,不满足此条件,则循 ...

  6. 一小时搞定DIV+CSS布局-固定页面开度布局

    本文讲解使用DIV+CSS布局最基本的内容,读完本文你讲会使用DIV+CSS进行简单的页面布局. 转载请标明:http://www.kwstu.com/ArticleView/divcss_20139 ...

  7. 让 asp.net mvc 支持 带有+ _ 等特殊字符的路由

    最近配置微信 业务域名 时,需要在服务器的根目录中上传一个文本文件,而这个文本文件需要放这样的目录中: 于在就在 服务器目录中创建了对应的文件夹,并将kuPv.txt上传,但是访问时,却怎么也访问不到 ...

  8. 如何让MyEclispe中英文切换

    我们通过网上的一些汉化办法汉化了我们的MyEclipse,可是我们有时候想切回英文版怎么办? 方法一:我们可以通过修改MyEclipse配置文件的办法来从中文恢复到英文, -Duser.languag ...

  9. CentOS 5.5安装图解教程

    说明:实际生产环境中,CentOS 5.5这个版本相当稳定,而且硬件兼容性也很好,是很多服务器装机者的首选系统,下面介绍CentOS 5.5的具体安装过程   说明:实际生产环境中,CentOS 5. ...

  10. 获取aplicationContext对象,从而获取任何注入的对象

    在Servlet中 方法一: 从ServletContext 取出 Spring容器上下文 ApplicationContext applicationContext = (ApplicationCo ...