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中. 本篇 ...
随机推荐
- 参加2016华为codecraft编程精英挑战赛后感
2016年4月参加了华为的软件比赛. 关于比赛:给了一道图论的np-hard问题.刚开始完全不知道怎么入手,请教过师兄,自己也琢磨过,没有什么万全的解决方法.注意,这里说的是万全的办法.本科搞算法时候 ...
- 337 House Robber III 打家劫舍 III
小偷又发现一个新的可行窃的地点. 这个地区只有一个入口,称为“根”. 除了根部之外,每栋房子有且只有一个父房子. 一番侦察之后,聪明的小偷意识到“这个地方的所有房屋形成了一棵二叉树”. 如果两个直接相 ...
- [转]linux之磁盘配额(quota)
转自:http://www.jb51.net/LINUXjishu/78446.html 磁盘配额(quota)比较常用的几个情况是: * 针对WWW server,例如:每个人的网页空间的容量限制 ...
- No operations allowed after connection closed--转
https://www.jianshu.com/p/1626d41572f2 Spring boot的单数据源配置比较简单,只需要在application.properties配置相关的jdbc连接的 ...
- 大话设计模式--DI(依赖注入)
1.背景 想象一个场景:有个功能通过某个参数决定了路由到不同的方法上或者几个方法模块可以自由搭配,咋办?一般人会对每个方法写一个helper(比如SendMessageForEmail.SendMes ...
- C#语言最基础的数组和集合
数组的书写格式:数据类型[]变量名=new 数据类型[长度]: 集合的书写格式:List<变量类型>变量名=new List<变量类型>(): 集合添加元素:变量名.Add(数 ...
- IE9的F12工具,"网络"页签,点击"开始捕获"之后,请求显示的状态是"挂起"的分析和解决
最近一个项目,客户端使用用jQuery编写ajax请求,服务端采用struts2框架.js发送请求和action处理请求过程中,遇到一个问题.刚开始觉得问题很诡异,仔细定位很久之后才发现问题,虽然问题 ...
- [Windows Server 2008] 服务器安全加固
★ 欢迎来到[护卫神·V课堂],网站地址:http://v.huweishen.com★ 护卫神·V课堂 是护卫神旗下专业提供服务器教学视频的网站,每周更新视频.★ 本节我们将带领大家:服务器安全加固 ...
- C# 返回值为 list<T>
public List<T> test<T>(List<T> EntityList) where T : class { return EntityList; }
- js 不能用关键字 delete 做函数名
把delete更改为mydelete正常.