• 自定义beans.xml文件实现Spring框架


    经过一天的补习,学习文件加载,java反射,JDom等知识,到了晚上终于能够搭出一个基于配置文件的简单spring框架实现!

    首先我们先看看这个问题:

    下面是两副图左边是项目结构图,右边是UML图:

                          

    正常情况下我们会按照上图一行一行的写代码:

    其中UserService的代码是这样的

    public class UserService {
              //实现dao层的一个实例对象
    	private UserDAO userDAO=new UserDAOImpl();
    
             //userDAO的setter和getter
    	public UserDAO getUserDao() {
    		return userDAO;
    	}
    
    	public void setUserDAO(UserDAO userDAO) {
    		this.userDAO = userDAO;
    	}
              //添加用户
    	public void add(User user) {
    		if (userDAO == null)
    			System.out.println("erro");
    		else {
    
    			userDAO.add(user);
    		}
    
    	}
    
    }
    

     正像UML图所画的那样,UserService对User,UserDao,UserDAOImpl都有单向关联!

    这里我们思考一下:

    这仅仅是一个对象的操作,如果有TeacherService,狗Service,猫Service.........那么我们是不是每个都得实现service手动的调动Dao,DAOImpl,User等等,何其麻烦,

    我们再注意看看:

    1.Dao层是专门 与数据库交互的,里面有很多方法,而service是用来调用dao层的方法,他们之间唯一的联系就是在方法调用时,

    Service层通过 private UserDAO userDAO=new UserDAOImpl();来实现与DAO层的耦合,我们知道程序设计讲究”高内聚低耦合“,

    2.我们再看private UserDAO userDAO=new UserDAOImpl(); 这句是得到UserDao这个接口对象实例,并且这个实例是由new UserDAOImpl来决定,

    我们知道,一个接口可以有很多实现类,这样写就是证明这个类中UserDAO的实例只能是UserDaoImpl的实例,不能使其他实现接口类的实例,那么这个类就具备重用的灵活性

    既然这样,有没有一种方式能够降低这种耦合,提高灵活性呢,答案是spring


    Spring思路


    我们的service和UserDAOImpl没有任何的联系,而是通过一个配置文件来关联各个类之间的关系

    1.我们看看beans.xml

    <beans>
    	<bean id="u" class="com.spring.dao.impl.UserDAOImpl" />
    	<bean id="userService" class="com.spring.service.UserService" >
    		<property name="userDAO" bean="u"/>
    	</bean>
    
    </beans>
    

      配置文件中又两个bean,所谓的bean就是java中的类,每个bean都有 id和class两个属性,id就是代表这个bean唯一标识,class就是这个类的(包+类)名

         我们看到第二个bean是有<property>子节点的,<property>表明这个bean中时存在以其他bean作为参数的,

         并且这个参数bean在这个类中实例对象名字为(userDAO),在所有beans中这个参数bean的id=u

    2.加载beans.xml

       我们先定义一个容器,通常是一个Map类型的容器,按照<bean>顺序依次初始化每个bean对应的类的对象,并把这个对象,和对象的id存放到Map容器中

    我们先来实现这个容器:

    package com.spring.buildframework;
    
    import java.lang.reflect.Method;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    import org.jdom.Document;
    import org.jdom.Element;
    import org.jdom.input.SAXBuilder;
    
    public class ClassPathXMLApplicationContext {
    
    	private static Map<String, Object> beans = new HashMap<String, Object>();
    
    	public ClassPathXMLApplicationContext() {
    
    		SAXBuilder sb = new SAXBuilder();
    
    		try {
    			Document doc = sb.build(this.getClass().getClassLoader()
    					.getResourceAsStream("beans.xml"));
    			
    			//获取根节点
    			Element root=doc.getRootElement();
    			//将根节点的下的孩子全部放到List中
    			List allList= root.getChildren("bean");
    			
    			for(int i=0;i<allList.size();i++)
    			{
    				Element sigElement=(Element)allList.get(i);
    				//获取每个<bean>节点的id和class属性的值
    				String id=sigElement.getAttribute("id").getValue();
    				String clazz=sigElement.getAttribute("class").getValue();
    				System.out.println(id+clazz);
    				//根据获取的类名利用反射得到实例
    				Class<?> demo=Class.forName(clazz);
    				Object obj=demo.newInstance();
    				//将id和类的实例放到beans中
    				beans.put(id, obj);
    				
    				//判断该bean下是否存在property的子节点
    				List propertyChild=sigElement.getChildren("property");
    				for(int j=0;j<propertyChild.size();j++)
    				{
    					//获取此bean下name和bean的属性 ,其中bean指的是配置文件中另一个bean
    					Element propertyElement=(Element)propertyChild.get(j);
    					String name=propertyElement.getAttributeValue("name");  //userDAO
    			    	String bean=propertyElement.getAttributeValue("bean");    //u
    			    	
    			   	    //拼接该bean(useDAO)的setter方法 setUserDAO
    		    	    String setterMethodName="set"+name.substring(0,1).toUpperCase()+name.substring(1);
    		    	    //调用setter方法是需要注入com.spring.dao.impl.UserDAOImpl类的 对象
    		    	    Object  fieldObj=beans.get(bean);
    		    	    //获取fieldObj对象的类的类型,
    		    	    Class<?> type=fieldObj.getClass().getInterfaces()[0];
    		    	    
    		    	    Method setterMethod=obj.getClass().getMethod(setterMethodName, type);
    		    	    setterMethod.invoke(obj,fieldObj);
    			    	System.out.println(type);
    				}
    			
    			}
    
    		} catch (Exception e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		}
    	}
    	
    	//提供给外界接口
    	public static Object getBean(String id)
    	{
    		return beans.get(id);
    	}
    
    }
    

      我们只需要初始化这个类,我们就能获得上图中的容器,而容器中就包含着我们需要的所有配置了的类的对象!

    这时我们的UserService:

    package com.spring.service;
    
    import com.spring.dao.UserDAO;
    import com.spring.dao.impl.UserDAOImpl;
    import com.spring.model.User;
    
    public class UserService {
    
    	private UserDAO userDAO;
    
    	public UserDAO getUserDao() {
    		return userDAO;
    	}
    
    	public void setUserDAO(UserDAO userDAO) {
    		this.userDAO = userDAO;
    	}
    
    	public void add(User user) {
    		if (userDAO == null)
    			System.out.println("erro");
    		else {
    
    			userDAO.add(user);
    		}
    
    	}
    
    }
    

      请注意和之前的不同,我们不再实例化userDAO而是通过  ClassPathXMLApplicationContext 类调用其set方法来实例化。

    其他类:

    public class UserDAOImpl implements UserDAO {
    
    	@Override
    	public void add(User user) {
    		// TODO Auto-generated method stub
    		System.out.println("user added successful");
    		
    	}
    
    }
    
    
    
    
    
    package com.spring.dao;
    
    import com.spring.model.User;
    
    public interface UserDAO {
    
    	public void add(User user);
    }
    
    
    package com.spring.model;
    
    public class User {
      private String username;
      private String age;
    public String getUsername() {
    	return username;
    }
    public void setUsername(String username) {
    	this.username = username;
    }
    public String getAge() {
    	return age;
    }
    public void setAge(String age) {
    	this.age = age;
    }
    	
    	
    }
    

      测试类:

    public class ClassPathXMLApplicationContextTest {
    
    	@Test
    	public void test() {
    		try {
    		//	Class<?> demo=Class.forName("com.spring.dao.impl.UserDAOImpl");
    		} catch (Exception e) {
    			// TODO: handle exception
    		}
    		//得到转载容器类的实例
    		ClassPathXMLApplicationContext test=new ClassPathXMLApplicationContext();
    //从容器中获取userService对象 UserService service=(UserService)ClassPathXMLApplicationContext.getBean("userService"); User user=new User();
    //执行方法 service.add(user);
    fail("Not yet implemented"); } }

      需要说明的是:我们得从容器中拿到UserService对象才能进行调用

         就这样:通过xml文件配置的简单spring框架就实现了

         顺便讲讲IOC和DI的概念:

      IOC(Inverse Of Control):1>就在UseService中我们UserDaO的初始化不是掌握在我们自己手中,而是掌握在容器中

                                              2>原来我们的程序写实现,现在依赖于抽象,也就是从实现具体的东西反转到接口(抽象上),给人的感觉是在控制接口而不是控制事项                            3>控制的实现在与接口而不是具体实现

    DI(Dependency Inject)   :向bean中注入参数

  • 相关阅读:
    华为云垃圾分类大赛,让AI 帮你“见圾行事”
    【带着canvas去流浪(14)】Three.js中凹浮雕模型的生成方式
    Ubuntu 配置网卡信息
    配置 Mysql 支持远程访问 并取消域名解析以提高链接速度
    jQuery 操作 html5 data-* 属性
    Laravel 中使用原生的 PHPExcel
    Laravel 上使用 phpexcel的两种方式
    debian中默认不存在sudo命令解决方法
    composer install 时,提示:Package yiisoft/yii2-codeception is abandoned, you should avoid using it. Use codeception/codeception instead.的解决
    Linux 磁盘分区存放文件和目录的数量 (inode)
  • 原文地址:https://www.cnblogs.com/fjsnail/p/3493344.html
Copyright © 2020-2023  润新知