1.什么是动态代理?

简单的来说,就是本来让我自己做的事,请给别人来做,这个请的人就是代理对象

那么动态代理就是在程序运行过程中产生这个代理对象,而程序运行中产生的对象就是用反射的来生成一个代理。

举一个例子:

有一个user对象,这个对象有四个方法分别是增,删,改,查。但是外界是不能直接调用这几个方法。你最多能执行查的操作,增、删、改的操作是不能执行的,你必须要加一个权限操作,应该看看你是否有权限执行这个操作。同理,谁操作了这个东西,你需要给我留下记录,免得我不知道是谁做的。所以,我应该在每一个方法的前面加权限校验,在每一个方法的后面加日志记录。

该怎么做呢?

有人说,很简单,直接在user对象的实现类里面去改,在增、删、改查前面加上权限校验,在后面加上日志记录。你能随便改别人的代码吗?你一改,所以用过user对象的地方都要改,这不乱套了吗?

有人说,可以再重新创建一个user对象,在新对象中加上权限校验和日志记录。确实是这样。但是如果我还有一个学生类,还有一个老师类...等等,你每一个都新创建一个对象的话,太麻烦了,而且没有必要,因为对我来说,我只关心对象的增、删、改、查操作,对于权限校验和日志记录我并不关心,这个时候,我们可以找中介来做权限校验和日志记录的事情,这个中介就是动态代理对象!

在java.lang.reflect包下提供一个Proxy类和一个InvocationHandle接口,通过这个类和接口可以实现生成动态代理对象。JDK提供的代理只能针对接口,而cglib则更加强大。

Proxy类的方法创建动态代理对象

Public static Object newProxyInstance(ClassLoader loader, Class<?> interfaces, InvocationHandle h);

最终会调用InvocationHandle的方法invoke

Object invoke(Object proxy, Method method, Object[] args);

2.动态代理的实现

下面用代码实现一下:

创建一个接口,其中有四个方法

/**
* Created by YuKai Fan on 2018/9/25.
*/
public interface UserDao {
public abstract void add();
public abstract void delete();
public abstract void update();
public abstract void find();
}

在创建该接口的实现类

/**
* Created by YuKai Fan on 2018/9/25.
*/
public class UserDaoImpl implements UserDao {
@Override
public void add() {
System.out.println("添加");
} @Override
public void delete() {
System.out.println("删除");
} @Override
public void update() {
System.out.println("修改");
} @Override
public void find() {
System.out.println("查找");
}
}

在创建一个类实现InvocationHandle接口

/**
* 该类实现了InvocationHandle接口
* Created by YuKai Fan on 2018/9/25.
*/
public class MyInvocationHandle implements InvocationHandler {
private Object target; //目标对象 public MyInvocationHandle(Object target) {
this.target = target;
} //重写invoke()方法
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("权限校验");
Object invoke = method.invoke(target, args);
System.out.println("日志记录");
return invoke;//返回的就是代理对象
}
}

创建测试类

/**
* Created by YuKai Fan on 2018/9/25.
*/
public class Test {
public static void main(String[] args) {
UserDao userDao = new UserDaoImpl();
userDao.add();
userDao.delete();
userDao.update();
userDao.find();
System.out.println("----------");
//我们要创建一个动态代理对象,在Proxy类中有一个方法可以创建动态代理对象
//public static Object newProxyInstance(ClassLoader loader, Class<?> interfaces, InvocationHandle h);
//将userDao对象作为一个代理对象
MyInvocationHandle myInvocationHandle = new MyInvocationHandle(userDao);
UserDao proxy = (UserDao) Proxy.newProxyInstance(userDao.getClass().getClassLoader(), userDao.getClass().getInterfaces(), myInvocationHandle);
proxy.find();
proxy.add();
proxy.update();
proxy.delete();
}
}

输出结果为

添加
删除
修改
查找
----------
权限校验
查找
日志记录
权限校验
添加
日志记录
权限校验
修改
日志记录
权限校验
删除
日志记录

以上为JDK动态代理,只能针对接口做代理。我们有更强大的代理cglib。

调用Proxy类中的newProxyInstance(ClassLoader loader,Class[] interfaces,InvocationHandler h)方法可以创建一个动态代理对象,但是这个方法需要3个参数,前两个参数是固定的,但第三个参数比较麻烦,需要我们创建一个类MyInvocationHandler来实现InvocationHandler接口,这个类里面要重写invoke()方法。

JDK动态代理和cglib动态代理有什么区别? JDK动态代理智能对实现了接口的类生成代理对象; cglib可以对任意类生成代理对象,它的原理是对目标对象进行继承代理,如果目标对象被final修饰,那么该类无法被cglib代理。

3.动态代理的应用

Spring框架的一大特点就是AOP,SpringAOP的本质就是动态代理,而且Spring使用的是JDK与CGlib的混合代理。如果被代理的对象实现了接口,就优先使用jdk代理,如果没有实现接口,就是用cglib代理。

AOP(Aspect-OrientedProgramming,面向切面编程),AOP包括切面(Aspect),通知(Advice),连接点(joinpoint),实现方式就是通过目标对象的代理在连接点前后加入通知,完成统一的切面操作。

实现AOP的技术,主要分为两大类:

一是动态代理,利用截取消息的方式。对消息进行装饰,以取代原有对象的执行。

二是静态织入,引入特定的语法创建“方面”,从而是的编译器可以在编译期间织入有关“方面”的代码。

Spring提供了两种方式来生成代理对象:JDKProxy和Cglib,具体使用哪种方式生成由AopProxyFactory根据AdviseSupport对象的配置来决定。

默认的策略是如果目标类是接口,则使用JDK动态代理技术,如果目标对象没有实现接口,则默认会采用CGLIB代理。

如果目标对象实现了接口,可以强制使用CGLIB实现代理(添加CGLIB库,并在Spring配置中加入<aop:aspectj-autoproxy proxy-target-class="true" />)

4.总结

JDK动态代理

1.因为利用JDKProxy生成的代理类实现了接口,所以目标类中所有的方法在代理类中都有。

2.生成的代理类的所有方法都拦截了目标类的所有方法。而拦截器中invoke方法的内容正好就是代理类的各个方法的组成体。

3.利用JDKProxy方法必须有接口的存在

4.invoke方法中的三个参数可以访问目标类的被调用方法的API,别调用方法的参数,被调用方法的返回类型。

cglib动态代理

1.CGlib是一个强大的,高性能,高质量的code生成类库。他可以来运行气扩展Java类与实现Java接口

2.用CGlib生成代理类是目标类的子类

3.用CGlib生成代理类不需要接口

4.用CGlib生成的代理类重写了父类的各个方法

5.拦截器中的intercept方法内容正好就是代理类中的方法体

Spring的两种代理方式

1.若目标对象实现了若干接口,spring使用JDK的java.lang.reflect.Proxy类代理。

优点:因为有接口,所以使系统更加松耦合

缺点:为每个目标类创建接口

2.若目标对象没有实现任何接口,spring使用cglib库生成目标对象的子类。

优点:因为代理类与目标类是继承关系,所以不需要有接口的存在

缺点:因为没有使用接口,所以系统的耦合性没有使用JDK的动态代理好。

Java基础——动态代理的更多相关文章

  1. java基础--动态代理实现与原理详细分析

    关于Java中的动态代理,我们首先需要了解的是一种常用的设计模式--代理模式,而对于代理,根据创建代理类的时间点,又可以分为静态代理和动态代理. 一.代理模式                     ...

  2. java 基础 --- 动态代理和静态代理

    问题  : 代理的应用场景是什么 动态代理的底层原理是什么,为什么只能继承接口 概述 代理模式是设计模式的一种,简单地说就是调用代理类的方法实际就是调用真实类的方法.这种模式在AOP (切面编程)中非 ...

  3. java --- 设计模式 --- 动态代理

    Java设计模式——动态代理 java提供了动态代理的对象,本文主要探究它的实现, 动态代理是AOP(面向切面编程, Aspect Oriented Programming)的基础实现方式, 动态代理 ...

  4. Java:动态代理小记

    Java:动态代理小记 对 Java 中的 动态代理,做一个微不足道的小小小小记 概述 动态代理:当想要给实现了某个接口的类中的方法,加一些额外的处理.比如说加日志,加事务等.可以给这个类创建一个代理 ...

  5. java的动态代理机制详解

    在学习Spring的时候,我们知道Spring主要有两大思想,一个是IoC,另一个就是AOP,对于IoC,依赖注入就不用多说了,而对于Spring的核心AOP来说,我们不但要知道怎么通过AOP来满足的 ...

  6. java中动态代理实现机制

    前言: 代理模式是常用的java设计模式,它的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息.过滤消息.把消息转发给委托类,以及事后处理消息等.代理类与委托类之间通常会存在关联关系 ...

  7. Java特性-动态代理

    代理在开发中无处不在: 我们完成一个接口开发A,接口下有很多个实现类,这些类有些共同要处理的部分,比如每一个类都定义了接口A中的方法getXX(String name).我现在想把每次调用某个实现类的 ...

  8. java的动态代理机制

    前几天看到java的动态代理机制,不知道是啥玩意,然后看了看.死活不知道 invoke(Object proxy, Method m, Object[] args)种的proxy是个什么东西,放在这里 ...

  9. java中动态代理

    一.在java中怎样实现动态代理 1.我们要有一个接口,还要有一个接口的实现类,而这个实现类呢就是我们要代理的对象 接口: package org.dynamicproxy.test; public ...

随机推荐

  1. Educational Codeforces Round 48 (Rated for Div. 2) B 1016B Segment Occurrences (前缀和)

    B. Segment Occurrences time limit per test 2 seconds memory limit per test 256 megabytes input stand ...

  2. POJ1031 Fence

    题目来源:http://poj.org/problem?id=1031 题目大意: 有一个光源位于(0,0)处,一个多边形的围墙.围墙是“全黑”的,不透光也不反射光.距光源r处的光强度为I0=k/r, ...

  3. angularJS处理table中checkbox的选中状态

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  4. Restful 3 -- 序列化组件(GET/PUT/DELETE接口设计)、视图优化组件

    一.序列化组件 基于上篇随笔的表结构,通过序列化组件的ModelSerializer设计如下三个接口: GET 127.0.0.1:8000/books/{id} # 获取一条数据,返回值:{} PU ...

  5. Docker从入门到实战(三)

    Docker从入门到实战(三) 一:安装Docker 1. linux系统脚本安装 Docker基于linux容器技术,面向服务器端,Docker只能安装运行在64位计算机上(社区有对32位的支持), ...

  6. WebP图片格式

    腾讯科技讯 科技博客Gig‍‍‍aOM近日撰文称,谷歌(微博)试图让WebP图片格式取代JPEG等现有图片格式.虽然谷歌无法很快达成所愿,但WebP仍然会对互联网产生重大影响. 文章全文如下: 受够了 ...

  7. C/C++规范学习:

    一 关于浮点数: 1.1浮点数是否等于0判断:因为浮点数都有精度,不能拿浮点数直接和0.0f进行比较,而应该采用以下方法: if (f32Data == 0.0f) // 隐含错误的比较 #defin ...

  8. (转)运维老鸟教你安装centos6.5如何选择安装包

    运维老鸟教你安装centos6.5如何选择安装包 原文:http://blog.51cto.com/oldboy/1564620 近来发现越来越多的运维小伙伴们都有最小化安装系统的洁癖,因此,找老男孩 ...

  9. Hive 基本语法操练(六):Hive 的权限控制

    Hive 的权限控制 Hive从0.10可以通过元数据控制权限.但是Hive的权限控制并不是完全安全的.基本的授权方案的目的是防止用户不小心做了不合适的事情. 为了使用Hive的授权机制,有两个参数必 ...

  10. Storm概念学习系列之Task任务

    不多说,直接上干货! 每一个Spout/Bolt的线程称为一个Task. Task任务 Task是运行Spout或Bolt的单元,每一个Spout/Bolt的线程称为一个Task. 在Storm 0. ...