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. Spring中好玩的注解和接口

    测试中: 一.unit中集中基本注解,是必须掌握的. @BeforeClass – 表示在类中的任意public static void方法执行之前执行 @AfterClass – 表示在类中的任意p ...

  2. Spring cloud微服务安全实战-5-8实现基于session的SSO(认证服务器的session有效期)

    认证服务器 session的有效期. 也就是认证服务器上的session的有效期 生成环境下,认证服务器一定是一个集群.集群.那么session一定是要在所有的服务器之间进行共享的.最简单的方式是用S ...

  3. centos7上安装mysql8(上)

    1.删除系统现存的mysql rpm -pa | grep mysql 2.卸载mysql组件 yum remove mysql-xxx-xxx- 3.删除mysql的配置文件,卸载不会自动删除配置文 ...

  4. conda使用报错:ImportError:DLL load failed

    conda安装python环境经常报: ImportError:DLL load failed 将环境变量加入path可以解决: D:\program\anaconda D:\program\anac ...

  5. docker进入容器内部执行命令

    [root@bogon ~]# docker ps -l CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 38a2cae4c32f jenk ...

  6. JS的slice、substring、substr字符串截取

    JS中截取一个字符串的三种方法:字符串.slice(开始索引,结束索引)字符串.substring(开始索引,结束索引)字符串.substr(开始索引,截取的长度) 如果需要截取到该字符串的最后,可以 ...

  7. 【sql server inject】使用动态查询执行sql语句实例

    应某少年要求授权测试一个存在报错注入点的站点,可读取数据库名,但是sqlmap执行–os-shell选项就会莫名当掉: 分步骤测试了几次,发现xp_cmdshell是开启状态,但用sqlmap注入却无 ...

  8. bootstrap-table和bootstrap-switch

    {% load staticfiles %} <!DOCTYPE html> <html lang="en"> <head> <meta ...

  9. Linux终极shell-zsh的完美配置方案!——oh-my-zsh

    Zsh 介绍 Zsh 兼容 Bash,据传说 99% 的 Bash 操作 和 Zsh 是相同的 Zsh 官网:http://www.zsh.org/ 先看下你的 Linux支持哪些 shell:cat ...

  10. 仔细看参数--NGINX之tcp_nodelay

    一.知识准备 ● 在nginx优化中有个经常需要设置的参数,tcp_nodelay ● 该参数最核心的功能,就是把小包组成成大包,提高带宽利用率也就是著名的nagle算法 ● tcp协议中,有一个现象 ...