日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

自己动手实现的 Spring IOC 和 AOP - 上篇

發布時間:2025/3/21 javascript 21 豆豆
生活随笔 收集整理的這篇文章主要介紹了 自己动手实现的 Spring IOC 和 AOP - 上篇 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

1. 背景

我在大四實習的時候開始接觸 J2EE 方面的開發工作,也是在同時期接觸并學習 Spring 框架,到現在也有快有兩年的時間了。不過之前沒有仿寫過 Spring IOC 和 AOP,只是宏觀上對 Spring IOC 和 AOP 原理有一定的認識。所以為了更進一步理解 Spring IOC 和 AOP 原理。在工作之余,參考了一些資料和代碼,動手實現了一個簡單的 IOC 和 AOP,并實現了如下功能:

  • 根據 xml 配置文件加載相關 bean
  • 對 BeanPostProcessor 類型的 bean 提供支持
  • 對 BeanFactoryAware 類型的 bean 提供支持
  • 實現了基于 JDK 動態代理的 AOP
  • 整合了 IOC 和 AOP,使得二者可很好的協同工作
  • 在實現自己的 IOC 和 AOP 前,我的想法比較簡單,就是實現一個非常簡單的 IOC 和 AOP,哪怕是幾十行代碼實現的都行。后來實現后,感覺還很有意思的。不過那個實現太過于簡單,和 Spring IOC,AOP 相去甚遠。后來想了一下,不能僅滿足那個簡單的實現,于是就有了這個仿寫項目。相對來說仿寫的代碼要復雜了一些,功能也多了一點,看起來也有點樣子的。盡管仿寫出的項目仍然是玩具級,不過寫仿寫的過程中,還是學到了一些東西。總體上來說,收獲還是很大的。在接下來文章中,我也將從易到難,實現不同版本的 IOC 和 AOP。好了,不多說了,開始干活。

    ?2. 簡單的 IOC 和 AOP 實現

    ?2.1 簡單的 IOC

    先從簡單的 IOC 容器實現開始,最簡單的 IOC 容器只需4步即可實現,如下:

  • 加載 xml 配置文件,遍歷其中的標簽
  • 獲取標簽中的 id 和 class 屬性,加載 class 屬性對應的類,并創建 bean
  • 遍歷標簽中的標簽,獲取屬性值,并將屬性值填充到 bean 中
  • 將 bean 注冊到 bean 容器中
  • 如上所示,僅需4步即可,是不是覺得很簡單。好了,Talk is cheap, Show me the code. 接下來要上代碼了。不過客官別急,上代碼前,容我對代碼結構做一下簡單介紹:

    1 2 3 4 5 SimpleIOC // IOC 的實現類,實現了上面所說的4個步驟 SimpleIOCTest // IOC 的測試類 Car // IOC 測試使用的 bean Wheel // 同上 ioc.xml // bean 配置文件

    容器實現類 SimpleIOC 的代碼:

    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 public class SimpleIOC {private Map<String, Object> beanMap = new HashMap<>();public SimpleIOC(String location) throws Exception {loadBeans(location);}public Object getBean(String name) {Object bean = beanMap.get(name);if (bean == null) {throw new IllegalArgumentException("there is no bean with name " + name);}return bean;}private void loadBeans(String location) throws Exception {// 加載 xml 配置文件InputStream inputStream = new FileInputStream(location);DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();DocumentBuilder docBuilder = factory.newDocumentBuilder();Document doc = docBuilder.parse(inputStream);Element root = doc.getDocumentElement();NodeList nodes = root.getChildNodes();// 遍歷 <bean> 標簽for (int i = 0; i < nodes.getLength(); i++) {Node node = nodes.item(i);if (node instanceof Element) {Element ele = (Element) node;String id = ele.getAttribute("id");String className = ele.getAttribute("class");// 加載 beanClassClass beanClass = null;try {beanClass = Class.forName(className);} catch (ClassNotFoundException e) {e.printStackTrace();return;}// 創建 beanObject bean = beanClass.newInstance();// 遍歷 <property> 標簽NodeList propertyNodes = ele.getElementsByTagName("property");for (int j = 0; j < propertyNodes.getLength(); j++) {Node propertyNode = propertyNodes.item(j);if (propertyNode instanceof Element) {Element propertyElement = (Element) propertyNode;String name = propertyElement.getAttribute("name");String value = propertyElement.getAttribute("value");// 利用反射將 bean 相關字段訪問權限設為可訪問Field declaredField = bean.getClass().getDeclaredField(name);declaredField.setAccessible(true);if (value != null && value.length() > 0) {// 將屬性值填充到相關字段中declaredField.set(bean, value);} else {String ref = propertyElement.getAttribute("ref");if (ref == null || ref.length() == 0) {throw new IllegalArgumentException("ref config error");}// 將引用填充到相關字段中declaredField.set(bean, getBean(ref));}// 將 bean 注冊到 bean 容器中registerBean(id, bean);}}}}}private void registerBean(String id, Object bean) {beanMap.put(id, bean);} }

    容器測試使用的 bean 代碼:

    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public class Car {private String name;private String length;private String width;private String height;private Wheel wheel;// 省略其他不重要代碼 }public class Wheel {private String brand;private String specification ;// 省略其他不重要代碼 }

    bean 配置文件 ioc.xml 內容:

    1 2 3 4 5 6 7 8 9 10 11 12 13 14 <beans><bean id="wheel" class="com.titizz.simulation.toyspring.Wheel"><property name="brand" value="Michelin" /><property name="specification" value="265/60 R18" /></bean><bean id="car" class="com.titizz.simulation.toyspring.Car"><property name="name" value="Mercedes Benz G 500"/><property name="length" value="4717mm"/><property name="width" value="1855mm"/><property name="height" value="1949mm"/><property name="wheel" ref="wheel"/></bean> </beans>

    IOC 測試類 SimpleIOCTest:

    1 2 3 4 5 6 7 8 9 10 11 public class SimpleIOCTest {@Testpublic void getBean() throws Exception {String location = SimpleIOC.class.getClassLoader().getResource("spring-test.xml").getFile();SimpleIOC bf = new SimpleIOC(location);Wheel wheel = (Wheel) bf.getBean("wheel");System.out.println(wheel);Car car = (Car) bf.getBean("car");System.out.println(car);} }

    測試結果:

    以上是簡單 IOC 實現的全部內容,難度不大,代碼也不難看懂,這里不再多說了。下面說說簡單 AOP 的實現。

    ?2.2 簡單的 AOP 實現

    AOP 的實現是基于代理模式的,這一點相信大家應該都知道。代理模式是AOP實現的基礎,代理模式不難理解,這里就不花篇幅介紹了。在介紹 AOP 的實現步驟之前,先引入 Spring AOP 中的一些概念,接下來我們會用到這些概念。

    通知(Advice)

    1 2 3 4 5 6 7 通知定義了要織入目標對象的邏輯,以及執行時機。 Spring 中對應了 5 種不同類型的通知: · 前置通知(Before):在目標方法執行前,執行通知 · 后置通知(After):在目標方法執行后,執行通知,此時不關系目標方法返回的結果是什么 · 返回通知(After-returning):在目標方法執行后,執行通知 · 異常通知(After-throwing):在目標方法拋出異常后執行通知 · 環繞通知(Around): 目標方法被通知包裹,通知在目標方法執行前和執行后都被會調用

    切點(Pointcut)

    1 2 如果說通知定義了在何時執行通知,那么切點就定義了在何處執行通知。所以切點的作用就是 通過匹配規則查找合適的連接點(Joinpoint),AOP 會在這些連接點上織入通知。

    切面(Aspect)

    1 切面包含了通知和切點,通知和切點共同定義了切面是什么,在何時,何處執行切面邏輯。

    說完概念,接下來我們來說說簡單 AOP 實現的步驟。這里 AOP 是基于 JDK 動態代理實現的,只需3步即可完成:

  • 定義一個包含切面邏輯的對象,這里假設叫 logMethodInvocation
  • 定義一個 Advice 對象(實現了 InvocationHandler 接口),并將上面的 logMethodInvocation 和 目標對象傳入
  • 將上面的 Adivce 對象和目標對象傳給 JDK 動態代理方法,為目標對象生成代理
  • 上面步驟比較簡單,不過在實現過程中,還是有一些難度的,這里要引入一些輔助接口才能實現。接下來就來介紹一下簡單 AOP 的代碼結構:

    1 2 3 4 5 6 7 MethodInvocation 接口 // 實現類包含了切面邏輯,如上面的 logMethodInvocation Advice 接口 // 繼承了 InvocationHandler 接口 BeforeAdvice 類 // 實現了 Advice 接口,是一個前置通知 SimpleAOP 類 // 生成代理類 SimpleAOPTest // SimpleAOP 從測試類 HelloService 接口 // 目標對象接口 HelloServiceImpl // 目標對象

    MethodInvocation 接口代碼:

    1 2 3 public interface MethodInvocation {void invoke(); }

    Advice 接口代碼:

    1 public interface Advice extends InvocationHandler {}

    BeforeAdvice 實現代碼:

    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public class BeforeAdvice implements Advice {private Object bean;private MethodInvocation methodInvocation;public BeforeAdvice(Object bean, MethodInvocation methodInvocation) {this.bean = bean;this.methodInvocation = methodInvocation;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// 在目標方法執行前調用通知methodInvocation.invoke();return method.invoke(bean, args);} }

    SimpleAOP 實現代碼:

    1 2 3 4 5 6 public class SimpleAOP {public static Object getProxy(Object bean, Advice advice) {return Proxy.newProxyInstance(SimpleAOP.class.getClassLoader(), bean.getClass().getInterfaces(), advice);} }

    HelloService 接口,及其實現類代碼:

    1 2 3 4 5 6 7 8 9 10 public interface HelloService {void sayHelloWorld(); }public class HelloServiceImpl implements HelloService {@Overridepublic void sayHelloWorld() {System.out.println("hello world!");} }

    SimpleAOPTest 代碼:

    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public class SimpleAOPTest {@Testpublic void getProxy() throws Exception {// 1. 創建一個 MethodInvocation 實現類MethodInvocation logTask = () -> System.out.println("log task start");HelloServiceImpl helloServiceImpl = new HelloServiceImpl();// 2. 創建一個 AdviceAdvice beforeAdvice = new BeforeAdvice(helloServiceImpl, logTask);// 3. 為目標對象生成代理HelloService helloServiceImplProxy = (HelloService) SimpleAOP.getProxy(helloServiceImpl,beforeAdvice);helloServiceImplProxy.sayHelloWorld();} }

    輸出結果:

    以上實現了簡單的 IOC 和 AOP,不過實現的 IOC 和 AOP 還很簡單,且只能獨立運行。在下一篇文章中,我將實現一個較為復雜的 IOC 和 AOP,大家如果有興趣可以去看看。好了,本篇文章到此結束。

    ?附錄:Spring 源碼分析文章列表

    ?Ⅰ. IOC

    更新時間標題
    2018-05-30Spring IOC 容器源碼分析系列文章導讀
    2018-06-01Spring IOC 容器源碼分析 - 獲取單例 bean
    2018-06-04Spring IOC 容器源碼分析 - 創建單例 bean 的過程
    2018-06-06Spring IOC 容器源碼分析 - 創建原始 bean 對象
    2018-06-08Spring IOC 容器源碼分析 - 循環依賴的解決辦法
    2018-06-11Spring IOC 容器源碼分析 - 填充屬性到 bean 原始對象
    2018-06-11Spring IOC 容器源碼分析 - 余下的初始化工作

    ?Ⅱ. AOP

    更新時間標題
    2018-06-17Spring AOP 源碼分析系列文章導讀
    2018-06-20Spring AOP 源碼分析 - 篩選合適的通知器
    2018-06-20Spring AOP 源碼分析 - 創建代理對象
    2018-06-22Spring AOP 源碼分析 - 攔截器鏈的執行過程

    ?Ⅲ. MVC

    更新時間標題
    2018-06-29Spring MVC 原理探秘 - 一個請求的旅行過程
    2018-06-30Spring MVC 原理探秘 - 容器的創建過程
    • 本文鏈接:?https://www.tianxiaobo.com/2018/01/18/自己動手實現的-Spring-IOC-和-AOP-上篇/

    from:http://www.tianxiaobo.com/2018/01/18/%E8%87%AA%E5%B7%B1%E5%8A%A8%E6%89%8B%E5%AE%9E%E7%8E%B0%E7%9A%84-Spring-IOC-%E5%92%8C-AOP-%E4%B8%8A%E7%AF%87/?

    總結

    以上是生活随笔為你收集整理的自己动手实现的 Spring IOC 和 AOP - 上篇的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: free性欧美hd精品4k | 欧美bbbbbbbbbbbb1| 五级黄高潮片90分钟视频 | 亚洲mv一区 | 日本午夜激情 | 麻豆传媒网站入口 | 影音先锋在线看片资源 | 亚洲视频在线观看一区二区三区 | 黑人vs亚洲人在线播放 | juliaannxxxxx高清 黄页网站在线播放 | 亚洲综合一二三区 | 乱中年女人伦 | 人人妻人人澡人人爽精品欧美一区 | 涩涩涩涩涩涩涩涩涩 | 香蕉影音 | 亚洲欧美日本在线 | 超碰在| 国产亚洲精品美女久久久久 | 四虎永久网址 | 亚洲丝袜色图 | 国产精品揄拍100视频 | 美女隐私免费看 | 欧美午夜精品理论片a级按摩 | 9i在线看片成人免费 | 伊人久久久久久久久久久久久 | 国产99久久| 久久视频在线 | 人人妻人人澡人人爽国产一区 | 亚洲精品 日韩无码 | 亚洲爆乳无码一区二区三区 | 一区二区三区网 | 久在线 | 亚洲一二三区视频 | 日日日日日日 | 91蜜桃网| 国产天堂一区 | 国产精品va无码一区二区三区 | 国产日韩欧美 | 97在线观看免费视频 | 国产免费视频一区二区三区 | 国产精品久久久久三级 | 韩国日本在线观看 | 骚虎视频最新网址 | 日本人妖xxxx| 免费黄色大片网站 | 久久久久久黄色片 | 国产免费专区 | 午夜色播 | 黄瓜视频在线观看 | jzzjzz日本丰满少妇 | 高清欧美性猛交 | 短视频在线观看 | 日本在线www | 高跟鞋av | 国产91一区二区三区 | xxx麻豆| 人人干人人干 | 丰满少妇被猛烈进入高清播放 | 中文字幕国产在线观看 | 午夜视频一区二区 | 国产区一区二区 | 亚洲综合在线观看视频 | xxxxwwww在线观看 | 激情在线网站 | 女人张开腿让男人桶爽 | 韩国日本美国免费毛片 | 少妇一级淫片免费放2 | 中文字幕一区二区三区乱码人妻 | 精品成人无码一区二区三区 | 在线视频在线观看 | 欧美性爱精品在线 | 欧美区二区三区 | 天天干,天天操,天天射 | 精品夜夜澡人妻无码av | 亚洲妇女av| 欧美一级录像 | 中文字幕女同女同女同 | 极品色综合 | 黄色短视频在线播放 | 欧美极品少妇xxxxⅹ免费视频 | 好av在线| 狠狠撸狠狠干 | 麻豆影视在线观看 | 五月婷婷一区二区 | 久久尤物 | 日韩欧美资源 | 91高清免费 | 免费的理伦片在线播放 | 色屁屁www影院免费观看入口 | 国产做受网站 | 无码成人精品区一级毛片 | 欧美日韩高清在线播放 | 三级免费看 | 婷婷射 | 日韩电影一区二区在线观看 | 中文字幕久久精品 | 国产精品色呦呦 | www.97色| 日韩亚洲国产欧美 |