SpringIOC随笔(二)-仿写SpringIOC

分手后的思念是犯贱 2022-12-16 14:24 327阅读 0赞

SpringIOC随笔(二)-仿写SpringIOC

思路:

  1. 定义一个beanFactor工厂接口,提供getBean方法,
  2. 实现工厂,定义一个Bean容器,Map,为了实现线程安全,使用private static Map<String, Object> beanMap = Collections.synchronizedMap(new HashMap<>());
  3. 初始化我们的bean容器,通过解析我们的xml配置文件//beans/bean创建出bean
  4. 初始化完成bean容器后我们需要将bean之间的关系装配好(注入)
  5. 然后实现getBean方法。

使用技术:dom4j解析xml,反射

代码:

  1. pom

    1. <dependencies>
    2. <dependency>
    3. <groupId>dom4j</groupId>
    4. <artifactId>dom4j</artifactId>
    5. <version>1.6.1</version>
    6. </dependency>
    7. <dependency>
    8. <groupId>jaxen</groupId>
    9. <artifactId>jaxen</artifactId>
    10. <version>1.1.6</version>
    11. </dependency>
    12. <dependency>
    13. <groupId>org.apache.commons</groupId>
    14. <artifactId>commons-lang3</artifactId>
    15. <version>3.4</version>
    16. </dependency>
    17. <dependency>
    18. <groupId>commons-collections</groupId>
    19. <artifactId>commons-collections</artifactId>
    20. <version>3.2.1</version>
    21. </dependency>
    22. <dependency>
    23. <groupId>junit</groupId>
    24. <artifactId>junit</artifactId>
    25. <version>4.12</version>
    26. <scope>test</scope>
    27. </dependency>
    28. </dependencies>
  2. applicationContext.xml

    1. <?xml version="1.0" encoding="UTF-8" ?>
    2. <beans>
    3. <bean id="userDaoHibernate" class="com.fxyh.spring.dao.impl.UserDaoHibernateImpl" />
    4. <bean id="userDaoMybatis" class="com.fxyh.spring.dao.impl.UserDaoMybatisImpl"/>
    5. <bean id="userService" class="com.fxyh.spring.service.impl.UserServiceImpl">
    6. <property name="userDao" ref="userDaoMybatis" />
    7. </bean>
    8. </beans>
  3. Dom4jUtils

    1. public class Dom4jUtils {
  1. /**
  2. * @Author fengzhaoquan
  3. * @Description 获取XML文档。其实就是将xml文档读取到内存中,形成DOM树
  4. * @Date
  5. * @Param
  6. * @return
  7. **/
  8. public static Document getDocument(String fileName){
  9. Document document = null;
  10. if(StringUtils.isBlank(fileName)){
  11. throw new IllegalArgumentException("");
  12. }
  13. try {
  14. SAXReader reader = new SAXReader();
  15. document = reader.read(Dom4jUtils.class.getClassLoader().getResourceAsStream(fileName));
  16. } catch (DocumentException e) {
  17. e.printStackTrace();
  18. }
  19. return document;
  20. }
  21. }
  1. BeanFactory接口

    1. public interface BeanFactory {
  1. /**
  2. * @Author fengzhaoquan
  3. * @Description 实现了该接口类型的对象
  4. * @Param clazz 接口类型的对象
  5. **/
  6. Object getBean(Class clazz);
  7. /**
  8. * @Author fengzhaoquan
  9. * @Description 获取className的对象(id)
  10. **/
  11. Object getBean(String className);
  12. }
  1. ClassPathXmlApplicationContext实现BeanFactory接口

    1. /**
    2. * @ClassName: ClassPathXmlApplicationContext
    3. * @description: BeanFactory的一个实现类
    4. * 1. 将xml中所有的bean标签创建出对象,然后放入容器中
    5. * 2. 对外提供了getBean方法,从而对于客户端而言可以很轻松的获取对象
    6. * @author: fengzhaoquan
    7. * @create: 2019-06-16 16:44
    8. * @Version 1.0
    9. **/
    10. public class ClassPathXmlApplicationContext implements BeanFactory {
  1. /**
  2. * @Author fengzhaoquan
  3. * @Description 配置文件中所有的bean都会放入beanMap中
  4. **/
  5. private static Map<String, Object> beanMap = Collections.synchronizedMap(new HashMap<>());
  6. public ClassPathXmlApplicationContext() {
  7. this("applicationContext.xml");
  8. }
  9. public ClassPathXmlApplicationContext(String fileName) {
  10. if (StringUtils.isBlank(fileName)) {
  11. throw new IllegalArgumentException("");
  12. }
  13. try {
  14. // 解析XML
  15. // 初始化beanMap
  16. initBeanMap(fileName);
  17. // 将bean之间的关系装配好(注入)
  18. injection(fileName);
  19. } catch (Exception e) {
  20. e.printStackTrace();
  21. }
  22. }
  23. /**
  24. * @Author fengzhaoquan
  25. * @Description 将bean之间的关系装配好(注入)
  26. **/
  27. private void injection(String fileName) throws Exception {
  28. Document document = Dom4jUtils.getDocument(fileName);
  29. List<Element> propertyElementList = document.selectNodes("//beans/bean/property");
  30. if (CollectionUtils.isNotEmpty(propertyElementList)) {
  31. for (Element propertyElement : propertyElementList) {
  32. String name = propertyElement.attributeValue("name");
  33. String refValue = propertyElement.attributeValue("ref");
  34. //setXxx方法拼接
  35. String methodName = "set" + name.substring(0, 1).toUpperCase() + name.substring(1);
  36. //找到父元素,也是就要被注入的对象
  37. Element beanElement = propertyElement.getParent();
  38. String parentElementIdValue = beanElement.attributeValue("id");
  39. if (beanMap.containsKey(parentElementIdValue) && beanMap.containsKey(refValue)){
  40. Object targetObject = beanMap.get(parentElementIdValue);
  41. Object parameterValue = beanMap.get(refValue);
  42. Method method = targetObject.getClass().getDeclaredMethod(methodName, parameterValue.getClass().getInterfaces());
  43. method.invoke(targetObject, parameterValue);
  44. }
  45. }
  46. }
  47. }
  48. /**
  49. * @Author fengzhaoquan
  50. * @Description 初始化beanMap
  51. **/
  52. private void initBeanMap(String fileName) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
  53. Document document = Dom4jUtils.getDocument(fileName);
  54. //XPath
  55. List<Element> beanElementList = document.selectNodes("//beans/bean");
  56. if (CollectionUtils.isNotEmpty(beanElementList)) {
  57. for (Element beanElement : beanElementList) {
  58. String id = beanElement.attributeValue("id");
  59. String beanClassName = beanElement.attributeValue("class");
  60. beanMap.put(id, Class.forName(beanClassName).newInstance());
  61. }
  62. }
  63. }
  64. @Override
  65. public Object getBean(Class clazz) {
  66. if(clazz == null){
  67. throw new IllegalArgumentException("");
  68. }
  69. return beanMap.get(clazz.getSimpleName().substring(0,1).toLowerCase() + clazz.getSimpleName().substring(1));
  70. }
  71. @Override
  72. public Object getBean(String className) {
  73. if(StringUtils.isBlank(className)){
  74. throw new IllegalArgumentException("");
  75. }
  76. return beanMap.get(className);
  77. }
  78. }
  1. Service,Dao,model代码:

    1. public class UserServiceImpl implements UserService {
  1. private UserDao userDao;
  2. public void setUserDao(UserDao userDao) {
  3. this.userDao = userDao;
  4. }
  5. @Override
  6. public void addUser(User user) {
  7. userDao.addUser(user);
  8. }
  9. }
  10. public class UserDaoHibernateImpl implements UserDao {
  11. @Override
  12. public void addUser(User user) {
  13. System.out.println("Hibernate add:" + user);
  14. }
  15. }
  16. public class UserDaoMybatisImpl implements UserDao {
  17. @Override
  18. public void addUser(User user) {
  19. System.out.println("Mybatis add:" + user);
  20. }
  21. }
  22. public class User implements Serializable {
  23. private static final long serialVersionUID = -5333671573596770181L;
  24. private String name;
  25. private String password;
  26. public String getName() {
  27. return name;
  28. }
  29. public void setName(String name) {
  30. this.name = name;
  31. }
  32. public String getPassword() {
  33. return password;
  34. }
  35. public void setPassword(String password) {
  36. this.password = password;
  37. }
  38. @Override
  39. public String toString() {
  40. return "User{" +
  41. "name='" + name + '\'' +
  42. ", password='" + password + '\'' +
  43. '}';
  44. }
  45. }
  1. 单元测试

    1. public class UserServiceImplTest {
  1. private BeanFactory factory;
  2. private UserService userService;
  3. @Before
  4. public void setUp() throws Exception {
  5. this.factory = new ClassPathXmlApplicationContext();
  6. this.userService = (UserService) this.factory.getBean(UserService.class);
  7. }
  8. @Test
  9. public void addUser() {
  10. User user = new User();
  11. user.setName("zhangsan");
  12. user.setPassword("123456");
  13. userService.addUser(user);
  14. }
  15. }

这是一个基本上可以说非常简陋的IOC,但是和Spring的原理是一样的。

发表评论

表情:
评论列表 (有 0 条评论,327人围观)

还没有评论,来说两句吧...

相关阅读

    相关 SpringIOC

    什么是IOC > 控制反转(Inversion of Control,缩写为IoC),是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度。其中最常见的方式