最近我手寫實現了Spring的核心功能,通過手寫更深入理解點擊打開鏈接了反射/動態代理
Spring核心包括兩部分:AOP/IOC
完整代碼可以去我的GitHub
介紹AOP和IOC之前,先 看看動態代理和反射
代理是一種設計模式,假如我們要找媳婦,我們可以不用自己去找,可以去婚姻介紹所,
婚姻介紹所就是代理,他可以幫我們找到需要的對象.當然了,在得到對象之前,我們需要告訴他需要那個,他會給我們看照片吧,看對象的介紹,然後我們看上哪個了就得到了(假設),在得到後,介紹所會收取一定費用(使用動態代理對方法進行增強).
關於動態代理,我們可以用jdk自帶的(需要接口來生成代理類)
需要寫一個類實現InvocationHandler接口
然後實現invoke方法,當我們使用代理類調用裏面的方法時,會走這個方法,這裏我們
我們在構造裏接受參數 c 就是需要被代理的對象
public JdkInvocationHandler(Object c){ this.c=c; }
然後可以在調用被代理對象的方法之前輸出"之前" ,然後在執行代理類方法後輸出"之後"
這就是動態代理的好處,可以對方法進行增強
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("之前");//這裏第一個參數必須是Object---------------------- method.invoke(c,args);
System.out.println("之後");return proxy;}
然後我們可以這樣獲得代理類
JdkInvocationHandler jdkInvocationHandler=new JdkInvocationHandler(c.newInstance()); Object o = Proxy.newProxyInstance(jdkInvocationHandler.getClass().getClassLoader(), c.getInterfaces(), jdkInvocationHandler);
先創建一個實現了InvocationHandler接口的類,傳入一個需要代理的對象
然後通過Proxy.newInstance()方法,傳遞一個類加載器,接口,實現了InvocationHandler接口的類來生成代理類
然後我們就能使用這個代理類了
可以對他進行強轉,然後調用方法就能看見效果了
**jdk的動態代理是有弊端的,那就是隻能使用接口來生成代理類
假如我們需要代理的對象沒有實現接口怎麼辦
這時候我們可以用cglib,可以通過繼承的辦法來生成代理類
-------
和jdk的動態代理差不多,我們需要寫一個實現了Methodinterceptor接口的類
執行被代理類的方法前打印“之前”,執行後打印“之後”
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("之前"); methodProxy.invokeSuper(o,objects);
System.out.println("之後");return o;}
怎麼獲得對象呢,先創建一個增強器,然後設置回調(就是調用代理類的方法需要做的事),然後create就得到對象了
Enhancer enhancer = new Enhancer(); enhancer.setCallbacks(new Callback[]{new CGlibMethodInterceptor(listListEntry.getKey(), listListEntry.getValue())}); enhancer.setSuperclass(c); Object o = enhancer.create();強轉後就能直接調用了
----------
接下來是關於反射的
我們可以通過Class.forName(String className)來傳入類名來獲得類對象
可以理解成數據庫的select操作,通過類名查找Class
可以用Method.invoke(Object o,Object[] args)來調用指定對象裏面的方法
可以用Field.set(Object o,Object v) 來設置類裏面的字段值
----------------------
AOP
面向切面編程,可以讓我們專注於業務邏輯開發(用動態代理實現)
具體可以看這個
使用動態代理來對方法進行增強
-----------------------
IOC
控制反轉(用反射實現)
可以讓框架來管理類
讓類的創建交給框架處理,
比如我們獲得通過反射獲得一個類對象,然後需要對類進行初始化,並且要對加了@Autowired註解的字段進行設置值,我們就把對字段的設置交給了框架進行處理,就實現了控制反轉
還有對需要增強方法的類進行增強,通過動態代理來生成代理類,也實現了控制反轉
接下來我們看一下關於AOP和IOC的具體流程(純手寫,僅實現核心功能)
1.首先,我們需要定義註解
After/Aspect/Autofired/BackPackage/Before/Controller/RequestMapping/Service
2.然後寫一個DispatcherServlet(核心)
並在web.xml中配置這個Servlet
當我們訪問任意路徑, 都會調用這個servleet來執行
這個Servlet有個init方法,會在初始化的時候執行
我們可以在init方法中寫初始化"框架"的方法
1.獲得需要掃描的包名
2.然後通過遞歸掃描指定包下的所有類,放到容器裏
3.接下來就是初始化切面容器,我們需要將條件和之前/之後需要調用的方法和類對象放到容器裏
由於我們切面是這樣使用的,之前要執行的方法可以有很多個,之後要執行的方法可能也有很多個
這裏我們可以把他放到Map中
這樣放到map中,用於後面爲需要增強方法的對象通過動態代理進行增強
4.然後我們需要對類進行初始化
邏輯是:
遍歷放了所有類的容器
如果類全名在切面容器內出現了
判斷這個類時候實現了接口
如果實現了接口,就使用jdk動態代理,將切面容器中的之前之後方法傳到jdkInvocationHandler中,生成代理對象並放到容器裏用於後面對使用了Autowired註解的字段進行注入
如果沒有實現接口,就使用cglib生成代理對象並放大容器裏,用於後面注入
如果沒有在切面容器裏出現,就直接newInstance 放到容器裏後面再注入
5.然後我們需要遍歷容器裏面存放的對象引用
遍歷對象引用,並且遍歷所有字段,如果加了Autowired註解,就從instanceMap中拿到並通過反射來注入值
通過Field.set(Object o,Object v)方法
6.然後我們需要掃描所有Controller
獲得所有映射和方法/類放到容器裏
7.然後在doGet和doPost中寫方法處理請求
這個方法就是獲得請求,然後在url映射容器裏找需要執行的方法,和類,然後通過反射進行調用
如果返回了String 就表示要顯示jsp頁面,就直接forword
Mybatis的手寫核心功能也完成了,明天寫博客,睡覺
完整代碼可以去我的GitHub