Java基础——动态代理
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基础——动态代理的更多相关文章
- java基础--动态代理实现与原理详细分析
关于Java中的动态代理,我们首先需要了解的是一种常用的设计模式--代理模式,而对于代理,根据创建代理类的时间点,又可以分为静态代理和动态代理. 一.代理模式 ...
- java 基础 --- 动态代理和静态代理
问题 : 代理的应用场景是什么 动态代理的底层原理是什么,为什么只能继承接口 概述 代理模式是设计模式的一种,简单地说就是调用代理类的方法实际就是调用真实类的方法.这种模式在AOP (切面编程)中非 ...
- java --- 设计模式 --- 动态代理
Java设计模式——动态代理 java提供了动态代理的对象,本文主要探究它的实现, 动态代理是AOP(面向切面编程, Aspect Oriented Programming)的基础实现方式, 动态代理 ...
- Java:动态代理小记
Java:动态代理小记 对 Java 中的 动态代理,做一个微不足道的小小小小记 概述 动态代理:当想要给实现了某个接口的类中的方法,加一些额外的处理.比如说加日志,加事务等.可以给这个类创建一个代理 ...
- java的动态代理机制详解
在学习Spring的时候,我们知道Spring主要有两大思想,一个是IoC,另一个就是AOP,对于IoC,依赖注入就不用多说了,而对于Spring的核心AOP来说,我们不但要知道怎么通过AOP来满足的 ...
- java中动态代理实现机制
前言: 代理模式是常用的java设计模式,它的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息.过滤消息.把消息转发给委托类,以及事后处理消息等.代理类与委托类之间通常会存在关联关系 ...
- Java特性-动态代理
代理在开发中无处不在: 我们完成一个接口开发A,接口下有很多个实现类,这些类有些共同要处理的部分,比如每一个类都定义了接口A中的方法getXX(String name).我现在想把每次调用某个实现类的 ...
- java的动态代理机制
前几天看到java的动态代理机制,不知道是啥玩意,然后看了看.死活不知道 invoke(Object proxy, Method m, Object[] args)种的proxy是个什么东西,放在这里 ...
- java中动态代理
一.在java中怎样实现动态代理 1.我们要有一个接口,还要有一个接口的实现类,而这个实现类呢就是我们要代理的对象 接口: package org.dynamicproxy.test; public ...
随机推荐
- P4135 作诗
传送门 分块 设sum[ i ] [ j ] 存从左边到第 i 块时,数字 j 的出现次数 f [ i ] [ j ] 存从第 i 块,到第 j 块的一整段的答案 那么最后答案就是一段区间中几块整段的 ...
- 024 Swap Nodes in Pairs 交换相邻结点
给定一个链表,对每两个相邻的结点作交换并返回头节点.例如:给定 1->2->3->4,你应该返回 2->1->4->3.你的算法应该只使用额外的常数空间.不要修改列 ...
- 022 Generate Parentheses 生成括号
给 n 对括号,写一个函数生成所有合适的括号组合.比如,给定 n = 3,一个结果为:[ "((()))", "(()())", "(())() ...
- Java面向对象_数据结构之链表
链表:是一种常见的基础数据结构,是一种线性表,但是并不会按线性的顺序存储数据,而是在每一个节点里村到下一个节点的指针. 在链表数据结构中,需要使用到递归算法.递归算法是一种直接或间接地调用自身算法的过 ...
- VMware安装CentOS7的详细过程
原文:https://www.jianshu.com/p/ce08cdbc4ddb?utm_source=tuicool&utm_medium=referral 本篇文章主要介绍了VMware ...
- 用CSS控制图片大小显示的方法
图片自动适应大小是一个非常常用的功能,在进行制作的时候为了防止图片撑开容器而对图片的尺寸进行必要的控制,我们可不可以用CSS控制图片使它自适应大小呢? 可以通过按比例缩小或者放大到某尺寸(自己指定), ...
- HDU 5501——The Highest Mark——————【贪心+dp】
The Highest Mark Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Other ...
- 性能测试学习第六天_loadrunner录制的一些问题
1.录制脚本的两种查看方式(脚本查看和树查看) 2.录制选项 在vugen界面点击开始录制,如下图,点击选项,即进入录制选项界面 重点讨论录制选项下 基于HTML的脚本和基于URL的脚本 注:菜单栏图 ...
- 13.padding和margin,几种参数
这篇会很短. 那么如上图所示,margin指的是外边距,padding指的是内边距,border自有其像素宽度,element在1335乘以392的地方. margin和padding一样总共有四个, ...
- logback的加载过程
使用logback-classic.jar时,启动应用后,logback按照以下顺序进行扫描: 1.在系统配置文件System Properties中寻找是否有logback.configuratio ...