手寫 簡單 aop 框架
阿新 • • 發佈:2018-11-19
cglib 手寫 簡單 aop 框架,實現方法級別的攔截
0 緣起
一直對 java 的動態代理 還有 spring 的 aop 理解不深刻, 所以打算實現一個簡單的 aop 目的是用於學習 cglib 和 aop 思想。
1 思路
1 掃描 aop 包, 獲取 aspect 的類
2 根據 切點 獲取該切點的 類 和 方法
3 根據配置的 類 和 方法 為該類生成一個代理物件
4 將改代理物件放入 bean Map 中
5 呼叫的時候 將代理物件 轉換成需要的物件
2 使用
Step 1: 定義被代理的實體類
public class Test {
public void doSomeThing() {
System.out.println("do some thing...");
}
public void doWtihNotProxy() {
System.out.println("do some thing with not proxy");
}
}
Step 2: 定義切點和切面, 並且繼承 AbsMethodAdvance
package org.aop.demo;
import org.aop.annotion.aspect.Aspect;
import org.aop.annotion.aspect.PointCut;
import org.aop.proxy.AbsMethodAdvance;
/**
* @Author: huangwenjun
* @Description:
* @Date: Created in 15:53 2018/4/18
**/
@Aspect
public class TestAspect extends AbsMethodAdvance {
/**
* 全類名_方法名 (被攔截的類_被攔截的方法)
*/
@PointCut("org.aop.demo.Test_doSomeThing")
public void testAspect() {
}
@Override
public void doBefore() {
System.out.println("do before");
}
@Override
public void doAfter() {
System.out.println("do after");
}
}
Step 3: 測試
public static void main(String[] args) {
// 模擬容器初始化
ApplicationContext applicationContext = new ApplicationContext();
ConcurrentHashMap<String, Object> proxyBeanMap = ApplicationContext.proxyBeanMap;
// 生成的代理物件 預設為該類名的小寫
Test test = (Test) proxyBeanMap.get("test");
test.doSomeThing();
System.out.println("-------------");
test.doWtihNotProxy();
}
輸出:
do before
do some thing...
do after
-------------
do some thing with not proxy
3 核心程式碼
3.1 ApplicationContext
public class ApplicationContext {
/**
* 存放代理類的集合
*/
public static ConcurrentHashMap<String, Object> proxyBeanMap = new ConcurrentHashMap<String, Object>();
static {
initAopBeanMap("org.aop.demo");
}
/**
* 初始化 aop 容器
*/
public static void initAopBeanMap(String basePath) {
try {
Set<Class<?>> classSet = ClassUtil.getClassSet(basePath);
for (Class clazz : classSet) {
if (clazz.isAnnotationPresent(Aspect.class)) {
//找到切面
Method[] methods = clazz.getMethods();
for(Method method : methods) {
if (method.isAnnotationPresent(PointCut.class)) {
// 找到切點
PointCut pointCut = (PointCut) method.getAnnotations()[0];
String pointCutStr = pointCut.value();
String[] pointCutArr = pointCutStr.split("_");
// 被代理的類名
String className = pointCutArr[0];
// 被代理的方法名
String methodName = pointCutArr[1];
// 根據切點 建立被代理物件
Object targetObj = ReflectionUtil.newInstance(className);
// 根據切面類建立代理者
AbsMethodAdvance proxyer = (AbsMethodAdvance) ReflectionUtil.newInstance(clazz);
// 設定代理的方法
proxyer.setProxyMethodName(methodName);
Object object = proxyer.createProxyObject(targetObj);
if (object != null) {
proxyBeanMap.put(targetObj.getClass().getSimpleName().toLowerCase(), object);
}
}
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
3.2 AbsMethodAdvance
public abstract class AbsMethodAdvance implements MethodInterceptor {
/**
* 要被代理的目標物件
*/
private Object targetObject;
/**
* 被代理的方法名
*/
private String proxyMethodName;
/**
* 根據被代理物件 建立代理物件
* @param target
* @return
*/
public Object createProxyObject(Object target) {
this.targetObject = target;
// 該類用於生成代理物件
Enhancer enhancer = new Enhancer();
// 設定目標類為代理物件的父類
enhancer.setSuperclass(this.targetObject.getClass());
// 設定回撥用物件為本身
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
Object result;
String proxyMethod = getProxyMethodName();
if (StringUtils.isNotBlank(proxyMethod) && proxyMethod.equals(method.getName())) {
doBefore();
}
// 執行攔截的方法
result = methodProxy.invokeSuper(proxy, args);
if (StringUtils.isNotBlank(proxyMethod) && proxyMethod.equals(method.getName())) {
doAfter();
}
return result;
}
public abstract void doBefore();
public abstract void doAfter();
public String getProxyMethodName() {
return proxyMethodName;
}
public void setProxyMethodName(String proxyMethodName) {
this.proxyMethodName = proxyMethodName;
}
}
4 完整程式碼
GitHub