久久精品国产一区二区电影,久久精品国产亚洲av瑜伽,精品无人区一码卡二卡三,久草热8精品视频在线观看 ,久久99精品久久久久麻豆

錘子簡歷品牌推廣師
面試官:擼一個IOC框架,真的很難嗎?
作者:錘子簡歷 2020/03/17 12:00:02
閱讀 106

最近,一些同學參加遠程面試,被問到Spring IOC相關的話題,由于理解的不是太深,面試被gg了,因此,寫下該篇文章,希望能夠幫助到正在找工作的同學。


Spring框架中最經典的兩個就是IOC和AOP,其中IOC(Inversion of Control)是什么呢?控制反轉,簡單來說就是將控制實體Bean的動作交給了Spring容器進行管理。再簡單點來說就是例如之前想用一個類,必須new一個,但是使用了Spring那么直接用@Autowired注解或者用xml配置的方式就能直接獲得此對象,而且你也不用管它的生命周期啊等等之類的。就不用自己new一個對象了。

簡歷模板

如果是之前沒有使用IOC的話,那么這些對象的創(chuàng)建以及賦值都是由我們自己創(chuàng)建了,下面簡單的演示了如果有上面四個對象依賴的話,那么沒有IOC我們必須要創(chuàng)建對象并且賦值。僅僅四個對象就這么多,那么一旦項目大了,對象成百上千,如果還這樣寫的話,那么絕對是一場災難。


對象A a = new 對象A();
對象B b = new 對象B();
對象C c = new 對象C();
對象D d = new 對象D();
a.setB(b);
a.setC(c);
b.setD(d);
c.setD(d);


因此在Spring中通過IOC將所有的對象統(tǒng)一放到Spring的容器中進行管理,所以就簡單了很多。上面的實例化對象的代碼也不需要我們寫了。



上面說了那么多,其實就是一句話IOC非常重要,但是如果直接看Spring源碼的話會非常懵逼,所以就簡單的寫一個IOC的小例子來理解這種思想。


# 分析并編寫代碼


還是編寫代碼前的分析階段,Spring的IOC其實就是將所有的Bean放在統(tǒng)一容器中進行管理起來,然后在在獲取的時候進行初始化,所以需要我們在程序啟動的時候將被標記的類進行存儲在自定義的容器中管理。


  • 初始化階段:將被@MyIoc類似于Spring中@Service標記的類放入到自定義的容器中。

  • 使用:通過自定義的獲取Bean的類進行統(tǒng)一獲取。


現(xiàn)在我們就以上面兩個步驟進行詳細點的分析


數(shù)據(jù)準備階段


首先初始化階段我們要先建立兩個注解類用于類的發(fā)現(xiàn)(@MyIoc類似于


@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyIoc {

}


然后要初始化信息進自定義容器的話用什么類型的容器去存儲這些信息呢?這里可以想到是用Map來存,用key為類名,value用什么呢?value就是要放在容器中進行管理的類的信息了,那么一個類有什么信息呢即類是由什么組成呢?有以下幾個信息


  • 類名

  • 構造函數(shù)

  • 屬性值

  • 父類


所以根據(jù)上面的分析我們可以建立一個實體類來存儲這些信息,此時我們就不考慮復雜的構造函數(shù)了,就都是初始化的無參構造函數(shù)。然后父類的屬性就不進行分析注入了。所以此時類實體類就簡單了。


@Data
public class BeanDefinition {
    private String className;
    private String alias;
    private String superNames;
}


初始化階段


有了存儲類信息的類了,那么我們在程序啟動的時候就應該將這些信息給加載到Map中,此時建立一個啟動類用于初始化被@MyIoc標記的類的信息。


@Component
@Order(value = 1)
public class IoCInitConifg implements CommandLineRunner{

    @Override
    public void run(String... args){
        ConcurrentHashMap<String,BeanDefinition> concurrentHashMap = new ConcurrentHashMap<>();
        Reflections reflections = new Reflections();
        //獲得項目中所有被MyIoc標記得類
        Set<Class<?>> typesAnnotatedWith = reflections.getTypesAnnotatedWith(MyIoc.class);
        //將其信息初始進自定義容器MyBeanFactory中
        for (Class clazz : typesAnnotatedWith){
            BeanDefinition beanDefinition = new BeanDefinition();
            String className = clazz.getName();
            String superclassName = clazz.getSuperclass().getName();
            beanDefinition.setClassName(className);
            beanDefinition.setSuperNames(superclassName);
            beanDefinition.setAlias(getClassName(className));
            concurrentHashMap.put(className,beanDefinition);
        }
        MyBeanFactoryImpl.setBeanDineMap(concurrentHashMap);
    }

    private String getClassName(String beanClassName) {
        String className = beanClassName.substring(beanClassName.lastIndexOf(".") + 1);
        className = className.substring(01).toLowerCase() + className.substring(1);
        return className;
    }
}


此時得說一下自定義的統(tǒng)一容器管理的類MyBeanFactory此類用作統(tǒng)一獲得類的途徑


public interface MyBeanFactory {

    Object getBeanByName(String name) throws Exception;
}


此時還有其實現(xiàn)類


@Log4j
public class MyBeanFactoryImpl implements MyBeanFactory{
    //存儲對象名稱和已經實例化的對象映射
    private static ConcurrentHashMap<String,Object> beanMap = new ConcurrentHashMap<>();
    //存儲對象名稱和對應對象信息的映射
    private static ConcurrentHashMap<String,BeanDefinition> beanDefineMap= new ConcurrentHashMap<>();
    //存儲存儲在容器中對象的名稱
    private static Set<String> beanNameSet = Collections.synchronizedSet(new HashSet<>());

    @Override
    public Object getBeanByName(String name) throws Exception 
{
        //看有沒有已經實例化的對象,有的話就直接返回
        Object object = beanMap.get(name);
        if (object != null){
            return object;
        }
        //沒有的話就實例化一個對象
        object = getObject(beanDefineMap.get(name));
        if (object != null){
            //對實例化中對象的注入需要的參數(shù)
            setFild(object);
            //將實例化的對象放入Map中,便于下次使用
            beanMap.put(name,object);
        }
        return object;
    }

    public void setFild(Object bean) throws Exception {
        Field[] declaredFields = bean.getClass().getDeclaredFields();
        for (Field field: declaredFields){
            String filedAllName = field.getType().getName();
            if (beanNameSet.contains(filedAllName)){
                Object findBean = getBeanByName(filedAllName);
                //為對象中的屬性賦值
                field.setAccessible(true);
                field.set(bean,findBean);
            }
        }
    }

    public Object getObject(BeanDefinition beanDefinition) throws Exception {
        String className = beanDefinition.getClassName();
        Class<?> clazz = null;
        try {
            clazz = Class.forName(className);
        } catch (ClassNotFoundException e) {
            log.info("can not find bean by beanName: "+className);
            throw new Exception("can not find bean by beanName: "+className);
        }
        return clazz;
    }

    public static void setBeanDineMap(ConcurrentHashMap<String,BeanDefinition> beanDefineMap){
        MyBeanFactoryImpl.beanDefineMap = beanDefineMap;
    }

    public static void setBeanNameSet(Set<String> beanNameSet){
        MyBeanFactoryImpl.beanNameSet = beanNameSet;
    }

}


此時初始化的階段已經完成了,即已經將所有被@MyIoc標記的類已經被全部存放在了自定義的容器中了。其實在這里我們已經能使用自己的自定義的容器進行獲得Bean了。


@MyIoc
@Data
public class User {
    private Student student;
}


@MyIoc
public class Student {
    public String play(){
        return "student"this.toString();
    }
}


此時我們在啟動類中寫如下


        User user1 = (User)beanFactory.getBeanByName("com.example.ioc.domain.User");
        User user2 = (User)beanFactory.getBeanByName("com.example.ioc.domain.User");
        Student student1 = user1.getStudent();
        Student student2 = user1.getStudent();
        Student student3 = (Student)beanFactory.getBeanByName("com.example.ioc.domain.Student");
        System.out.println(user1);
        System.out.println(user2);
        System.out.println(student1);
        System.out.println(student2);
        System.out.println(student3);


發(fā)現(xiàn)控制臺中輸出的對象都是同一個對象,并且在User中也自動注入了Student對象。此時一個簡單的IOC就完成了。


User(student=com.example.ioc.domain.Student@705e7b93)
User(student=com.example.ioc.domain.Student@705e7b93)
com.example.ioc.domain.Student@705e7b93
com.example.ioc.domain.Student@705e7b93
com.example.ioc.domain.Student@705e7b93


# 總結


本來一開始的想法的是想要寫一個類似于@Autowired注解的自定義注解,但是在編碼過程中遇到了一個困難,就是例如下面的代碼,實例化B容易,但是如何將B注入到每一個實例化的A中,這個問題困擾了我好幾天,也查找了許多的資料,至今還是沒有解決,估計是只有研究Spring源碼才能夠了解是如何做到的。


@MyIoc
public class A{

@MyIocUse
private B b;

}


內容來源說明:本文章來自網(wǎng)絡收集,如侵犯了你的權益,請聯(lián)系QQ:2772182309進行刪除。