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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

手写简版spring --3--对象实例化策略

發布時間:2025/3/15 编程问答 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 手写简版spring --3--对象实例化策略 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一、目標

這一章節的目標主要是為了解決上一章節我們埋下的坑,那是什么坑呢?其實就是一個關于 Bean 對象在含有構造函數進行實例化的坑。在上一章節我們擴充了 Bean 容器的功能,把實例化對象交給容器來統一處理,但在我們實例化對象的代碼里并沒有考慮對象類是否含構造函數,也就是說如果我們去實例化一個含有構造函數的對象那么就要拋異常了。怎么驗證?其實就是把 UserService 添加一個含入參信息的構造函數就可以。

  • 驗證
public class UserService {private String name;public void queryUserInfo(){System.out.println("查詢用戶信息");}public UserService(String name) { this.name = name; } }


發生這一現象的主要原因就是因為 beanDefinition.getBeanClass().newInstance(); 實例化方式并沒有考慮構造函數的入參,所以就這個坑就在這等著你了!那么我們的目標就很明顯了,來把這個坑填平!

二、設計

填平這個坑的技術設計主要考慮兩部分

  • 一個是串流程從哪合理的把構造函數的入參信息傳遞到實例化操作里
  • 另外一個是怎么去實例化含有構造函數的對象。
  • 參考 Spring Bean 容器源碼的實現方式,在 BeanFactory 中添加 Object getBean(String name, Object... args) 接口,這樣就可以在獲取 Bean 時把構造函數的入參信息傳遞進去了。
  • 另外一個核心的內容是使用什么方式來創建含有構造函數的 Bean 對象呢?這里有兩種方式可以選擇,一個是基于 Java 本身自帶的方法DeclaredConstructor,另外一個是使用 Cglib 來動態創建 Bean 對象。 Cglib 是基于字節碼框架 ASM 實現,所以你也可以直接通過 ASM 操作指令碼來 創建對象

關于代理的文章

三、實現

  • 工程結構
  • 類依賴圖
  • 相比于第二章的類依賴圖,主要變化:

    • 在現有工程中添加 InstantiationStrategy 實例化策略接口
    • 以及在BeanFactory接口中補充相應的 getBean 入參信息,讓外部調用時可以傳遞構造函數的入參并順利實例化。
    • BeanFactory
    //BeanFactory中我們重載了一個含有入參信息 args 的 getBean 方法,這樣就可以方便的傳遞入參給構造函數實例化了 public interface BeanFactory {Object getBean(String name) throws BeansException;Object getBean(String name, Object... args) throws BeansException; }
    • 定義實例化策略接口
    //在實例化接口 instantiate 方法中添加必要的入參信息,包括:beanDefinition、beanName、ctor、args //其中 Constructor 你可能會有一點陌生,它是 java.lang.reflect 包下的Constructor 類,里面包含了一些必要的類信息,有這個參數的目的就是為了拿到符合入參信息相對應的構造函數。 //而 args 就是一個具體的入參信息了,最終實例化時候會用到。 public interface InstantiationStrategy {Object instantiate(BeanDefinition beanDefinition, String beanName, Constructor ctor, Object[] args) throws BeansException; }
    • 實例化(使用上面提到的兩種方式)

    JDK方式:

    public class SimpleInstantiationStrategy implements InstantiationStrategy {@Overridepublic Object instantiate(BeanDefinition beanDefinition, String beanName, Constructor ctor, Object[] args) throws BeansException {Class clazz = beanDefinition.getBeanClass();try {if (null != ctor) {return clazz.getDeclaredConstructor(ctor.getParameterTypes()).newInstance(args);} else {return clazz.getDeclaredConstructor().newInstance();}} catch (NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e) {throw new BeansException("Failed to instantiate [" + clazz.getName() + "]", e);}} }
    • 首先通過 beanDefinition 獲取 Class 信息,這個 Class 信息是在 Bean 定義的時候傳遞進去的。
    • 接下來判斷 ctor 是否為空,如果為空則是無構造函數實例化,否則就是需要有構造函數的實例化。
    • 這里我們重點關注有構造函數的實例化,實例化方式為clazz.getDeclaredConstructor(ctor.getParameterTypes()).ne wInstance(args);把入參信息傳遞給 newInstance 進行實例化。

    CGLIB方式:

    public class CglibSubclassingInstantiationStrategy implements InstantiationStrategy {@Overridepublic Object instantiate(BeanDefinition beanDefinition, String beanName, Constructor ctor, Object[] args) throws BeansException {Enhancer enhancer = new Enhancer();enhancer.setSuperclass(beanDefinition.getBeanClass());enhancer.setCallback(new NoOp() {@Overridepublic int hashCode() {return super.hashCode();}});if (null == ctor) return enhancer.create();return enhancer.create(ctor.getParameterTypes(), args);} }
  • 創建策略調用
  • public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory {private InstantiationStrategy instantiationStrategy = new CglibSubclassingInstantiationStrategy();@Overrideprotected Object createBean(String beanName, BeanDefinition beanDefinition, Object[] args) throws BeansException {Object bean = null;try {bean = createBeanInstance(beanDefinition, beanName, args);} catch (Exception e) {throw new BeansException("Instantiation of bean failed", e);}addSingleton(beanName, bean);return bean;}protected Object createBeanInstance(BeanDefinition beanDefinition, String beanName, Object[] args) {Constructor constructorToUse = null;Class<?> beanClass = beanDefinition.getBeanClass();Constructor<?>[] declaredConstructors = beanClass.getDeclaredConstructors();for (Constructor ctor : declaredConstructors) {if (null != args && ctor.getParameterTypes().length == args.length) {constructorToUse = ctor;break;}}return getInstantiationStrategy().instantiate(beanDefinition, beanName, constructorToUse, args);}public InstantiationStrategy getInstantiationStrategy() {return instantiationStrategy;}public void setInstantiationStrategy(InstantiationStrategy instantiationStrategy) {ths.instantiationStrategy = instantiationStrategy;} }
    • 首先在 AbstractAutowireCapableBeanFactory 抽象類中定義了一個創建對象的實例化策略屬性類 InstantiationStrategy instantiationStrategy,這里我們選擇了 Cglib 的實現類。
    • 接下來抽取 createBeanInstance 方法,在這個方法中需要注意 Constructor代表了你有多少個構造函數,通過 beanClass.getDeclaredConstructors() 方式可以獲取到你所有的構造函數,是一個集合。
    • 接下來就需要循環比對出構造函數集合與入參信息 args 的匹配情況,這里我們對比的方式比較簡單,只是一個數量對比,而實際 Spring 源碼中還需要比對入參類型,否則相同數量不同入參類型的情況,就會拋異常了。
  • 測試
  • @Testpublic void test_BeanFactory() {// 1.初始化 BeanFactoryDefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();// 2. 注入beanBeanDefinition beanDefinition = new BeanDefinition(UserService.class);beanFactory.registerBeanDefinition("userService", beanDefinition);// 3.獲取beanUserService userService = (UserService) beanFactory.getBean("userService", "小傅哥");userService.queryUserInfo();}

    四、總結

    • 本章節的主要以完善實例化操作,增加 InstantiationStrategy 實例化策略接口,并新增了兩個實例化類。這部分類的名稱與實現方式基本是 Spring 框架的一個縮小版,大家在學習過程中也可以從 Spring 源碼找到對應的代碼。
    • 從我們不斷的完善增加需求可以看到的,當你的代碼結構設計的較為合理的時候,就可以非常容易且方便的進行擴展不同屬性的類職責,而不會因為需求的增加導致類結構混亂。所以在我們自己業務需求實現的過程中,也要盡可能的去考慮一個良 好的擴展性以及拆分好類的職責。
    與50位技術專家面對面20年技術見證,附贈技術全景圖

    總結

    以上是生活随笔為你收集整理的手写简版spring --3--对象实例化策略的全部內容,希望文章能夠幫你解決所遇到的問題。

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