一:代理

代理类和目标类实现了同样的接口。同样的方法。

假设採用工厂模式和配置文件的方式进行管理,则不须要改动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代理分析的更多相关文章

  1. Spring AOP源码分析(三)创建AOP代理

    摘要: 本文结合<Spring源码深度解析>来分析Spring 5.0.6版本的源代码.若有描述错误之处,欢迎指正. 目录 一.获取增强器 1. 普通增强器的获取 2. 增加同步实例化增强 ...

  2. spring源码 — 三、AOP代理生成

    AOP代理生成 AOP就是面向切面编程,主要作用就是抽取公共代码,无侵入的增强现有类的功能.从一个简单的spring AOP配置开始: <?xml version="1.0" ...

  3. 记一次Spring的aop代理Mybatis的DAO所遇到的问题

    由来 项目中需要实现某个订单的状态改变后然后推送给第三方的功能,由于更改状态的项目和推送的项目不是同一个项目,所以为了不改变原项目的代码,我们考虑用spring的aop来实现. 项目用的是spring ...

  4. Spring学习13-中IOC(工厂模式)和AOP(代理模式)的详细解释

    我们是在使用Spring框架的过程中,其实就是为了使用IOC,依赖注入,和AOP,面向切面编程,这两个是Spring的灵魂. 主要用到的设计模式有工厂模式和代理模式. IOC是工厂模式参考:设计模式- ...

  5. 设计模式(四) 手动实现AOP代理

    1.事务的使用: 每次对数据库操作我们都需要开启事务,事务开启后,我们就需要对数据库进行一次或者多次操作,当操作完成后就需要提交事务.比如一个业务中多次操作数据库,但是当某个方法出错的时候,我们需要整 ...

  6. spring5 源码深度解析----- AOP代理的生成

    在获取了所有对应bean的增强后,便可以进行代理的创建了.回到AbstractAutoProxyCreator的wrapIfNecessary方法中,如下所示: protected static fi ...

  7. 过滤器、拦截器和AOP的分析与对比

    目录 一.过滤器(Filter) 1.1 简介 1.2 应用场景 1.3 源码分析 二.拦截器(Interceptor) 2.1 简介 2.2 应用场景 2.2 源码分析 三.面向切面编程(AOP) ...

  8. Spring事物入门简介及AOP陷阱分析

    转载请注明出处: https://www.cnblogs.com/qnlcy/p/15237377.html 一.事务的定义 事务(Transaction),是指访问并可能更新数据库中各种数据项的一个 ...

  9. AOP源码解析之二-创建AOP代理前传,获取AOP信息

    AOP源码解析之二-创建AOP代理前传,获取AOP信息. 上篇文章对AOP的基本概念说清楚了,那么接下来的AOP还剩下两个大的步骤获取定义的AOP信息,生成代理对象扔到beanFactory中. 本篇 ...

随机推荐

  1. 非常无聊——STD::sort VS 基数排序

    众所周知,Std::sort()是一个非常快速的排序算法,它基于快排,但又有所修改.一般来说用它就挺快的了,代码一行,时间复杂度O(nlogn)(难道不是大叫一声“老子要排序!!”就排好了么...). ...

  2. SCOI2014总结

    似乎还没有写过SCOI的总结,今天补上,权当填坑. PS:CDQZ的看到了不要到处黑 SCOI-2014应该算是我的小高考,感觉拿住一本招的瓶颈就在这里.加之NOIp只有400分有点拖后腿,所以很早就 ...

  3. 【百度之星】-IP聚合

    问题描述: Problem Description 当今世界,网络已经无处不在了,小度熊由于犯了错误,当上了度度公司的网络管理员,他手上有大量的 IP列表,小度熊想知道在某个固定的子网掩码下,有多少个 ...

  4. java学习笔记_网络

    客户端 import java.io.*; import java.net.*; public class DailyAdviceClient { public void go() { try { S ...

  5. [Codeforces]Codeforces Round #489 (Div. 2)

    Nastya and an Array 输出有几种不同的数字 #pragma comment(linker, "/STACK:102400000,102400000") #ifnd ...

  6. 原生js实现简单的焦点图效果

    用到一些封装好的运动函数,主要是定时器 效果为图片和图片的描述定时自动更换 <!DOCTYPE html> <html> <head> <meta chars ...

  7. HTTP05--HTML常用知识

    一.URL地址含义 需要搞清URL和URI的差别,以及QueryString的含义. 二.GET和POST的区别 详细介绍可参考文章:http://zengrong.net/post/1802.htm ...

  8. CSS——盒子

    CSS中的盒子具有以下几个种重要的属性: 1.border(边框) :盒子的厚度 2.padding(内边距):盒子内容距离盒子边框的距离 3.margin(外边距):盒子边框与其他的盒子的距离

  9. [Windows Server 2012] Discuz X3安全设置

    ★ 欢迎来到[护卫神·V课堂],网站地址:http://v.huweishen.com ★[护卫神·V课堂]是护卫神旗下专业提供服务器教学视频的网站,每周更新视频. ★ 本节我们将带领大家:Discu ...

  10. Windows10下Docker的安装

    安装前先说明一下,这里windows10要是专业版(Professional)或者是企业版(Enterprise),而且要是64位,否则会出现错误.不是这两个版本的win10没有自带的虚拟机(教育版未 ...