Spring IoC简单实现

2018-05-02  本文已影响0人  ryancao_b9b9

1、概述

Spring容器的原理就是基于解析XML文件、反射创建Bean、通过工厂模式管理Bean集合, 只需要调用getBean("beanID")方法即可获得这Bean。


2、实现过程

2.1 反射机制

反射.png
详情

2.2 XML解析

XML文件示例:

<?xml version="1.0" encoding="UTF-8"?>
<beans>  
    <bean id="user" class="com.falcon.model.User" />  
    <bean id="userDAO" class="com.falcon.dao.impl.UserDAOImpl" />  
    <bean id="userService" class="com.falcon.service.UserService">  
        <property name="userDAO" bean="userDAO" />  
    </bean>  
</beans> 

ClassPathXmlApplicationContext:读取xml文件内容,并创建对象及对象关系(使用setter方式)

package com.falcon.spring;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
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.JDOMException;
import org.jdom.input.SAXBuilder;
public class ClassPathXmlApplicationContext implements BeanFactory
{
    private Map<String, Object> beans = new HashMap<String, Object>();
    public ClassPathXmlApplicationContext() throws JDOMException, IOException,
            InstantiationException, IllegalAccessException,
            ClassNotFoundException, SecurityException, NoSuchMethodException,
            IllegalArgumentException, InvocationTargetException
    {
        SAXBuilder sb = new SAXBuilder();
        // 构造文档对象
        Document doc = sb.build(ClassPathXmlApplicationContext.class
                .getClassLoader().getResourceAsStream("beans.xml"));
        // 获取根元素
        Element root = doc.getRootElement();
        // 取到根元素所有元素
        List list = root.getChildren();
        for (int i = 0; i < list.size(); i++)
        {
            Element element = (Element) list.get(i);
            // 取id子元素
            String beanid = element.getAttributeValue("id");
            // 取class子元素
            String clzss = element.getAttributeValue("class");
            // 实例化
            Object o = Class.forName(clzss).newInstance();
            // 将所有bean放入map中
            beans.put(beanid, o);
            // 获取property 进行依赖注入
            for (Element propertyElement : (List<Element>) element
                    .getChildren("property"))
            {
                String name = propertyElement.getAttributeValue("name");
                System.out.println(name);//userDAO
                String bean = propertyElement.getAttributeValue("bean");
                System.out.println(bean);//userDAO
                // 从beans.xml中根据id取到类的对象
                //Object beanObj = this.getBean(name);
                // 从beans.xml中根据id取到类的对象
                Object beanObj = this.getBean(bean);
                System.out.println(beanObj);//com.yyb.dao.impl.UserDAOImpl@a09ee92
                // 形成setXXX方法名
                String methodName = "set" + name.substring(0, 1).toUpperCase()
                        + name.substring(1);
                System.out.println(name.substring(0, 1).toUpperCase());//U
                System.out.println(name.substring(1));//serDAO
                System.out.println(methodName);//setUserDAO
                
                // 反射机制对方法进行调用,将对象在加载bean时就注入到环境上下文中
                Method m = o.getClass().getMethod(methodName,
                        beanObj.getClass().getInterfaces()[0]);
                System.out.println(o.getClass());//class com.yyb.service.UserService
                System.out.println(beanObj.getClass().getInterfaces()[0]);//interface com.yyb.dao.UserDAO
                System.out.println(m);//public void com.yyb.service.UserService.setUserDAO(com.yyb.dao.UserDAO)
                // 执行注入,相当于执行了一个setXXX(args..)的方法
                m.invoke(o, beanObj);
            }
        }
    }
    @Override
    public Object getBean(String name)
    {
        return beans.get(name);
    }
}

2.3 BeanFactory

接口示例:

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

Bean示例:

public class User {
    private String userName;  
    private String password;  
    /** 
     * @return the userName 
     */  
    public String getUserName()  
    {  
        return userName;  
    }  
    /** 
     * @param userName 
     * the userName to set 
     */  
    public void setUserName(String userName)  
    {  
        this.userName = userName;  
    }  
    /** 
     * @return the password 
     */  
    public String getPassword()  
    {  
        return password;  
    }  
    /** 
     * @param password 
     *  the password to set 
     */  
    public void setPassword(String password)  
    {  
        this.password = password;  
    }  
    public String toString()  
    {  
        StringBuffer sb = new StringBuffer();  
        sb.append(this.userName);  
        sb.append(this.password);  
        return sb.toString();  
    }  
}
public interface UserDAO {
     void save(User u);  
     void delete(); 
}
public class UserDAOImpl implements UserDAO {
       @Override  
        public void save(User u) {  
            System.out.println("User:" + u.toString());  
        }  
        @Override  
        public void delete() {  
            System.out.println("delete User");  
        }  
}
public class UserService {
   private UserDAO userDAO;  
   public void addUser(User u)  
    {  
        this.userDAO.save(u);  
    }  
    /** 
     * @return the userDAO 
     */  
    public UserDAO getUserDAO()  
    {  
        return userDAO;  
    }  
    /** 
     * @param userDAO 
     *  the userDAO to set 
     */  
    public void setUserDAO(UserDAO userDAO)  
    {  
        this.userDAO = userDAO;  
    }  
}

2.4 自动依赖注入

依赖注入核心部分

                      // 实例化
            Object o = Class.forName(clzss).newInstance();
            // 将所有bean放入map中
            beans.put(beanid, o);
            // 获取property 进行依赖注入
            for (Element propertyElement : (List<Element>) element
                    .getChildren("property"))
            {
                String name = propertyElement.getAttributeValue("name");
                System.out.println(name);//userDAO
                String bean = propertyElement.getAttributeValue("bean");
                System.out.println(bean);//userDAO
                // 从beans.xml中根据id取到类的对象
                //Object beanObj = this.getBean(name);
                // 从beans.xml中根据id取到类的对象
                Object beanObj = this.getBean(bean);
                System.out.println(beanObj);//com.yyb.dao.impl.UserDAOImpl@a09ee92
                // 形成setXXX方法名
                String methodName = "set" + name.substring(0, 1).toUpperCase()
                        + name.substring(1);
                System.out.println(name.substring(0, 1).toUpperCase());//U
                System.out.println(name.substring(1));//serDAO
                System.out.println(methodName);//setUserDAO
                
                // 反射机制对方法进行调用,将对象在加载bean时就注入到环境上下文中
                Method m = o.getClass().getMethod(methodName,
                        beanObj.getClass().getInterfaces()[0]);
                System.out.println(o.getClass());//class com.yyb.service.UserService
                System.out.println(beanObj.getClass().getInterfaces()[0]);//interface com.yyb.dao.UserDAO
                System.out.println(m);//public void com.yyb.service.UserService.setUserDAO(com.yyb.dao.UserDAO)
                // 执行注入,相当于执行了一个setXXX(args..)的方法
                m.invoke(o, beanObj);
            }

实现效果:
Service service=(Service)beans.get("userService");
Dao dao = (Dao)beans.get("userDAO");
//依赖注入,Service实现依赖dao的实现
service.setDao(dao);


3、测试

public class client {

    public static void main(String[] args) throws InstantiationException, IllegalAccessException, ClassNotFoundException, SecurityException, NoSuchMethodException, IllegalArgumentException, InvocationTargetException, JDOMException, IOException {
    BeanFactory factory = new ClassPathXmlApplicationContext(); 
    //通过工厂直接获取
        UserService userService = (UserService) factory.getBean("userService"); 
        //其实User也可以从工厂中获得
        User u=(User)factory.getBean("user");
        //User u = new User();  
        u.setUserName("yyb");  
        u.setPassword("1234");  
        userService.addUser(u);//打印结果yyb1234
    }

}
上一篇下一篇

猜你喜欢

热点阅读