文档章节

静态代理与动态代理实现与原理

ifree613
 ifree613
发布于 2016/03/11 15:01
字数 1264
阅读 1022
收藏 6

基础代码准备

接口类:

public interface IUser {
  /**
 * 判断用户的权限
 * @param uid 用户的UID
 * @return
 */
  public boolean isAuthUser(int uid);
}

实现类:

/**
 * 类的实现
 * @author Jason
 *
 */
public class UserImpl implements IUser {
  @Override
  public boolean isAuthUser(int uid) {
    //做一些权限验证的工作
   System.out.println(uid);
    //....
    return false;
 }
}

  • 静态代理

由程序员创建或特定工具自动生成源代码,再对其编译,在程序运行前,代理类的.class文件就已经存在了。

原理:

对普通一个接口与一直实现类在加入一个代理类,用于包装实现类中实现的方法,而业务使用方只需要实例化代理类,并传递需要代理的普通类即可。

优点:

编译时生成代码,性能高

缺点:

  1. 一个代理类只能为一个接口服务,开发中必然会产生过多的代理

  2. 所有的代理操作除了调用的方法不一样之外,其他的操作都一样,则此时肯定是重复代码

代码示例

代理类

/**
 * 通过代理类,实现代理接口,通过构造进行实现的代理,在每个方法里面进行日志捕获
 * <pre>
 * 外部实现权限验证的时候,只需要之所想该方法即可,不需要再去实现UserImpl方法了
 * <pre>
 */
public class UserProxy implements IUser {
  private UserImpl userImpl;
  // 构造的时候直接传入代理实现类
  public UserProxy(UserImpl userImpl) {
    super();
    this.setUserImpl(userImpl);
  }
  @Override
  public boolean isAuthUser(int uid) {
    System.out.println("proxy insert msg:准备权限验证,有必要这里可以发送消息到MQ,做实时登录验证次数预警处理");
    boolean b = userImpl.isAuthUser(uid);
    System.out.println("proxy insert msg:验证完成,做一些清理等工作.....");
    return b;
  }
  // ***********get,set************
  public UserImpl getUserImpl() {
    return userImpl;
  }
  public void setUserImpl(UserImpl userImpl) {
    this.userImpl = userImpl;
  }
}

  public static void main(String[] args) {
    UserProxy userProxy = new UserProxy(new UserImpl());
    userProxy.isAuthUser(5);
  }

  • 动态代理

原理:

动态代理类的字节码在程序运行时由Java反射机制动态生成,无需程序员手工编写它的源代码。

优点

可以通过一个代理类,完成所有代理工作,不需要向静态代理需要一个一个实现接口来代理

缺点

通过反射动态代理方法将消耗系统性能,如果非常多的话,性能比较低

JDK动态代理

原理:JDK的动态代理机制只能代理实现了接口的类,而不能实现接口的类就不能实现JDK的动态代理

代理类:UserJDKProxy 

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

/**
 * JDK动态代理代理类,可以将InvocationHandler接口的子类想象成一个代理的最终操作类 
 * JDK的动态代理依靠接口实现,如果有些类并没有实现接口,则不能使用JDK代理,这个也是缺陷
 * @author Jason
 *
 */
public class UserJDKProxy implements InvocationHandler {

  // 需要代理的类
  private Object target;

  
  
  public UserJDKProxy() {
     super();
  }

  /**
  * 绑定委托对象并返回一个代理类 ClassLoader loader:类加载器 Class<?>[] interfaces:得到全部的接口 InvocationHandler
  * h:得到InvocationHandler接口的子类实例
  * 
  * @param target
  * @return
  */
  public Object initUserJDKProxy(Object target) {
     this.target = target;
     // 可以看出这里的第二个参数是获取接口,那么也就是说我们实现代理,需要类去实现接口,在有的时候,类是没有接口的,所以这里是一个缺陷
     return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
  }

  /**
  * 调用具体的方法
  * 
  * @param proxy
  *           指被代理的对象
  * @param method
  *           要调用的方法
  * @param args
  *           方法调用时所需要的参数
  * @return
  * @throws Throwable
  */
  @Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
     System.out.println("proxy:这里拦截处理一下事情....,如监控参数、插入日志....");
     //传入处理对象和参数
     Object object = method.invoke(target, args);
     System.out.println("proxy:这里做一些收尾工作....");
     return object;
  }

}

测试:

    UserJDKProxy userJDKProxy=new UserJDKProxy();
    IUser iUser=(IUser) userJDKProxy.initUserJDKProxy(new UserImpl());
    iUser.isAuthUser(19);

CGLib动态代理

原理:cglib是针对类来实现代理的,他的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理。

这里需要注意,改包需要引入外部包,提供pom

<dependency>
			<groupId>cglib</groupId>
			<artifactId>cglib</artifactId>
			<version>2.2.2</version>
		</dependency>

代理类:UserCglibProxy 

import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
/**
 * 采用CGLib方式动态代理类
 * @author Jason
 *
 */
public class UserCglibProxy implements MethodInterceptor {
  private Object target;
  public Object getInstance(Object target) {
    this.target = target;
    Enhancer enhancer = new Enhancer();
    enhancer.setSuperclass(target.getClass());
    //回调方法  
    enhancer.setCallback(this);
    //创建代理对象  
    return enhancer.create();
  }
  // 回调方法
  @Override
  public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
    System.out.println("可以做一些监控、预警等工作...");
    Object object = proxy.invokeSuper(obj, args);
    System.out.println("收尾工作....");
    return object;
  }
}

测试

UserCglibProxy userCglibProxy=new UserCglibProxy();
UserImpl userImpl=(UserImpl) userCglibProxy.getInstance(new UserImpl());
userImpl.isAuthUser(50);


其他

动态代理在我们使用的框架Spring中已经运用到,主要是AOP,他主要是动态代理+反射的方式

如Spring通过CGLib来实现了类代理方式,通过Java动态代理来实现接口代理,从而把两种动态代理结合使用


© 著作权归作者所有

ifree613

ifree613

粉丝 29
博文 27
码字总数 44789
作品 0
成都
高级程序员
私信 提问
代理模式

代理模式一般分为两种,即静态代理和动态代理,静态代理限制比较严格,代理类和委托类必须实现相同的接口;而动态代理则更加灵活,除了jdk的动态代理,其他的代理方式,如cglib和javassist则...

high_m
2017/11/15
0
0
Java动态代理与CGLIB

静态代理模式 因为需要对一些函数进行二次处理,或是某些函数不让外界知道时,可以使用代理模式,通过访问第三方,间接访问原函数的方式,达到以上目的,来看一下代理模式的类图: interfac...

Hosee
2016/04/11
960
2
深入理解【代理模式】原理与技术

代理模式的定义:为其他对象提供一种代理以控制对这个对象的访问。 23种常用的面向对象软件的设计模式之一。 代理模式分为静态代理、动态代理。 如何理解代理模式? 思考抽象问题最好的办法就...

像风一样i
2018/08/19
0
0
Java动态代理 深度详解

文章首发于【博客园-陈树义】,点击跳转到原文深入浅出Java动态代理 代理模式是设计模式中非常重要的一种类型,而设计模式又是编程中非常重要的知识点,特别是在业务系统的重构中,更是有举足...

陈树义
2017/11/21
0
0
Spring/Boot/Cloud系列知识(2)——代理模式

代理模式是23种设计模式中的一种,属于一种结构模式。用一句大白话解释这个设计模式:当外部调用者调用A来完成一件事情/一个动作时,并不直接调用A本身,而是调用一个代理者,并再由代理者负...

yinwenjie
2017/09/15
0
0

没有更多内容

加载失败,请刷新页面

加载更多

Spring Cloud Alibaba 实战(二) - 关于Spring Boot你不可不知道的实情

0 相关源码 1 什么是Spring Boot 一个快速开发的脚手架 作用 快速创建独立的、生产级的基于Spring的应用程序 特性 无需部署WAR文件 提供starter简化配置 尽可能自动配置Spring以及第三方库 ...

JavaEdge
今天
7
0
TensorFlow 机器学习秘籍中文第二版(初稿)

TensorFlow 入门 介绍 TensorFlow 如何工作 声明变量和张量 使用占位符和变量 使用矩阵 声明操作符 实现激活函数 使用数据源 其他资源 TensorFlow 的方式 介绍 计算图中的操作 对嵌套操作分层...

ApacheCN_飞龙
今天
7
0
五、Java设计模式之迪米特原则

定义:一个对象应该对其他对象保持最小的了解,又叫最小知道原则 尽量降低类与类之间的耦合 优点:降低类之间的耦合 强调只和朋友交流,不和陌生人说话 朋友:出现在成员变量、方法的输入、输...

东风破2019
昨天
23
0
jvm虚拟机结构

1:jvm可操作数据类型分为原始类型和引用类型,因此存在原始值和引用值被应用在赋值,参数,返回和运算操作中,jvm希望在运行时 明确变量的类型,即编译器编译成class文件需要对变量进行类型...

xpp_ba
昨天
5
0
聊聊nacos Service的processClientBeat

序 本文主要研究一下nacos Service的processClientBeat Service.processClientBeat nacos-1.1.3/naming/src/main/java/com/alibaba/nacos/naming/core/Service.java public class Service ex......

go4it
昨天
6
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部