手寫Spring

最近我手寫實現了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

面向切面編程,可以讓我們專注於業務邏輯開發(用動態代理實現)

具體可以看這個

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

 點擊打開鏈接

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章