是什么时AOP
aop在我的理解的就是干动态代理,方法增加的。专业一点就是面向切面编程!!
我们实现aop选择spring实现aspectJ aop框架,说白了就是那几个注解:pointCut,before,after,afterthrowing,ascept
不过实现之前还是先了解一下aop的相关概论:
- pointCut:切入点,可以理解要增强的具体方法
- advice:通知 ,就是要增加的具体逻辑,比如前置通知before注解啊,就是在切入点执行之前执行你要执行的逻辑就行了
- aspect: 切面,嗯,,这个我也不是很懂,大概就是切入点和avice通知和在一起,这个类叫切面吧,代码是这样表现的。
实现aop的具体思路
- 之前ioc文章里讲过,我们先后初始化BeanDefinition对象,在BeanDefinition对象里面定义一个属性判断是否是切面
- 初始化aop,遍历BeanDefinition,如果是,则将pointcut,before等注解解析成GPAopConfig对象
- 然后在getBean方法里面,class.newInstance();之后判断是否需要动态代理,就是class是否有切入点
- 如果有就利用动态代理(jdk,cglib)返回一个代理后的对象,后面的属性赋值什么的都对代理对象进行
相关类及其作用
-
GPAopConfig:相当于一个切面,储蓄切面的信息
这个我要说一下,我能力不够,无法解析pointCui对应的表达式,于是想出了给pointCut注解3个属性,分别是package,class,methon,这样我就可以定位到是否要被代理 -
GPAdvice:通知对象,里面有切面和要加强的方法
-
GPAdviceSupport: 这个是个很重要的类,里面有methodCache对象(存放所有被增强方法及相对应的通知和切面(GPAdvice对象))
这个map的key是要被加强的方法,value是个map1,map1就是前置后置啊啥的,map1的key是before,after这种,value就是具体的通知,还是个list,通知有个order是排序用的。
具体思路代码
- 初始化:
/**
* 初始化aop容器
*/
public void initAspect() {
ConcurrentHashMap<String, BeanDefinition> beanDefinitions = BeanFactory.getBeanDefinitions();
List<GPAopConfig> configs = new ArrayList<>();
beanDefinitions.forEach((beanName, beanDefinition) -> {
if (beanDefinition.isAspect()) {
Class clazz = beanDefinition.getClazz();
GPAopConfig aopConfig = new GPAopConfig();
if (clazz.isAnnotationPresent(Order.class)) {
aopConfig.setOrder(((Order) clazz.getDeclaredAnnotation(Order.class)).value());
} else {
aopConfig.setOrder(1);
}
Method[] declaredMethods = clazz.getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
String methodString = declaredMethod.getName();
if ("wait".equals(methodString) || "equals".equals(methodString) || "toString".equals(methodString) ||
"hashCode".equals(methodString) || "getClass".equals(methodString) || "notify".equals(methodString) ||
"notifyAll".equals(methodString)) {
continue;
}
aopConfig.setAspectClass(clazz.getName());
try {
if (declaredMethod.isAnnotationPresent(PointCut.class)) {
PointCut annotation = declaredMethod.getAnnotation(PointCut.class);
aopConfig.setPointCut_class(annotation.class_name());
aopConfig.setPointCut_package(annotation.package_name());
aopConfig.setPointCut_method(annotation.method_name());
}
if (declaredMethod.isAnnotationPresent(Before.class)) {
aopConfig.setAspectBefore(declaredMethod.getName());
}
if (declaredMethod.isAnnotationPresent(After.class)) {
aopConfig.setAspectAfter(declaredMethod.getName());
}
if (declaredMethod.isAnnotationPresent(AfterThrowing.class)) {
aopConfig.setAfterThrowing(declaredMethod.getName());
}
if (declaredMethod.isAnnotationPresent(AfterReturning.class)) {
aopConfig.setAfterReturning(declaredMethod.getName());
}
if (declaredMethod.isAnnotationPresent(Around.class)) {
aopConfig.setAround(declaredMethod.getName());
}
} catch (Exception e) {
e.printStackTrace();
}
}
configs.add(aopConfig);
}
});
AopFactory.setConfigs(configs);
}
- 判断是否需要初始化,如果需要的话将要被加强的mehon放methodCache中
判断是否需要代理:
GPAdviceSupport config = new GPAdviceSupport();
config.setTargetClass(clazz);
config.setTarget(newInstance);
if (config.pointCutMatch()) {
try {
newInstance = new CglibDynamicAopProxy(config).getProxy();
} catch (Exception e) {
newInstance = new GPJDKDynamicAopProxy(config).getProxy();
}
}
Object finalNewInstance1 = newInstance;
这里是逻辑:,,我把整个类都贴出来吧,不太好说,,
package it.yuzuojian.com.aop;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class GPAdviceSupport {
private Class targetClass;
private Object target;
private Map<Method, Map<String, List<GPAdvice>>> methodCache = new HashMap<>();
private boolean check = false;
public boolean pointCutMatch() {
return check;
}
public void parse() {
List<GPAopConfig> configs = AopFactory.getConfigs();
configs.forEach((config) -> {
String pointCut_package = config.getPointCut_package();
if (targetClass.getPackage().getName().contains(pointCut_package)) {
String[] pointCut_class = config.getPointCut_class();
String[] pointCut_method = config.getPointCut_method();
Map<String, Method> aspectMethods = new HashMap<>();
Class aspectClass = null;
try {
aspectClass = Class.forName(config.getAspectClass());
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
for (Method declaredMethod : aspectClass.getDeclaredMethods()) {
aspectMethods.put(declaredMethod.getName(), declaredMethod);
}
if (pointCut_class[0].equals("") && pointCut_method[0].equals("")) {
if (!check) {
check = true;
}
init(config, aspectClass, aspectMethods);
} else if (!pointCut_class[0].equals("") && pointCut_method[0].equals("")) {
if (targetClass.getSimpleName().equals(pointCut_class)) {
if (!check) {
check = true;
}
init(config, aspectClass, aspectMethods);
}
} else if (pointCut_class[0].equals("") && !pointCut_method[0].equals("")) {
init(config, aspectClass, aspectMethods, pointCut_method);
} else {
if (!check) {
check = true;
}
init(config, aspectClass, aspectMethods, pointCut_class, pointCut_method);
}
}
});
}
public void init(GPAopConfig config, Class aspectClass, Map<String, Method> aspectMethods) {
for (Method declaredMethod : this.targetClass.getDeclaredMethods()) {
String methodString = declaredMethod.getName();
if ("wait".equals(methodString) || "equals".equals(methodString) || "toString".equals(methodString) ||
"hashCode".equals(methodString) || "getClass".equals(methodString) || "notify".equals(methodString) ||
"notifyAll".equals(methodString)) {
continue;
}
Map<String, List<GPAdvice>> advices = methodCache.get(declaredMethod);
if (advices == null || advices.size() == 0) {
advices = new HashMap<>();
}
try {
if (!(null == config.getAspectBefore() || "".equals(config.getAspectBefore()))) {
List<GPAdvice> before = advices.get("before");
if (before == null || before.size() == 0) {
before = new ArrayList<>();
}
before.add(new GPAdvice(aspectClass.newInstance(), aspectMethods.get(config.getAspectBefore()), config.getOrder()));
advices.put("before", before);
}
if (!(null == config.getAspectAfter() || "".equals(config.getAspectAfter()))) {
List<GPAdvice> after = advices.get("after");
if (after == null || after.size() == 0) {
after = new ArrayList<>();
}
after.add(new GPAdvice(aspectClass.newInstance(), aspectMethods.get(config.getAspectAfter()), config.getOrder()));
advices.put("after", after);
}
if (!(null == config.getAfterThrowing() || "".equals(config.getAfterThrowing()))) {
List<GPAdvice> afterThrowing = advices.get("afterThrowing");
if (afterThrowing == null || afterThrowing.size() == 0) {
afterThrowing = new ArrayList<>();
}
GPAdvice gpAdvice = new GPAdvice(aspectClass.newInstance(), aspectMethods.get(config.getAfterThrowing()), config.getOrder());
afterThrowing.add(gpAdvice);
advices.put("afterThrowing", afterThrowing);
}
} catch (Exception e) {
e.printStackTrace();
}
methodCache.put(declaredMethod, advices);
}
}
public void init(GPAopConfig config, Class aspectClass, Map<String, Method> aspectMethods, String[] pointCut_method) {
for (Method declaredMethod : this.targetClass.getDeclaredMethods()) {
String methodString = declaredMethod.getName();
if ("wait".equals(methodString) || "equals".equals(methodString) || "toString".equals(methodString) ||
"hashCode".equals(methodString) || "getClass".equals(methodString) || "notify".equals(methodString) ||
"notifyAll".equals(methodString)) {
continue;
}
if (methodString.contains("throws")) {
methodString = methodString.substring(0, methodString.lastIndexOf("throws")).trim();
}
if (check(pointCut_method,methodString)) {
if (!check) {
check = true;
}
Map<String, List<GPAdvice>> advices = methodCache.get(declaredMethod);
if (advices == null || advices.size() == 0) {
advices = new HashMap<>();
}
try {
if (!(null == config.getAspectBefore() || "".equals(config.getAspectBefore()))) {
List<GPAdvice> before = advices.get("before");
if (before == null || before.size() == 0) {
before = new ArrayList<>();
}
before.add(new GPAdvice(aspectClass.newInstance(), aspectMethods.get(config.getAspectBefore()), config.getOrder()));
advices.put("before", before);
}
if (!(null == config.getAspectAfter() || "".equals(config.getAspectAfter()))) {
List<GPAdvice> after = advices.get("after");
if (after == null || after.size() == 0) {
after = new ArrayList<>();
}
after.add(new GPAdvice(aspectClass.newInstance(), aspectMethods.get(config.getAspectAfter()), config.getOrder()));
advices.put("after", after);
}
if (!(null == config.getAfterThrowing() || "".equals(config.getAfterThrowing()))) {
List<GPAdvice> afterThrowing = advices.get("afterThrowing");
if (afterThrowing == null || afterThrowing.size() == 0) {
afterThrowing = new ArrayList<>();
}
GPAdvice gpAdvice = new GPAdvice(aspectClass.newInstance(), aspectMethods.get(config.getAfterThrowing()), config.getOrder());
afterThrowing.add(gpAdvice);
advices.put("afterThrowing", afterThrowing);
}
} catch (Exception e) {
e.printStackTrace();
}
methodCache.put(declaredMethod, advices);
}
}
}
public boolean check(String[] arr,String name){
for (String s : arr) {
if(s.equals(name)){
return true;
}
}
return false;
}
public void init(GPAopConfig config, Class aspectClass, Map<String, Method> aspectMethods, String pointCut_class[], String pointCut_method[]) {
if (check(pointCut_class, targetClass.getSimpleName())) {
for (Method declaredMethod : this.targetClass.getDeclaredMethods()) {
String methodString = declaredMethod.getName();
if ("wait".equals(methodString) || "equals".equals(methodString) || "toString".equals(methodString) ||
"hashCode".equals(methodString) || "getClass".equals(methodString) || "notify".equals(methodString) ||
"notifyAll".equals(methodString)) {
continue;
}
if (methodString.contains("throws")) {
methodString = methodString.substring(0, methodString.lastIndexOf("throws")).trim();
}
if (check(pointCut_method, methodString)) {
if (!check) {
check = true;
}
Map<String, List<GPAdvice>> advices = methodCache.get(declaredMethod);
if (advices == null || advices.size() == 0) {
advices = new HashMap<>();
}
try {
if (!(null == config.getAspectBefore() || "".equals(config.getAspectBefore()))) {
List<GPAdvice> before = advices.get("before");
if (before == null || before.size() == 0) {
before = new ArrayList<>();
}
before.add(new GPAdvice(aspectClass.newInstance(), aspectMethods.get(config.getAspectBefore()), config.getOrder()));
advices.put("before", before);
}
if (!(null == config.getAspectAfter() || "".equals(config.getAspectAfter()))) {
List<GPAdvice> after = advices.get("after");
if (after == null || after.size() == 0) {
after = new ArrayList<>();
}
after.add(new GPAdvice(aspectClass.newInstance(), aspectMethods.get(config.getAspectAfter()), config.getOrder()));
advices.put("after", after);
}
if (!(null == config.getAfterThrowing() || "".equals(config.getAfterThrowing()))) {
List<GPAdvice> afterThrowing = advices.get("afterThrowing");
if (afterThrowing == null || afterThrowing.size() == 0) {
afterThrowing = new ArrayList<>();
}
GPAdvice gpAdvice = new GPAdvice(aspectClass.newInstance(), aspectMethods.get(config.getAfterThrowing()), config.getOrder());
afterThrowing.add(gpAdvice);
advices.put("afterThrowing", afterThrowing);
}
} catch (Exception e) {
e.printStackTrace();
}
methodCache.put(declaredMethod, advices);
}
}
}
}
public Map<String, List<GPAdvice>> getAdvices(Method method, Class targetClass) throws NoSuchMethodException {
Map<String, List<GPAdvice>> adviceMap = methodCache.get(method);
if (null == adviceMap) {
Method declaredMethod = targetClass.getDeclaredMethod(method.getName(), method.getParameterTypes());
adviceMap = methodCache.get(declaredMethod);
this.methodCache.put(declaredMethod, adviceMap);
}
return adviceMap;
}
public Class getTargetClass() {
return targetClass;
}
public void setTargetClass(Class targetClass) {
this.targetClass = targetClass;
parse();
}
public Object getTarget() {
return target;
}
public void setTarget(Object target) {
this.target = target;
}
}
- 最后就是动态代理了,这个没啥好说的,前面都把对象放入methonCache中了,获取在进行代理就好了,有个排序要注意一下,更具order排序嘛,before跟after要是反的哦,因为是链式的嘛
public static Object getProxy(GPAdviceSupport config, Method method, Object[] args) throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {
Map<String, List<GPAdvice>> adviceMap=config.getAdvices(method,config.getTargetClass());
Object result=null;
try {
List<GPAdvice> befores = adviceMap.get("before");
befores.sort(new Comparator<GPAdvice>() {
@Override
public int compare(GPAdvice o1, GPAdvice o2) {
return o1.getOrder()- o2.getOrder();
}
});
for (GPAdvice before : befores) {
before.getAdviceMethod().invoke(before.getAspect());
}
result=method.invoke(config.getTarget(),args);
List<GPAdvice> afters = adviceMap.get("after");
afters.sort(new Comparator<GPAdvice>() {
@Override
public int compare(GPAdvice o1, GPAdvice o2) {
return o2.getOrder()- o1.getOrder();
}
});
for (GPAdvice after : afters) {
after.getAdviceMethod().invoke(after.getAspect());
}
} catch (Exception e) {
e.printStackTrace();
List<GPAdvice> afterThrowings = adviceMap.get("afterThrowing");
afterThrowings.sort(new Comparator<GPAdvice>() {
@Override
public int compare(GPAdvice o1, GPAdvice o2) {
return o2.getOrder()- o1.getOrder();
}
});
for (GPAdvice afterThrowing : afterThrowings) {
afterThrowing.getAdviceMethod().invoke(afterThrowing.getAspect());
}
}
return result;
}
相关事项
我这里实现的也有很多的不足:
- pointCut不会解析表示式,用了3个属性去代替
- 没有用实现around注解
- 比较重要的一点就是我这实现逻辑是一个切面定义一个切入点,这个切面的所有的通知都是只针对这个一个切入点说的,没有实现跟spring一样,一个切面可以有很多个pointCut,方法上可以同时加上pointcut注解和before注解这样,不过想想也不是很难呀,是不是可以针对befor,after这种加上几个map,然后被代理的方法去跟这些map匹配,有兴趣的可以去试一下。
本人目前刚刚毕业,写的不好,逻辑不对或表达不够清楚的可以一起说说,不要喷我就好了,,,源码地址在之前的博客有写!!