AOP代理分析
一:代理
代理类和目标类实现了同样的接口。同样的方法。
假设採用工厂模式和配置文件的方式进行管理,则不须要改动client程序。在配置文件里配置使用目标类还是代理类,这样以后就非常easy切换。(比如Spring框架的实现)
AOP:AOP的目标就是要使交叉业务模块化。能够将切面代码移动到原始方法的范围。
二:动态代理
JVM能够在执行期间动态生成出类的字节码。这样的动态生成的类往往被用作代理类,即动态代理类。
JVM生成的动态类必须实现一个或多个接口,所以JVM生成的动态类仅仅能用作具有同样接口的目标类的代理。
CGLIB库能够动态生成一个类的子类,一个类的子类也能够用作该类的代理,所以假设要为一个没有实现接口的类生成动态代理类,能够使用CGLIB库。
三:代理类中的各个方法中通常除了要用目标的对应方法和对外返回目标返回的结构外,还能够在代理方法中的4个位置加入系统功能代码
1.在调用目标方法之前
2.在调用目标方法之后
3.在调用目标方法的前后
4.在处理目标方法异常的catch块中
四:代码測试JVM生成的动态代理类
// 创建jvm动态代理并查看全部构造方法及參数类型(原始类为Collection)
Class clazzProxy = Proxy.getProxyClass(Collection.class.getClassLoader(), Collection.class); // 得到代理对象的字节码
// 得到动态代理类的全部构造方法
Constructor[] constructors = clazzProxy.getConstructors();
for (Constructor constructor : constructors) {
String name = constructor.getName();
StringBuilder sbuilder = new StringBuilder(name);
sbuilder.append("{");
// 得到构造方法的全部參数类型
Class[] clazzParames = constructor.getParameterTypes();
for (Class clazzParame : clazzParames) {
// 将參数类型拼接
sbuilder.append(clazzParame.getName()).append(",");
}
if (clazzParames != null && clazzParames.length != -1) {
sbuilder.deleteCharAt(sbuilder.length() - 1);
}
sbuilder.append("}");
System.out.println(sbuilder);
// 创建jvm动态代理并查看全部方法及參数类型(原始类为Collection)
Method[] methods = clazzProxy.getMethods();
for (Method constructor : methods) {
String name = constructor.getName();
StringBuilder sbuilder = new StringBuilder(name);
sbuilder.append("{");
// 得到方法的全部參数类型
Class[] clazzParames = constructor.getParameterTypes();
for (Class clazzParame : clazzParames) {
// 将參数类型拼接
sbuilder.append(clazzParame.getName()).append(",");
}
if (clazzParames != null && clazzParames.length != -1) {
sbuilder.deleteCharAt(sbuilder.length() - 1);
}
sbuilder.append("}");
System.out.println(sbuilder);
// 创建动态类的的实例化对象方式一(原始类为Collection)
Constructor constructor = clazzProxy.getConstructor(InvocationHandler.class); // 必须创建个有參的构造方法
// InvocationHandler是个接口,自己创建个类实现接口
class MyInvocationHandler1 implements InvocationHandler { @Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
return null;
}
}
// 创建对象。传递的是实现InvocationHandler类的对象
Collection collectonProxy1 = (Collection) constructor.newInstance(new MyInvocationHandler1());
System.out.println(collectonProxy1); // 输出null
// //说明该动态代理对象的toString()方法为null
// 创建动态类的的实例化对象方式二(原始类为Collection)---通过创建匿名内部类
Collection collectionProxy2 = (Collection) constructor
.newInstance(new InvocationHandler() { @Override
public Object invoke(Object proxy, Method method,
Object[] args) throws Throwable {
return null;
}
});
// 创建动态类的的实例化对象方式三---直接一步到位//传递3个參数,第二个參数为接口数组类型
Collection collectionProxy3 = (Collection) Proxy.newProxyInstance(
Collection.class.getClassLoader(),
new Class[] { Collection.class }, new InvocationHandler() {
ArrayList target = new ArrayList(); // !!!将ArrayList的对象改为成员变量。每次调用的都是同一个代理对象 @Override
// proxy:代表代理的对象 method:代表代理对象调用的方法 args:代表调用方法接收的參数
public Object invoke(Object proxy, Method method,
Object[] args) throws Throwable {
Object retVal = method.invoke(target, args);
// 反射机制,调用目标对象target的方法
// ////传递给目标target
System.out.println(method.getName() + "被调用..");
// return对象将返回给代理。可将值进行过滤
return retVal;
}
});
// 对象调用方法測试
// 每调用次add()方法就去运行InvocationHandler类的invoke()方法
collectionProxy3.add("wzl");
collectionProxy3.add("hlw"); // 调用后的代理对象的方法后的返回值从invoke的返回值取
System.out.println(collectionProxy3.size());
// -----------------------------------------------------------------------------
// 抽取成方法。InvocationHandler类传递两个对象(目标对象和系统功能方法封装成的对象)
1.系统方法类接口
/*
* 系统功能的接口类
*/
public interface Advice {
void beforMethod(); // 在目标方法之前的系统功能方法(仅仅传递目标方法method,可传递目标对象target,method,參数args) void afterMethod(Method method); // 在目标方法之后的系统功能方法
}
2.实现接口类的系统方法类
/*
* 实现系统功能接口的类
*/
public class MyAdvice implements Advice {
private long startTime = 0; @Override
public void beforMethod() {
System.out.println("----调用目标方法之前的系统方法");
startTime = System.currentTimeMillis();
} @Override
public void afterMethod(Method method) {
System.out.println("----调用目标方法之后的系统方法");
long endTime = System.currentTimeMillis();
System.out
.println(method.getName() + " 运行时间:" + (endTime - startTime));
} }
3.抽取成方法,InvocationHandler类传递两个对象(原始类为Collection)---(目标对象和系统功能方法封装成的对象)
// 1.创建目标对象target
final ArrayList target = new ArrayList(); // !!!将ArrayList的对象改为成员变量,每次调用的都是同一个代理对象
Collection collectionProxy4 = (Collection) getProxy(target,new MyAdvice()); //传递目标对象和实现系统功能的对象
/*測试
collectionProxy4.add("wzl");
collectionProxy4.add("hlw"); // 调用后的代理对象的方法后的返回值从invoke的返回值取
System.out.println(collectionProxy4.size());
*/
}
//InvocationHandler类传递两个对象
private static Object getProxy(final Object target,final Advice advice) {
return (Object) Proxy.newProxyInstance(
target.getClass().getClassLoader(), //实现的是和目标对象同样的类载入器
target.getClass().getInterfaces(), //实现的是和目标对象同样的接口
new InvocationHandler() { @Override
// proxy:代表代理的对象 method:代表代理对象调用的方法 args:代表调用方法接收的參数
public Object invoke(Object proxy, Method method,
Object[] args) throws Throwable {
advice.beforMethod();
Object retVal = method.invoke(target, args); // 反射机制,调用目标对象target的方法
advice.afterMethod(method); // ////传递给目标target
// return对象将返回给代理。可将值进行过滤
return retVal;
}
}); }
AOP代理分析的更多相关文章
- Spring AOP源码分析(三)创建AOP代理
摘要: 本文结合<Spring源码深度解析>来分析Spring 5.0.6版本的源代码.若有描述错误之处,欢迎指正. 目录 一.获取增强器 1. 普通增强器的获取 2. 增加同步实例化增强 ...
- spring源码 — 三、AOP代理生成
AOP代理生成 AOP就是面向切面编程,主要作用就是抽取公共代码,无侵入的增强现有类的功能.从一个简单的spring AOP配置开始: <?xml version="1.0" ...
- 记一次Spring的aop代理Mybatis的DAO所遇到的问题
由来 项目中需要实现某个订单的状态改变后然后推送给第三方的功能,由于更改状态的项目和推送的项目不是同一个项目,所以为了不改变原项目的代码,我们考虑用spring的aop来实现. 项目用的是spring ...
- Spring学习13-中IOC(工厂模式)和AOP(代理模式)的详细解释
我们是在使用Spring框架的过程中,其实就是为了使用IOC,依赖注入,和AOP,面向切面编程,这两个是Spring的灵魂. 主要用到的设计模式有工厂模式和代理模式. IOC是工厂模式参考:设计模式- ...
- 设计模式(四) 手动实现AOP代理
1.事务的使用: 每次对数据库操作我们都需要开启事务,事务开启后,我们就需要对数据库进行一次或者多次操作,当操作完成后就需要提交事务.比如一个业务中多次操作数据库,但是当某个方法出错的时候,我们需要整 ...
- spring5 源码深度解析----- AOP代理的生成
在获取了所有对应bean的增强后,便可以进行代理的创建了.回到AbstractAutoProxyCreator的wrapIfNecessary方法中,如下所示: protected static fi ...
- 过滤器、拦截器和AOP的分析与对比
目录 一.过滤器(Filter) 1.1 简介 1.2 应用场景 1.3 源码分析 二.拦截器(Interceptor) 2.1 简介 2.2 应用场景 2.2 源码分析 三.面向切面编程(AOP) ...
- Spring事物入门简介及AOP陷阱分析
转载请注明出处: https://www.cnblogs.com/qnlcy/p/15237377.html 一.事务的定义 事务(Transaction),是指访问并可能更新数据库中各种数据项的一个 ...
- AOP源码解析之二-创建AOP代理前传,获取AOP信息
AOP源码解析之二-创建AOP代理前传,获取AOP信息. 上篇文章对AOP的基本概念说清楚了,那么接下来的AOP还剩下两个大的步骤获取定义的AOP信息,生成代理对象扔到beanFactory中. 本篇 ...
随机推荐
- 修改docker-toolbox/boot2docker容器镜像
进入虚拟机 vi /var/lib/boot2docker/profile 编辑在EXTRA_ARGS,加入 --registry-mirror=https://pee6w651.mirror.ali ...
- SVN系列学习(一)-SVN的安装与配置
1.SVN的介绍 SVN是Subversion的简称,是一个开发源代码的版本控制系统,采用了分支管理系统. 文件保存在中央版本库,除了能记住文件和目录的每次修改以外,版本库非常像普通的文件服务器.你可 ...
- overflow:解决 div的高度塌陷问题
高度塌陷是如何引起的? 解析: 当一个 div中所有的子 div都进行了浮动后,那么会出现该问题,那么解决方就是在父 div中 设置其 overflow:hidden;即可解决高度塌陷问题. 方式 ...
- 前端-Node.js思维导图笔记
看不清的朋友右键保存或者新窗口打开哦!喜欢我可以关注我,还有更多前端思维导图笔记
- 【PostgreSQL-9.6.3】分区表
PostgreSQL中的分区表是通过表继承来实现的(表继承博客http://www.cnblogs.com/NextAction/p/7366607.html).创建分区表的步骤如下: (1)创建“父 ...
- Ajax——异步基础知识(二)
XML数据格式 首行必须是版本号和格式等信息 <?xml version="1.0" encoding="utf-8" ?> 最外层需要一个根节点进 ...
- 将vim的UltiSnips的快捷键彻底从tab键中分离
在我之前的<<vim之补全1>>和<<vim之补全2>>中曾经成功的将vim的supertab和UltiSnips共用一个tab键, 这样做的优点的两种 ...
- 一个有趣的 ”Validation of viewstate MAC failed” 错误的发现和解决
在ASP.NET里面,View State使用较为广泛.它作为一个隐藏字段,可以帮助服务端”记住“客户端的改变,这样客户端 收到服务器对PostBack的响应后,仍然可以展现在PostBack之前设定 ...
- 一台电脑同时使用多个Git账号
参照 https://my.oschina.net/u/3578363/blog/2209781
- input按钮的事件处理大全
input按钮的事件处理大全 input按钮的事件处理大全1.<INPUT onclick=document.all.WebBrowser.ExecWB(1,1) type=button v ...