1. jdk静态代理

  jdk静态代理主要使用硬编码实现.他通过对在代理类中持有委托类的引用,来打到在委托类方法执行前和执行后进行处理,实现简单,容易理解.

  代码如下:

  1.业务逻辑接口

 package jdkStaticProxy;

 public interface Service {

     public void doService();

 }

  2.业务逻辑实现类

 package jdkStaticProxy;

 public class ServiceImpl implements Service {

     @Override
public void doService() {
System.out.println("this is doService method");
}
}

  3.代理类

 package jdkStaticProxy;

 public class ServiceProxy implements Service {

     private Service service;

     public ServiceProxy(Service service) {
this.service = service;
} @Override
public void doService() {
System.out.println("there is before method");//前置处理方法
service.doService();//业务逻辑方法
System.out.println("there is after method");//后置处理方法
}
}

  在代理类中持有一个委托类的应用,以达到在代理类中进行相关处理.

  4.测试类

 package jdkStaticProxy;

 public class Main {

     public static void main(String[] args) {
Service service=new ServiceImpl();
Service serviceProxy=new ServiceProxy(service);
serviceProxy.doService();
} }

  以上就是jdk静态代理,很容易理解,但是他的问题也显而易见----dk静态代理因为是硬编码实现,所以可能会存在大量的重复代码.加入我们的service有10个方法,那么我们的代理类中就必须有10个对应的代理方法,这样的工作量是非常大.

2. jdk动态代理

  jdk动态代理主要使用反射实现.要使用jdk代理必须实现一个接口,原因是jdk代理是用代理类替换委托类进行方法调用,为了让代理能够完成替换,就必须实现一个接口,这样jdk就能生成对应的代理类.代理类的生成主要通过一个Proxy工厂生成,代理类的方法通过调用一个InvocationHandler接口的invoke方法执行.

  代码如下:

  1.业务逻辑接口

    同静态代理

  2.业务逻辑实现类

    同静态代理

  3.InvocationHandler

 package jdkDynamicProxy;

 import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method; public class MyInvocationHandler implements InvocationHandler { private Object target; public MyInvocationHandler(Object target) {
this.target = target;
} @Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("there is before method"); method.invoke(target,args); System.out.println("there is after method"); return null;
} }

    从代码里面可以看出来,代理类持有委托类的引用.委托类的方法是通过反射来进行调用的.method是委托类的方法.

  4.测试类

package jdkDynamicProxy;

import java.lang.reflect.Proxy;

public class Main {

    public static void main(String[] args) {
ServiceImpl service=new ServiceImpl();
MyInvocationHandler myInvocationHandler=new MyInvocationHandler(service); Service service1= (Service) Proxy.newProxyInstance(
service.getClass().getClassLoader(),//委托类的类加载器
service.getClass().getInterfaces(),//委托类的接口
myInvocationHandler);//InvocationHandler service1.doService(); System.out.println("实际类型:"+service1.getClass());
} }

  Proxy是一个工厂类,调用newProxyInstance生成一个代理类,传入委托类加载器和委托类的接口是为了创建一个能够替换委托类的代理类(为什么需要这两个参数请了解JVM如何判断两个类相等),InvocationHandler为代理类的逻辑方法.代码中的service1实际类型是com.sun.proxy.$Proxy0.代理类的创建是通过反射创建,有兴趣的读者可以研究Proxy的源码,也可以看这里

3. cglib动态代理

  cglib是一个开源库,他不需要委托类实现一个接口,他是通过创建一个继承委托类的代理类,来进行强化方法,代理类的实现方法通过调用MethodInterceptor的intercept方法.创建代理类主要借助asm这个java字节码生成框架.

  代码如下:

  1.业务逻辑类

    同静态代理

  2.intercept

 package cglibProxy;

 import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy; import java.lang.reflect.Method; public class MyInterceptor implements MethodInterceptor { @Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("-----before");
methodProxy.invokeSuper(o,objects);//调用父类(业务逻辑)方法
System.out.println("-----after");
return null;
} }

  其中method是委托类的方法,methodProxy是代理类的代理方法.

  3.测试方法

 package cglibProxy;

 import net.sf.cglib.proxy.Enhancer;

 public class Main {

     public static void main(String[] args) {

         Enhancer enhancer=new Enhancer();//该类是cglib的字节码生成器,能够直接生成对应代理类的字节码
enhancer.setSuperclass(Service.class);//继承委托类(final类不可被继承)
enhancer.setCallback(new MyInterceptor());//设置回调
Service service= (Service) enhancer.create();//生成代理对象 service.doService();
System.out.println("实际类型:"+service.getClass()); }
}

    代理类对象是由Enhancer类创建的。Enhancer是CGLIB的字节码增强器,可以很方便的对类进行拓展.通过设置回调方法和委托类,生成对应代理类的字节码,然后将代理类加载进来,生成代理对象.

    创建代理类的步骤如下:

      1.生成代理类的二进制字节码文件

      2.加载二进制字节码,生成Class对象( 例如使用Class.forName()方法 )

      3.通过反射机制获得实例构造,并创建代理类对象

    cglib原理请看这里

4. 各代理对比

  1.jdk静态代理:实现简单易懂,但是由于是硬编码实现,所以可能会出现大量重复代码.

  2.jdk动态代理:通过反射机制创建代理类以及代理类方法调用,他在创建代理类的效率上会比cglib高,但是在调用方法的效率上比cglib低.

  3.cglib动态代理:通过生成字节码的方式创建代理类,他在创建代理类的效率上由于要生成字节码以及加载类所以比jdk代理低,但是方法执行效率上由于是直接执行,不需要进行反射所以效率比jdk代理高.

jdk代理与cglib代理的更多相关文章

  1. 总结两种动态代理jdk代理和cglib代理

    动态代理 上篇文章讲了什么是代理模式,为什么用代理模式,从静态代理过渡到动态代理. 这里再简单总结一下 什么是代理模式,给某个对象提供一个代理对象,并由代理对象控制对于原对象的访问,即客户不直接操控原 ...

  2. spring的AOP动态代理--JDK代理和CGLIB代理区分以及注意事项

    大家都知道AOP使用了代理模式,本文主要介绍两个代理模式怎么设置以及区别,对原文一些内容进行了引用后加入了自己的理解和更深入的阐述:   一.JDK代理和CGLIB代理的底层实现区别* JDK代理只能 ...

  3. 关于JDK动态代理与Cglib代理

    关于JDK动态代理与Cglib代理 最近有时间学习一下SpringAOP源码,底层用到了代理,大概是这样的: 当需要被代理的类实现了接口,则使用JDK动态代理创建代理对象,增加增强操作执行目标方法 当 ...

  4. Java中jdk代理和cglib代理

    代理模式 给某一个对象提供一个代理,并由代理对象控制对原对象的引用.在一些情况下,一个客户不想或者不能够直接引用一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用. 在Java中代理模式从实 ...

  5. java代理,静态代理、jdk代理、cglib代理、Aspectj

    我实在接触spring的时候才接触到代理这个东西的,一直想整理一下笔记. 什么是代理模式:代理模式是通过代理对象访问目标对象,这样可以在目标对象基础上增强额外的功能.简单来说就是要创建一个新的对象,我 ...

  6. java代理(静态代理和jdk动态代理以及cglib代理)

    版权声明:本文为Fighter168原创文章,未经允许不得转载.   目录(?)[+]   说到代理,脑袋中浮现一大堆代理相关的名词,代理模式,静态代理,jdk代理,cglib代理等等. 记忆特别深刻 ...

  7. (转)Java动态代理与CGLib代理

    <br>public class UserDAOImpl{ <br><br>    public void save() { <br>        / ...

  8. IT忍者神龟之Java动态代理与CGLib代理

    <br>public class UserDAOImpl{ <br><br>    public void save() { <br>        / ...

  9. jdk代理和cglib代理

    1.jdk静态代理(静态代理和动态代理) 本质:在内存中构建出接口的实现类. 缺陷:只能对实现接口的类实现动态代理, 使用cglib可以对没有实现接口的类进行动态代理. 2.cglib动态代理     ...

  10. jdk动态代理与cglib代理、spring aop代理实现原理

    原创声明:本博客来源与本人另一博客[http://blog.csdn.net/liaohaojian/article/details/63683317]原创作品,绝非他处摘取 代理(proxy)的定义 ...

随机推荐

  1. 算法习题---4-8特别困的学生(UVa12108)

    一:题目 课堂上有n个学生(n<=),每个学生上课都会出现一个“清醒-睡眠”周期,其中第i个学生学习Ai分钟后睡眠Bi分钟,依次重复.其中在从清醒到睡眠时有一个条件:只有到全班睡眠人数大于清醒人 ...

  2. Python subprocess中的run方法

    调用subprocess的推荐方法是对于它可以处理的所有使用场景都使用run()函数. run()函数是在Python 3.5中添加的,如果在老版本中使用,需要下载并扩展. 扩展安装方式: $ pip ...

  3. Java进阶教程:使用Lombok提升开发效率

    Java进阶教程:使用Lombok提升开发效率 Lombok Lombok是一种Java™实用工具,可用来帮助开发人员消除Java的冗长代码,尤其是对于简单的Java对象(POJO).它通过注释实现这 ...

  4. 将linux的root用户的家目录由/root切换为/home/root

    步骤1,先以root登录,然后创建目录/home/root步骤2,vi /etc/passwd里root用户的家目录为/home/root:步骤3,cp -rf /root/ /home/将原来的ro ...

  5. 030 Android 第三方开源下拉框:NiceSpinner的使用+自定义Button样式+shape绘制控件背景图+图片选择器(selector)

    1.NiceSpinner下拉框控件介绍 Android原生的下拉框Spinner基本上可以满足Android开发对于下拉选项的设计需求,但现在越来越流行的下拉框不满足于Android原生提供的下拉框 ...

  6. [转帖]ARM发布Ethos-N57/N73 NPU、Mali-G57 Valhall GPU和Mali-D37 DPU

    ARM发布Ethos-N57/N73 NPU.Mali-G57 Valhall GPU和Mali-D37 DPU https://www.cnbeta.com/articles/tech/902417 ...

  7. Hystrix【参数配置及缓存】

    1.常用参数说明 hystrix参数的详细配置可参照 https://github.com/Netflix/Hystrix/wiki/Configuration 下面是一些常用的配置: 配置项 默认值 ...

  8. C之推栈溢出原因

    https://blog.csdn.net/weixin_36194037/article/details/78871468

  9. PAT(B) 1043 输出PATest(Java)统计

    题目链接:1043 输出PATest (20 point(s)) 题目描述 给定一个长度不超过 10​4​​ 的.仅由英文字母构成的字符串.请将字符重新调整顺序,按 PATestPATest- 这样的 ...

  10. 题解-APIO2019路灯

    problem \(\mathtt {loj-3146}\) 题意概要:一条直线上有 \(n+1\) 个点和 \(n\) 条道路,每条道路连通相邻两个点.在 \(q\) 个时刻内,每个时刻有如下两种操 ...