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中. 本篇 ...
随机推荐
- [转]Linux下chkconfig命令详解
转自:http://www.cnblogs.com/panjun-Donet/archive/2010/08/10/1796873.html chkconfig命令主要用来更新(启动或停止)和查询系统 ...
- Task.Run 和 Task.Factory.StartNew
在.Net 4中,Task.Factory.StartNew是启动一个新Task的首选方法.它有很多重载方法,使它在具体使用当中可以非常灵活,通过设置可选参数,可以传递任意状态,取消任务继续执行,甚至 ...
- Razor的使用
Razor可以识别尖括号,且关键词是@,默认情况下会对输出的html代码进行转义 1.C#代码 用 @ 加 中括号 包起来 @{ ; i < ; i++) { <h3>C#语句块要用 ...
- Android studio & SDK的国内有效站点。
SDK.TOOLS的国内有效镜像节点: mirrors.zzu.edu.cn/android/repository/ 网上的地址只写了mirrors.zzu.edu.cn,有误,需要补齐后面的子目录才 ...
- Java 6中类路径ClassPath对通配符的支持
在java 6之前,如果我们的应用依赖多个jar包,通常是将所有jar包文件枚举设置到环境变量CLASSPATH或者命令行参数-classpath(-cp)中.通常我们需要写一段shell脚本实现该功 ...
- Ajax——异步基础知识(三)
封装异步请求 1.将函数作为参数进行使用 2.因为获取数据是在一个注册事件中获取的,所以只有事件触发的时候才会调用此函数 <!DOCTYPE html> <html lang=&qu ...
- C# 字符串的入门
1."@"表示字符串中的"\"不当成转义符. 2.转义符或者特殊处理的一些字符只是针对于代码中直接写出的字符串中,对于程序运行中读取出来的转义符或者特殊处理的字 ...
- 8、scala面向对象编程之对象
1. Object 2.伴生对象 3.让object继承抽象类 4.apply方法 5.main方法 6.用object实现枚举功能 1. Object Object,相当于class的单个实例, ...
- MySQL详细操作
一.用户管理 -- 创建用户 create user "用户名"@"IP地址" identified by "密码"; "; &q ...
- 小白神器 - 一篇博客学会HTML
小白神器 - 一篇博客学会HTML 一. 简介 1. HTML 定义 htyper text markup language 即超文本标记语言. 超文本: 就是指页面内可以包含图片.链接,甚至音乐. ...