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. PAT甲级——1098 Insertion or Heap Sort (插入排序、堆排序)

    本文同步发布在CSDN:https://blog.csdn.net/weixin_44385565/article/details/90941941 1098 Insertion or Heap So ...

  2. 理解js继承的6种方式

    想要继承,就必须要提供个父类(继承谁,提供继承的属性) 一.原型链继承 重点:让新实例的原型等于父类的实例. 特点:1.实例可继承的属性有:实例的构造函数的属性,父类构造函数属性,父类原型的属性.(新 ...

  3. [Leetcode]007. Reverse Integer

    public class Solution { public int reverse(int x) { long rev=0; while(x!=0){ rev = rev*10+x%10; x=x/ ...

  4. 11-散列3 QQ帐户的申请与登陆 (25 分)

    实现QQ新帐户申请和老帐户登陆的简化版功能.最大挑战是:据说现在的QQ号码已经有10位数了. 输入格式: 输入首先给出一个正整数N(≤),随后给出N行指令.每行指令的格式为:“命令符(空格)QQ号码( ...

  5. 使用open live writer客户端写博客(亲测有效)

    博客都开了这么久了,才开始将资料上传,但是每次都要登录网页确实很麻烦,所以就用open live writer,使用起来真的是挺方便的,所以将我在安装配置时,发现的问题汇总起来以便日后再次碰到忘记怎么 ...

  6. c#spinLock使用

        版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/u011915028/article/details/53011811 一下解释摘自msdn  ...

  7. PartTime__学习辅助软件_20161025

    1.http://www.680.com/ruanjian/412629.html 1.1.http://www.gysjxjy.com/ 密码:我的名字的拼音(全小写) 使用的身份证信息:http: ...

  8. 剑指Offer——数组中只出现一次的数字(一个很帅的异或解法)

    题目: 一个整型数组里除了两个数字之外,其他的数字都出现了两次.请写程序找出这两个只出现一次的数字. 看题目脑子里就出现做法了: 遍历,用个HashMap来记录出现的次数,然后再遍历HashMap返回 ...

  9. 在myecplise中更新代码发布后没效果

    requestmapping指定路径不能访问: 重新发布,重新访问,清除缓存,重新访问,重启浏览器,清除缓存,重新访问,清除Tomcat相关目录,重新发布,重新访问……折腾了很久,可还是没有解决问题. ...

  10. 【Java密码学】使用Bouncy Castle生成数字签名、数字信封

    Bouncy Castle(轻量级密码术包)是一种用于 Java 平台的开放源码的轻量级密码术包,它支持大量的密码术算法,并提供 JCE 1.2.1 的实现.最近项目上正好用到了Bouncy Cast ...