静态代理与动态代理

静态代理

  • 代理模式

    (1)代理模式是常用设计模式的一种,我们在软件设计时常用的代理一般是指静态代理,也就是在代码中显式指定的代理。

(2)静态代理由 业务实现类、业务代理类 两部分组成。业务实现类 负责实现主要的业务方法,业务代理类负责对调用的业务方法作拦截、过滤、预处理,主要是在方法中首先进行预处理动作,然后调用业务实现类的方法

  • 例子

        /**
     * 定义一个账户接口
     * @author Administrator
     */
    public interface Count {
        // 查询账户
        public void queryCount();  

        // 修改账户
        public void updateCount();  

    }
    /**
 * 委托类(包含业务逻辑)
 *
 * @author Administrator
 *
 */
public class CountImpl implements Count {  

    @Override
    public void queryCount() {
        System.out.println("查看账户...");  

    }  

    @Override
    public void updateCount() {
        System.out.println("修改账户...");  

    }
}
    public class CountProxy implements Count {
    private CountImpl countImpl;  //组合一个业务实现类对象来进行真正的业务方法的调用

    /**
     * 覆盖默认构造器
     *
     * @param countImpl
     */
    public CountProxy(CountImpl countImpl) {
        this.countImpl = countImpl;
    }  

    @Override
    public void queryCount() {
        System.out.println("查询账户的预处理——————");
        // 调用真正的查询账户方法
        countImpl.queryCount();
        System.out.println("查询账户之后————————");
    }  

    @Override
    public void updateCount() {
        System.out.println("修改账户之前的预处理——————");
        // 调用真正的修改账户操作
        countImpl.updateCount();
        System.out.println("修改账户之后——————————");
    }
}
  • 静态代理

    静态代理的缺点很明显:一个代理类只能对一个业务接口的实现类进行包装,如果有多个业务接口的话就要定义很多实现类和代理类才行。而且,如果代理类对业务方法的预处理、调用后操作都是一样的(比如:调用前输出提示、调用后自动关闭连接),则多个代理类就会有很多重复代码。这时我们可以定义这样一个代理类,它能代理所有实现类的方法调用:根据传进来的业务实现类和方法名进行具体调用。——那就是动态代理。


动态代理

  • JDK动态代理

    JDK动态代理设计到java.lang.relect包中的两个类:Proxy和InvocationHandler,InvocationHandler可以通过实现该接口定义横切逻辑,并通过反射机制调用目标类的代码,动态将横切逻辑与业务逻辑编织到一起。Proxy利用InvocationHandler动态创建某一符合该接口的实例,生成目标类的代理对象。

    public class Monitor {

    public static void begin(){
        System.out.println("before");
    }

    public static void end(){
        System.out.println("after");
    }
}
    public interface CouponService {

    void getCoupon();
}
    public class CouponServiceImpl implements CouponService {

    public void getCoupon() {

        //Monitor.begin();
        try {
            System.out.println("业务代码");
        } catch (Exception e) {
            throw new RuntimeException();
        }
        //Monitor.end();
    }
}
    public class PerformanceHandler implements InvocationHandler {

    //被代理对象
    private Object target;

    public PerformanceHandler(Object target) {
        this.target = target;
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        Monitor.begin();
        Object object = method.invoke(target, args);
        Monitor.end();
        return object;
    }
}
    public class Client {

    public static void main(String[] args) {

        //被代理对象
        CouponService target = new CouponServiceImpl();

        //让PerformanceHandler将监视横切逻辑编织到CouponService中
        PerformanceHandler performanceHandler = new PerformanceHandler(target);

        //通过Proxy的newProxyInstace()方法,为编织了业务逻辑与监控逻辑的handler创建一个符合CouponService接口的代理实现
        CouponService proxy = (CouponService) Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),performanceHandler);

        proxy.getCoupon();
    }
}
  • Cglib 实现动态代理
    JDK创建代理只能为接口创建代理,实际开发中我们很难保证每个类都有其对应的接口,对于没有通过接口定义业务方法的类,JDK已经没法对其进行代理,这就出现了Cglib,通过字节码技术,为一个类创建子类,在子类中采用方法拦截的技术拦截所有父类方法的调用并织入横切逻辑。
    public class CglibProxy implements MethodInterceptor {
    private Enhancer enhancer = new Enhancer();

    public Object getProxy(Class clazz) {
        //设置需要创建子类的类
        enhancer.setSuperclass(clazz);
        enhancer.setCallback(this);
        //通过字节码技术动态创建子类实例
        return enhancer.create();
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("before");
        //通过代理类调用父类中的方法
        Object result = methodProxy.invokeSuper(o, objects);
        System.out.println("after");
        return result;
    }
}
    public class Client {

    public static void main(String[] args) {
        CglibProxy proxy = new CglibProxy();

        //通过冬天生成子类的方式创建代理类
        CouponServiceImpl couponService = (CouponServiceImpl) proxy.getProxy(CouponServiceImpl.class);

        couponService.getCoupon();
    }
}
  • 总结

    Cglib所创建的动态代理,性能要比jdk创建的动态代理高。但对用Cglib创建代理的时间,JDK动态代理显然要快很多。对于无需单例的代理对象或实例池可以使用CGLib来创建代理(无需频繁创建),反之使用JDK动态代理。

Spring AOP JDK动态代理与CGLib动态代理区别的更多相关文章

  1. 【转载】Spring AOP详解 、 JDK动态代理、CGLib动态代理

    Spring AOP详解 . JDK动态代理.CGLib动态代理  原文地址:https://www.cnblogs.com/kukudelaomao/p/5897893.html AOP是Aspec ...

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

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

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

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

  4. Java之代理(jdk静态代理,jdk动态代理,cglib动态代理,aop,aspectj)

    一.概念 代理是什么呢?举个例子,一个公司是卖摄像头的,但公司不直接跟用户打交道,而是通过代理商跟用户打交道.如果:公司接口中有一个卖产品的方法,那么公司需要实现这个方法,而代理商也必须实现这个方法. ...

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

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

  6. 浅谈Spring中JDK动态代理与CGLIB动态代理

    前言Spring是Java程序员基本不可能绕开的一个框架,它的核心思想是IOC(控制反转)和AOP(面向切面编程).在Spring中这两个核心思想都是基于设计模式实现的,IOC思想的实现基于工厂模式, ...

  7. Spring 静态代理+JDK动态代理和CGLIB动态代理

    代理分为两种:静态代理 动态代理 静态代理:本质上会在硬盘上创建一个真正的物理类 动态代理:本质上是在内存中构建出一个类. 如果多个类需要进行方法增强,静态代理则需要创建多个物理类,占用磁盘空间.而动 ...

  8. jdk动态代理与cglib动态代理例子

    1.JAVA的动态代理特征:特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息.过滤消息.把消息转发给委托类,以及事后处理消息等.代理类与委托类之间通常会存在关联关系,一个代理类的对象 ...

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

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

  10. 从静态代理,jdk动态代理到cglib动态代理-一文搞懂代理模式

    从代理模式到动态代理 代理模式是一种理论上非常简单,但是各种地方的实现往往却非常复杂.本文将从代理模式的基本概念出发,探讨代理模式在java领域的应用与实现.读完本文你将get到以下几点: 为什么需要 ...

随机推荐

  1. Skyline WEB端开发2——添加一个定位点、文本标签

    Skyline 添加定位点 sgworld.Creator.CreatePosition CreatePosition( X, //兴趣点的东西方向坐标,即经度 Y, //兴趣点的南北方向坐标,即纬度 ...

  2. MMM 数位dp学习记

    数位dp学习记 by scmmm 开始日期 2019/7/17 前言 状压dp感觉很好理解(本质接近于爆搜但是又有广搜的感觉),综合了dp的高效性(至少比dfs,bfs优),又能解决普通dp难搞定的问 ...

  3. 【原创】一个shell脚本记录(实现rsync生产文件批量迁移功能)

    #!/bin/bash #Date:2018-01-08 #Author:xxxxxx #Function:xxxxxx #Change:2018-01-17 # #设置忽略CTRL+C信号 trap ...

  4. 微信小程序生成随机数

    const charts = ['0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F','G','H','I','J','K', ...

  5. fjnu2016-2017 低程 PROBLEM B 捧杯

    #include <iostream>#include <cmath>using namespace std; int _gcd(int x,int y){ return y= ...

  6. Java学习笔记之---Servlet

    Java学习笔记之---Servlet (一)如何实现Servlet 1.实现javax.servlet.Servlet接口: 2.继承javax.servlet.GenericServlet类: 3 ...

  7. Java中的I/O输入输出流概述

    流是一组有序的数据序列,根据操作类型,可以分为输入流和输出流两种,Java语言中定义的负责各种输入输出的类都被放在java.io包中.其中所有的输入流类都是抽象类InputStream(字节输入流)或 ...

  8. Android App安装包瘦身计划

    Android App安装包瘦身计划 Android App安装包体积优化: 理由, 指标和可以采用的方法. 本文内容归纳如下图: 为什么要安装包瘦身 安装包需要瘦身吗? 不需要吗? 安装包要瘦身的主 ...

  9. mysql协议分析1---报文的格式和基本类型

    navicat 和 mysql 是一对好基友,每天都有非常频繁的交流,主人在navicat上写下每条sql语句,轻轻的点了下执行按钮,navicat就飞快的把主人的指令传送到mysql那里,mysql ...

  10. 剖析std::function接口与实现

    目录 前言 一.std::function的原理与接口 1.1 std::function是函数包装器 1.2 C++注重运行时效率 1.3 用函数指针实现多态 1.4 std::function的接 ...