天天看點

springIOC簡單模拟實作-----XML方式

springIOC簡單模拟實作-----XML方式和注解方式

為了看懂spring底層代碼結構,模拟完成了一個依賴注入的小例子,僅供自己更好的了解springIoc。

XML方式

1、建立一個dao接口和對應的兩個實作類。

public interface UserService {
    public void find();
}

public class UserDaoImpl implements UserDao {
    @Override
    public void query() {
        System.out.println("user");
    }
}

public class UserDaoImpl1 implements UserDao {
    @Override
    public void query() {
        System.out.println("user1");
    }
}
           

2、建立一個service接口和一個實作類,調用dao接口。

public class UserServiceImpl implements UserService {
    UserDao dao;
    TestDao test;
    /*public UserServiceImpl(UserDao dao){//構造方法注入時使用
        this.dao = dao;
    }
*/
    @Override
    public void find() {
        System.out.println("service");
        dao.query();
        test.query();
    }
    /*public void setDao(UserDao dao) {//setter方法注入時使用
        this.dao = dao;
    }*/
}
           

3、建立一個xml配置檔案,提供需要維護的對象和對象之間的依賴關系。

<?xml version="1.0" encoding="UTF-8"?>
<beans default-autowire="byType"><!-- 自動裝配時使用 -->

    <!--<bean id="dao" class="com.spring.dao.UserDaoImpl"></bean>-->

    <bean id="dao1" class="com.spring.dao.UserDaoImpl1"></bean>

    <bean id="test" class="com.spring.dao.TestDaoImpl"></bean>

    <bean id="service" class="com.spring.service.UserServiceImpl">

        <!--setter方法注入-->
        <!--<property name="dao" ref="dao"></property>-->

        <!--構造方法注入-->
        <!--<constructor-arg name="dao" ref="dao"></constructor-arg>-->

    </bean>

</beans>
           

4、解析xml,建立對象并維護對象的依賴。(根據配置檔案中的要求實作)

public class BeanFactory {

    //對象名稱和類的對應關系
    Map<String,Object> map = new HashMap<String,Object>();

    public BeanFactory(String xml){
        parseXml(xml);
    }

    //解析xml中的映射關系
    private void parseXml(String xml){
        //讀取XML檔案
        File xmlFile = new File(this.getClass().getResource("/").getPath()+"//"+xml);
        SAXReader reader = new SAXReader();
        try {
            //獲得XML文檔
            Document document = reader.read(xmlFile);
            Element documentRoot = document.getRootElement();

            //是否自動裝配
            Attribute autowire = documentRoot.attribute("default-autowire");
            Boolean flag = false;
            if(autowire != null){
                flag = true;
            }

            //bean清單
            for (Iterator<Element> itFirst = documentRoot.elementIterator(); itFirst.hasNext();) {
                //建立對象

                Element elementFirst = itFirst.next();
                //對象名
                Attribute attributeId = elementFirst.attribute("id");
                String attributeIdName = attributeId.getValue();
                //對象
                Attribute attributeClass = elementFirst.attribute("class");
                String attributeClassName = attributeClass.getValue();
                Class objectClazz = Class.forName(attributeClassName);
                Object object = null;



                //維護對象的依賴關系
                for (Iterator<Element> itSecond = elementFirst.elementIterator(); itSecond.hasNext();) {

                    Element elementSecond = itSecond.next();
                    //用setter方法注入
                    if(elementSecond.getName().equals("property")){
                        //使用預設構造方法
                        object = objectClazz.newInstance();

                        //擷取ref屬性值
                        Attribute attributeRef = elementSecond.attribute("ref");
                        String refValue = attributeRef.getValue();
                        Object refObject = map.get(refValue);//根據ref值找到對應對象
                        //擷取name屬性值--對應對象中的set方法後面的值
                        Attribute attributeName = elementSecond.attribute("name");
                        String nameValue = attributeName.getValue();
                        Field field = objectClazz.getDeclaredField(nameValue);
                        //找不到對應方法
                        if(field == null){
                            throw new NyExecption("依賴在類中未被注入!");
                        }
                        field.setAccessible(true);//開啟屬性注入
                        field.set(object,refObject);
                    }else if(elementSecond.getName().equals("constructor-arg")){
                        //獲得依賴對象
                        String refValue = elementSecond.attribute("ref").getValue();
                        Object refObject = map.get(refValue);
                        //獲得構造參數需要的class
                        String nameValue = elementSecond.attribute("name").getValue();
                        Class fieldClazz = objectClazz.getDeclaredField(nameValue).getType();
                        //獲得構造對象
                        Constructor constructor = objectClazz.getConstructor(fieldClazz);
                        //使用特殊的構造方法
                        object = constructor.newInstance(refObject);
                    }else {
                        throw new NyExecption("配置檔案标簽錯誤,請修改。");
                    }


                }
                //沒有配置注入時使用自動裝配
                if(flag && object == null){
                    String autoType = autowire.getValue();
                    if(autoType.equals("byType")){//按類型裝配
                        //獲得對象
                        object = objectClazz.newInstance();
                        //判斷是否有依賴
                        Field[] fields = objectClazz.getDeclaredFields();
                        for (Field field : fields) {
                            //得到屬性的類型
                            Class injectClazz = field.getType();
                            /**
                             * 由於是bytype 是以需要周遊map當中的所有對象
                             * 判斷對象的類型是不是和這個injectObjectClazz相同
                             */
                            int count = 0;
                            Object injectObject = null;
                            for (String key : map.keySet()) {
                                Class injectObjectClazz = map.get(key).getClass().getInterfaces()[0];
                                if(injectObjectClazz.getName().equals(injectClazz.getName())){
                                    injectObject = map.get(key);
                                    //記錄找到一個,因為可能找到多個count
                                    count++;
                                }
                            }

                            if(count > 1){
                                throw new NyExecption("需要一個對象,但是找到了"+count+"個對象");
                            }else {//注入對象依賴
                                field.setAccessible(true);
                                field.set(object,injectObject);
                            }
                        }
                    }else if(autoType.equals("byName")){//按名稱裝配

                        //判斷是否有依賴
                        Field[] fields = objectClazz.getDeclaredFields();
                        object = objectClazz.newInstance();//獲得對象
                        for (Field field : fields) {
                            String injectName = field.getName();
                            Object injectObject = map.get(injectName);
                            //找不到注入的對象
                            if(injectObject == null){
                                throw new NyExecption("依賴的對象不存在!");
                            }
                            //對象注入屬性--依賴對象
                            field.setAccessible(true);
                            field.set(object,injectObject);
                        }

                    }
                }

                //沒有子标簽
                if(object == null){
                    object = objectClazz.newInstance();
                }

                map.put(attributeIdName,object);
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //擷取對應對象
    public Object getBean(String beanName){
        return map.get(beanName);
    }
}
           

5、測試類(根據不同情況進行修改測試)

public class Test {

    public static void main(String[] args) {

        BeanFactory beanFactory = new BeanFactory("spring.xml");

        UserService userService = (UserService) beanFactory.getBean("service");

        userService.find();

    }
}
           

注解方式

前兩步與第一種方法一樣。

3、自定義一個注解,用于标記掃描的類

@Retention(RetentionPolicy.RUNTIME)
public @interface MyService {

    public String value();

}
           

4、解析注解

public class MyAnnotationConfigApplicationContext {

    //對象名稱和類的對應關系
    Map<String,Object> map = new HashMap<String,Object>();

    public MyAnnotationConfigApplicationContext(String basePackage){
        Scan(basePackage);
    }

    public Object Scan(String basePackage){

        Object object = null;

        String rootPath = this.getClass().getResource("/").getPath();
        //将包路徑替換為/格式
        String basePackagePath = basePackage.replaceAll("\\.","\\\\");

        File file = new File(rootPath+"\\"+basePackagePath);
        String[] fileList = file.list();//擷取路徑下所有類

        for (String className : fileList) {
            try {
                className = className.substring(0,className.indexOf("."));
                //擷取class對象
                Class clazz = Class.forName(basePackage + "." + className);
                //隻掃描有MyService注解的類
                if (clazz.isAnnotationPresent(MyService.class)) {
                    //擷取注解中的value
                    MyService service = (MyService) clazz.getDeclaredAnnotation(MyService.class);
                    System.out.println(service.value());

                    //對象注入
                    object = clazz.newInstance();
                    System.out.println(object);

                    map.put(service.value(),object);
                }

            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        //檢查類中是否有需要自動注入的屬性
        //思路:1、建一個map存入上方注入的類名稱和class對象
        //2、檢查注入的對象中屬性是否有@Autowired注解或@Resource注解
        //3、如果有@Autowired注解按照屬性類型的class到map中找是否有對應類型進行注入,注意隻能有一個
        //4、如果有@Resource注解,取裡面的name屬性,到map中的key中找是否有對應的key,進行注入。
        if (!map.isEmpty()){
            //周遊對象進行依賴注入
            for (String name : map.keySet()) {
                Object injectObject = map.get(name);
                Class injectObjectClazz = injectObject.getClass();

                Object innerObject = null;
                //擷取所有屬性
                Field[] fields = injectObjectClazz.getDeclaredFields();
                if(fields.length > 0){
                    for (Field field : fields) {
                        //存在Autowired注解
                        if(field.isAnnotationPresent(Autowired.class)){
                            Class fieldClazz = field.getType();
                            int count = 0;
                            //周遊map找到對應class對象
                            for (String objName : map.keySet()) {
                                Class objClazz =  map.get(objName).getClass();
                                if(fieldClazz.getName().equals(objClazz.getInterfaces()[0].getName())){
                                    innerObject = map.get(objName);
                                    count++;
                                }
                            }
                            //判斷是否有比對的注入對象
                            if(count == 0){
                                throw new NyExecption("沒有找到屬性值比對的類型對象。");
                            }else if(count == 1){

                                try {
                                    field.setAccessible(true);
                                    field.set(injectObject,innerObject);
                                } catch (Exception e) {
                                    e.printStackTrace();
                                }
                            }else {
                                throw new NyExecption("需要一個對象,但是找到了"+count+"個對象");
                            }
                        }
                        //存在Resource注解
                        if(field.isAnnotationPresent(Resource.class)){
                            //擷取注解中的name
                            Resource resource = (Resource) field.getDeclaredAnnotation(Resource.class);
                            String daoName = resource.name();
                            //在map中找到對應class對象
                            Object fieldObject = map.get(daoName);
                            if(fieldObject == null){
                                throw new NyExecption("沒有找到屬性值比對的類型對象。");
                            }

                            try {
                                field.setAccessible(true);
                                field.set(injectObject,fieldObject);
                            } catch (Exception e) {
                                e.printStackTrace();
                            }
                        }
                    }
                }

            }
        }



        return object;
    }

    //擷取對應對象
    public Object getBean(String beanName){
        return map.get(beanName);
    }

}
           

5、測試類,根據不同情況調整代碼進行測試

public class Test {

    public static void main(String[] args) {

        MyAnnotationConfigApplicationContext context = new MyAnnotationConfigApplicationContext("com.spring.dao");

        TestDao testDao = (TestDao) context.getBean("testDaoImpl");

        testDao.query();
    }

}
           

以上就是簡易的SpringIoc實作小例子,需要根據不同情況就行調整測試,是新手了解springIoc的一個好方式。

上一篇: 寫入檔案