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 ...
随机推荐
- 深入理解Java虚拟机 学习总结
一.运行时数据区域 Java虚拟机管理的内存包括几个运行时数据内存:方法区.虚拟机栈.本地方法栈.堆.程序计数器,其中方法区和堆是由线程共享的数据区,其他几个是线程隔离的数据区 1.1 程序计数器 程 ...
- 分层图最短路【bzoj2763】: [JLOI2011]飞行路线
bzoj2763: [JLOI2011]飞行路线 Description Alice和Bob现在要乘飞机旅行,他们选择了一家相对便宜的航空公司.该航空公司一共在n个城市设有业务,设这些城市分别标记为0 ...
- Multi-catch parameters are not allowed for source level below 1.7 报错处理
有可能是你项目右键build-path里面的这个东西 在项目上右键properties->project Facets->修改右侧的version 保持一致 还有一个就是Window里面 ...
- 方程的解_NOI导刊2010提高(01) 组合数
题目描述 佳佳碰到了一个难题,请你来帮忙解决. 对于不定方程a1+a2+…+ak-1+ak=g(x),其中k≥2且k∈N,x是正整数,g(x)=x^x mod 1000(即x^x除以1000的余数), ...
- yum 缓存包到本地
yum install –downloadonly –downloaddir=/root/mypackages/ vim 说明: --downloadonly 只下载 --downloaddir 下载 ...
- :input获得焦点时被弹出键盘挡住解决办法
这个是移动端非常常见的bug了,这里说下综合的解决办法,因为有时候你的办法就是会失效.. 上代码 /*input框调起输入法盖住输入问题*/$('input[type="text" ...
- list倒序删除
public static void main(String[] args) { List<Integer> nums = new ArrayList<Integer>(); ...
- 积分图像的应用(二):非局部均值去噪(NL-means)
非局部均值去噪(NL-means)一文介绍了NL-means基本算法,同时指出了该算法效率低的问题,本文将使用积分图像技术对该算法进行加速. 假设图像共像个素点,搜索窗口大小,领域窗口大小, 计算两个 ...
- logAB = logA + logB; A,B>0
令 X = logA, Y = logB, Z=logAB .2x = A, 2y = B, 2z = AB, 则有 2z = AB = 2x * 2y = 2x+y ,有z = x+y,即 logA ...
- wamp 下运行Drupal慢的解决方法
1.Editing your php.ini and make realpath_cache_size=2M, 2.uncomment skip innodb in your my.cnf(my.in ...