springIOC简单模拟实现-----XML方式

4 篇文章 0 订阅
2 篇文章 0 订阅

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的一个好方式。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值