前言
小编在学习一本书《spring 技术内幕》,书中讲解源码,以及源码的设计思路,通过AOP这章内容的学习,小编发现需要拿出来总结一番了。(百度网盘地址:https://pan.baidu.com/s/1mA1NCehfmB8deud8f3w2xQ 提取码:zzsd )
AOP概念
1. Aspect-Oriented Programming,面向方面编程或面向切面编程。
2.维基百科中解释
Aspect是一种新的模块化机制,用来描述分散在对象、类或函数中的横切关注点(crosscutting concern),从关注点中分离出横切关注点是面向切面编程的核心概念。
3.模块化
c语言程序设计,体现了模块化,分而治之,一个大函数分解成多个子函数;
面向对象的设计方式,也是一种模块化方法,计算尽可能靠近数据,通过继承来重用和管理方法;在功能重复需要用在不同地方,继承方法无法很好解决这个问题,AOP可以将重复的代码抽取出来单独维护,在需要使用时统一调用。
AOP体系结构
AOP联盟定义的AOP体系结构把与AOP相关的概念大致分为由高到低、由使用到实现三个层次。
一、语言和开发环境
这是最高层,分为基础、切面和配置
1.基础(base):待增强对象或目标对象
2.切面(aspect):包含对基础的增强应用
3.配置(configuration):可以看成是一种编织,通过配置完成切面对目标对象的编织实现。使用IOC容器来实现编织配置。
使用Java语言实现增强对象与切面增强
二、面向方面系统
主要包括配置和编织实现两部分,对这些实现进行抽象的高级API封装,为最高层提供了有力的支持。
三、编织实现模块
使用Java语言的特性,如Java 的Proxy代理类、拦截器等技术,实现AOP编织。
具体实现方法:反射、程序预处理、拦截器框架、类装载器框架、元数据处理等。
Advice通知
一、基本概念
Advice(通知)定义在连接点做什么,为切面增强提供织入接口。
Spring AOP 的实现中, 使用了这个统一接口,为AOP的切面增强的织入功能做了更多的细化和扩展,比如添加了具体的通知类型,如BeforeAdvice、AfterAdvice、ThrowsAdvice等接口。
二、BeforeAdvice的实现
1.类层次结构
在BeforeAdvice的继承关系中,定义了为待增强的目标方法设置的前置增强接口MethodBeforeAdvice,使用这个前置接口需要实现一个回调函数:
void before(Method method,Object[] args,Object target)throws Throwable;
作为回调函数,会在Advice中被配置到目标方法后,调用目标方法时被回调。
2.具体的调用参数
Method对象,这个参数是目标方法的反射对象;
Object[]对象数组,包含目标方法的输入参数;
Object target
3.BeforeAdvice的具体使用
(1)CountingBeforeAdvice是接口MethodBeforeAdvice的具体实现,统计被调用方法的次数。
作为切面的增强,它会根据调用方法的方法名进行统计,把统计结果根据方法名和调用次数作为键值放入一个map中。
public class CountingBeforeAdvice extends MethodCounter implements MethodBeforeAdvice{
public void before(Method m,Object[] args,Object target)throws Throwable{
count(m);
}
}
(2)MethodCounter作为基类,实现了count(method m)方法
在统计过程中,首先通过目标方法的反射对象得到方法名,然后进行累加,把统计结果放到维护的哈希表中,如果需要统计数据,就到哈希表中根据key值去取。
public class MethodCounter implements Sirializable{
// 这个hashMap用来存储方法名和调用次数的键值对
private HashMap<String,Integer> map=new HashMap<String,Integer>();
// 调用的次数,不管什么方法名
private int allCount;
protected void count(Method m){
// CountingBeforeAdvice的入口
count(m.getName());
}
// 根据方法名统计调用次数
protected void count(String methodName){
Integer i=map.get(methodName);
i=(i!=null) ? new Integer(i.intValue()+1):new Integer(1);
map.put(methodName,i);
++allCount;
}
// 根据方法名取得调用次数
public int getCalls(String methodName){
Integer i= map.get(methodName);
return (i!=null ? i.intValue:0);
}
// 取得所有方法的调用次数
public int getCalls(){
return allCount;
}
public boolean equals(Object other){
return(other!=null && other.getClass()==this.getClass());
}
public int hashCode(){
return getClass.hashCode;
}
}
小结
补充两个概念:
1.回调函数:回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。
2.反射:
反射之中包含了一个“反”的概念,所以要想解释反射就必须先从“正”开始解释,一般而言,当用户使用一个类的时候,应该先知道这个类,而后通过这个类产生实例化对象,但是“反”指的是通过对象找到类。
用于 reflection 的类,如 Method,可以在 java.lang.relfect 包中找到。使用这些类的时候必须要遵循三个步骤:第一步是获得你想操作的类的 java.lang.Class 对象。在运行中的 Java 程序中,用 java.lang.Class 类来描述类和接口等。
下面就是获得一个 Class 对象的三个方法:
Class c = Class.forName("java.lang.String");
Class c = int.class;
Class c = Integer.TYPE;
推荐博客:https://www.cnblogs.com/cs-lcy/p/7397955.html
感谢您的访问!