Spring依赖注入 --- 模拟实现

时间:2023-03-08 17:46:38

Spring依赖注入 --- 模拟实现

面向接口编程,又称面向抽象编程,

数据库如果发生更改,对应的数据访问层也应该改变
多写几个实现,需要用谁的时候在service里new谁就可以了
面向抽象编程的好处就是灵活。

创建用户实体类,

/ImitateSpring/src/yuki/spring/imitate/pojo/User.java

package yuki.spring.imitate.pojo;

public class User {

    private String username;
    private String password;

    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }

}

/ImitateSpring/src/yuki/spring/imitate/service/UserService.java

package yuki.spring.imitate.service;

import yuki.spring.imitate.dao.UserDAO;
import yuki.spring.imitate.pojo.User;

public class UserService {

    private UserDAO userDAO/* = new UserDAOImpl()*/;

    public UserDAO getUserDAO() {
        return userDAO;
    }
    public void setUserDAO(UserDAO userDAO) {
        this.userDAO = userDAO;
    }

    public void add(User u){
        this.userDAO.save(u);
    }
}

/ImitateSpring/src/yuki/spring/imitate/dao/UserDAO.java

package yuki.spring.imitate.dao;

import yuki.spring.imitate.pojo.User;

/*public class UserDAO {

    public void save(User u){
        System.out.println("user saved...");
    }
}*/

public interface UserDAO {
    void save(User u);
}

/ImitateSpring/src/yuki/spring/imitate/dao/impl/UserDAOImpl.java

package yuki.spring.imitate.dao.impl;

import yuki.spring.imitate.dao.UserDAO;
import yuki.spring.imitate.pojo.User;

public class UserDAOImpl implements UserDAO {

    @Override
    public void save(User u) {
        System.out.println("user saved...");
    }
}

之前的new很多DAO的解决方式是写工厂方法
现在,要新建一个总的工厂,把消息写在工厂文件中
用jdom解析xml,反射创建对象

引入jar包,jdom-2.0.5.jar

/ImitateSpring/src/yuki/spring/imitate/xml/test.xml

<?xml version="1.0" encoding="UTF-8"?>
<HD>
    <disk name="C">
        <capacity>8G</capacity>
        <directories>200</directories>
        <files>1580</files>
    </disk>
    <disk name="D">
        <capacity>10G</capacity>
        <directories>500</directories>
        <files>3000</files>
    </disk>
</HD>

/ImitateSpring/src/yuki/spring/imitate/spring/ClassPathXmlApplicationContext.java

package yuki.spring.imitate.xml;

import java.util.List;

import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.input.SAXBuilder;

public class Sample1 {

    public static void main(String[] args) throws Exception {
        SAXBuilder saxBuilder = new SAXBuilder();
        Document document = saxBuilder.build(
                /*Sample1.class.getClassLoader().getResourceAsStream("/text.xml")*/
                "D:/Workspaces/Eclipse/ImitateSpring/bin/yuki/spring/imitate/xml/test.xml");
        Element root = document.getRootElement();
        List<Element> elements = root.getChildren();
        for(Element element : elements){
            String name = element.getAttributeValue("name");
            String capacity = element.getChildText("capacity");
            String directories = element.getChildText("directories");
            String files = element.getChildText("files");
            System.out.println("磁盘信息:");
            System.out.println("分区盘符:" + name);
            System.out.println("分区容量:" + capacity);
            System.out.println("目录数:" + directories);
            System.out.println("文件数:" + files);
            System.out.println("------------------------------");
        }

    }
}

运行结果如下:

磁盘信息:
分区盘符:C
分区容量:8G
目录数:200
文件数:1580
------------------------------
磁盘信息:
分区盘符:D
分区容量:10G
目录数:500
文件数:3000
------------------------------

可以把bean作为另一个bean的属性注入

/ImitateSpring/src/beans.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans>
    <bean id="u" class="yuki.spring.imitate.dao.impl.UserDAOImpl"></bean>

    <bean id="userService" class="yuki.spring.imitate.service.UserService">
        <property name="userDAO" bean="u"></property>
    </bean>

</beans>

/ImitateSpring/src/yuki/spring/imitate/spring/BeanFactory.java

package yuki.spring.imitate.spring;

public interface BeanFactory {
    Object getBean(String name);
}

/ImitateSpring/src/yuki/spring/imitate/spring/ClassPathXmlApplicationContext.java

package yuki.spring.imitate.spring;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.input.SAXBuilder;

public class ClassPathXmlApplicationContext implements BeanFactory {

    private Map<String, Object> beans = new HashMap<String, Object>();

    public ClassPathXmlApplicationContext() throws Exception {
        SAXBuilder saxBuilder = new SAXBuilder();
        Document document = saxBuilder.build(
                "D:/Workspaces/Eclipse/ImitateSpring/bin/beans.xml");
        Element root = document.getRootElement();
        List<Element> elements = root.getChildren();
        for(Element element : elements){
            String id = element.getAttributeValue("id");
            String clazz = element.getAttributeValue("class");
            System.out.println(id + " : " + clazz);
            Object o = Class.forName(clazz).newInstance();
            beans.put(id, o);

            for(Element propertyElement : element.getChildren("property")){
                String name = propertyElement.getAttributeValue("name");
                String bean = propertyElement.getAttributeValue("bean");
                Object beanObject = beans.get(bean);

                String methodName = "set" + name.substring(0, 1).toUpperCase() + name.substring(1);
                System.out.println("method name = " + methodName);

                Method m = o.getClass().getMethod(methodName, beanObject.getClass().getInterfaces()[0]);
                m.invoke(o, beanObject);
            }
        }
    }

    @Override
    public Object getBean(String name){
        return beans.get(name);
    }
}

通过JUnit,可以新建测试类

Spring依赖注入 --- 模拟实现

/ImitateSpring/test/yuki/spring/imitate/service/UserServiceTest.java

package yuki.spring.imitate.service;

import org.junit.Test;

import yuki.spring.imitate.pojo.User;
import yuki.spring.imitate.spring.BeanFactory;
import yuki.spring.imitate.spring.ClassPathXmlApplicationContext;

public class UserServiceTest {

    @Test
    public void testAdd() throws Exception {
        BeanFactory factory = new ClassPathXmlApplicationContext();
        UserService service = (UserService) factory.getBean("userService");
        /*UserDAO userDAO = (UserDAO) factory.getBean("u");
        service.setUserDAO(userDAO);*/
        User u = new User();
        service.add(u);
    }

}

运行结果如下:

u : yuki.spring.imitate.dao.impl.UserDAOImpl
userService : yuki.spring.imitate.service.UserService
method name = setUserDAO
user saved...

术语解释:

控制反转(IOC)、依赖注入(DI)
本来应该自己控制的,交给容器控制,可以实现随意装配

本文参考了[尚学堂马士兵_Spring_模拟Spring]的公开课程

更多好文请关注:http://www.cnblogs.com/kodoyang/