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中. 本篇 ...
随机推荐
- Objective-C——关联对象
动态语言 OC是一种动态语言,它的方法,对象的类型都是到运行的时候才能够确定的.所以这就使得OC存在了关联对象这一强大的机制. 关联对象 所谓关联对象,其实就是我们在运行时对一个已存在的对象上面绑定一 ...
- [Codeforces]Codeforces Round #489 (Div. 2)
Nastya and an Array 输出有几种不同的数字 #pragma comment(linker, "/STACK:102400000,102400000") #ifnd ...
- 实现div毛玻璃背景
毛玻璃效果 ios里毛玻璃效果的使用非常多,本文介绍一个实现div毛玻璃背景的方法 CSS3 Filter CSS3的Filter主要用在图像的特效处理上,默认值为none,还有以下备选项: 1. ...
- 第一次android混淆实战
第一次混淆,主要是因为引用本地第三方jar包的问题.虽然说本地第三方jar包自动避免混淆,但一些本地第三方jar包下的一些包要避免混淆.比如: 文中的com.org 这些包名都要避免混淆. 下面是我用 ...
- THREE.DecalGeometry(转载)
function getDecalGeometry(position, direction){ var decalGeometry = new THREE.DecalGeometry( earthMe ...
- WPF在win7运行时报'Initialization of 'System.Windows.Setter' threw an exception.'
写的一个WPF程序,在win10运行好好的,在win7就报'Initialization of 'System.Windows.Setter' threw an exception.' 原来是xaml ...
- java数据类型和码表、转义字符
类型名称 字节空间 范围 整数型 byte 1 -27到27-1 或者 -128到127 short 2 -215到215-1 int 4 -231到231-1 long 8 ...
- hdu2003 求绝对值【C++】
求绝对值 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submis ...
- 【codeforces 755E】PolandBall and White-Red graph
[题目链接]:http://codeforces.com/contest/755/problem/E [题意] 给你n个节点; 让你在这些点之间接若干条边;构成原图(要求n个节点都联通) 然后分别求出 ...
- Struts2 值栈总结(ValueStack)
1.获取值栈 //获取值栈的第一种方式 ValueStack valueStack1 = (ValueStack) ServletActionContext.getRequest().getAttri ...