手写简单Spring IoC实现 和set注入

本文介绍了如何手动实现Spring的核心功能,包括使用反射机制给User对象的age属性赋值,以及解析XML配置文件来创建和初始化bean。通过ClassPathXmlApplicationContext类,实现了读取XML配置文件,根据配置信息创建对象并存储在map中,以及根据bean的属性设置值。最后,通过示例展示了如何获取和使用这些bean。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

手写Spring

1、回顾反射机制

如何使用反射?

1、调用什么对象
2、调用该对象的的什么方法,
3、需要什么参数,
4、执行该方法并返回什么(可以无返回值)
解决反射需要条件

假定现在要给User对象的age属性赋值

  • 1、调用什么对象?==>Class<?> clazz =Class.forName()传入类全路径

    ​ Object o = clazz.newInstance() 得到该对象

  • 2、调用该对象的的什么方法, 假定是set方法

    通过属性名获取该属性名的第一个字母大写,加截取第一个字母的后面所有内容

    获取方法名 ==>String methed = “set” + name.toUpperCase().charAt(0) + name.substring(1);

    获取该方法==>Method methed1 = clazz.getDeclaredMethod(“方法名”,“参数类型”.Class)

  • 3、需要什么参数,

    “参数类型”.Class如何获取?==>Field field = clazz.getField(“属性名”);

    field.getType()返回该属性的Class

    Method methed = clazz.getDeclaredMethod(methed, field.getType());

  • 4、执行该方法并返回什么(可以无返回值) methed.invoke()方法

    methed .invoke(o, 30);

到此就完成了对User对象的age属性赋值

        Class<?> clazz = Class.forName("com.xxxxx.pojo.User");
        String name = "age";
        //1、获取对象
        Object o = clazz.newInstance();
        //2、获取方法名 第一个字母转大写 并截取1以后的方法名
        String methed = "set" + name.toUpperCase().charAt(0) + name.substring(1);
        //3、需要什么参数 方法名+属性的class getField()通过属性名返回field对象 属性名是唯一的
        Field field = clazz.getField(name);
        //field.getType() 返回值是该对象的Class
        Method methed1 = clazz.getDeclaredMethod(methed, field.getType());
        //4、无返回值
        methed1.invoke(o, 30);
        System.out.println(o);
        Method dosome = clazz.getDeclaredMethod("dosome");
        dosome.invoke(o);
二、准备xml文件解析
<dependency>
    <groupId>dom4j</groupId>
    <artifactId>dom4j</artifactId>
    <version>1.1</version>
</dependency>
<dependency>
    <groupId>jaxen</groupId>
    <artifactId>jaxen</artifactId>
    <version>1.2.0</version>
</dependency>
三、准备接口
public interface ApplicationContext {

    /**
     * 通过name 获取bean对象
     *
     * @param beanName
     * @return
     */
    Object getBean(String beanName);
}
四、创建实现类
创建对象放在map集合中
 //存储bean对象
    private Map<String, Object> map = new HashMap<>();

    /**
     * 提供构造方法、读取xml文件
     */
    public ClassPathXmlApplicationContext(String config) {
        /*第一步:将所有bean标签中的对象存到map集合中
         * */
        try {
            //dom4j解析xml文件的核心对象
            SAXReader reader = new SAXReader();
            //获取类路径下的资源 以流的方式获取 指向配置文件config
            InputStream resourceAsStream = ClassLoader.getSystemClassLoader().getResourceAsStream(config);
            //读取流对象 获取xml文件document
            Document document = reader.read(resourceAsStream);
            //获取所有的bean标签 //bean
            List<Node> nodes = document.selectNodes("//bean");
            //遍历bean标签
            nodes.forEach(node -> {
                //将node向下转型为Element Element继承Branch接口,Branch接口继承Node接口
                //向下转型是因为Element方法更加丰富 为了使用Element接口中的方法
                Element element = (Element) node;
                //element.attributeValue 获取该标签中属性为id的值
                String id = element.attributeValue("id");
                //获取类路径
                String aClass = element.attributeValue("class");
                try {
                    //获取Class
                    Class<?> clazz = Class.forName(aClass);
                    //clazz.getDeclaredConstructor获取无参构造方法
                    Constructor<?> defultCon = clazz.getDeclaredConstructor();
                    //调用无参构造器实例化对象
                    Object o = defultCon.newInstance();
                    //将对象添加到Map集合中
                    map.put(id, o);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            });
             * */
            //遍历bean标签并给属性赋值
            nodes.forEach(node -> {
                try {
                    //向下转型 element方法更丰富
                    Element element = (Element) node;
                    //获取bean标签中属性为id的value
                    String id = element.attributeValue("id");
                    //获取bean标签中属性为class的value 也就是全类名
                    String aClass = element.attributeValue("class");
                    //通过类获取到Class对象
                    Class<?> clazz = Class.forName(aClass);

                    //element.elements获取该标签下所有名为porperty的标签 返回一个Element list集合
                    List<Element> porpertys = element.elements("porperty");
                    //遍历所有的porperty标签
                    porpertys.forEach(porperty -> {
                        try {
                            //获取set方法前的方法名
                            String name = porperty.attributeValue("name");
                            //获取参数类型 getDeclaredField()和getField区别
                            Field field = clazz.getDeclaredField(name);
                            //方法名等于set+set方法后字母首字母大写+后续的 toUpperCase()转大写.charAt(0)获取首字母 substring(1)截取一个字符串后的所有字符串
                            String methed = "set" + name.toUpperCase().charAt(0) + name.substring(1);
                            //获取clazz类的方法
                            Method declaredMethod = clazz.getDeclaredMethod(methed, field.getType());
                            //获取porperty标签中属性为value的属性(简单类型)
                            String value = porperty.attributeValue("value");
                            //真正要给简单类型赋的值
                            Object realValue = null;
                            //获取porperty标签中属性为ref的属性(引用类型)
                            String ref = porperty.attributeValue("ref");
                            //如果value不等于null 代表是简单类型
                            if (value != null) {
                                //调用set方法(没有返回值)
                                //我们myspring框架只支持以下类型为简单类型
                                //byte short int long float double boolean char
                                //Byte Short Integer Long Float Double Boolean Character
                                //String
                                //如果是简单类型 需要对获取到的 String value进行转换 field.getType()获取类型(包含java.lang.*) getSimpleName()获取真正的类型名
                                String simpleName = field.getType().getSimpleName();
                                switch (simpleName) {
                                    case "byte":
                                        realValue = Byte.parseByte(value);
                                        break;
                                    case "short":
                                        realValue = Short.parseShort(value);
                                        break;
                                    case "int":
                                        realValue = Integer.parseInt(value);
                                        break;
                                    case "long":
                                        realValue = Long.parseLong(value);
                                        break;
                                    case "float":
                                        realValue = Float.parseFloat(value);
                                        break;
                                    case "double":
                                        realValue = Double.parseDouble(value);
                                        break;
                                    case "boolean":
                                        realValue = Boolean.parseBoolean(value);
                                        break;
                                    case "char":
                                        //如果是char类型 代表只有一个字符
                                        realValue = value.charAt(0);
                                        break;
                                    case "Byte":
                                        realValue = Byte.valueOf(value);
                                        break;
                                    case "Short":
                                        realValue = Short.valueOf(value);
                                        break;
                                    case "Integer":
                                        realValue = Integer.valueOf(value);
                                        break;
                                    case "Long":
                                        realValue = Long.valueOf(value);
                                        break;
                                    case "Float":
                                        realValue = Float.valueOf(value);
                                        break;
                                    case "Double":
                                        realValue = Double.valueOf(value);
                                        break;
                                    case "Boolean":
                                        realValue = Boolean.valueOf(value);
                                        break;
                                    case "Character":
                                        realValue = value.charAt(0);
                                        break;
                                    case "String":
                                        realValue = value;
                                        break;
                                }
                                //给属性赋set值
                                declaredMethod.invoke(map.get(id), realValue);
                            }
                            //如果ref不等于null 代表是引用类型 map.get(id)从集合中获取该对象,map.get(ref)给该对象的引用赋值
                            if (ref != null) {
                                declaredMethod.invoke(map.get(id), map.get(ref));
                            }
                        } catch (Exception e) {
                            e.printStackTrace();
                        }

                    });
                } catch (Exception e) {
                    e.printStackTrace();
                }
            });
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

返回实体类

 /**
     * 通过id返回bean实例 需要向下转型
     *
     * @param beanName
     * @return
     */
    @Override
    public Object getBean(String beanName) {
        return map.get(beanName);
    }

    /**
     * 通过id和Class返回指定bean实例
     *
     * @param beanName
     * @param tClass
     * @param <T>
     * @return
     */
    public <T> T getBean(String beanName, Class<T> tClass) {
        return (T) map.get(beanName);
    }

    /**
     * 根据类型自动匹配 如果有超过一个 直接报错
     *
     * @param tClass
     * @param <T>
     * @return
     */
    @Override
    public <T> T getBean(Class<T> tClass) {
        int i = 0;
        List<T> list = new ArrayList<>();
        for (String key : map.keySet()) {
            if (tClass.equals(map.get(key).getClass())) {
                i++;
                if (i > 1) {
                    throw new RuntimeException();
                }
                list.add((T) map.get(key));
            }
        }
        if (!list.isEmpty()) {
            return list.get(0);
        }
        return null;
    }

验证程序测试
配置 Xml

<?xml version="1.0" encoding="UTF-8"?>
<beans>
    <!--给简单类型赋值-->
    <bean id="user" class="com.bijianhua.bean.User">
        <porperty name="userName" value="张三"/>
        <porperty name="age" value="20"/>
    </bean>
    <bean id="userServiceBean" class="com.bijianhua.dao.UserService">
        <porperty name="userDao" ref="userDaoBean"/>
    </bean>
    <bean id="userDaoBean" class="com.bijianhua.dao.UserDaoImpl"/>


</beans>

测试程序 UserBean

public class User {

    private String userName;
    private Integer age;

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "User{" +
                "userName='" + userName + '\'' +
                ", age=" + age +
                '}';
    }
}

测试程序:UserSerivce

//接口
public interface UserDao {

    void save();
}
//实现类
public class UserDaoImpl implements UserDao {
    @Override
    public void save() {
        System.out.println("数据库保存了信息");
    }
}
//具体的Service
public class UserService {

    private UserDao userDao;

    //提供set方法
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

    public void insert() {
        //调用dao中的save方法
        userDao.save();
    }
}

main方法中测试
简单类型

 public static void main(String[] args) {
        ApplicationContext ioc=new ClassPathXmlApplicationContext("myspring.xml");
        User user = ioc.getBean("user", User.class);
        System.out.println(user);
    }
    打印结果:
    User{userName='张三', age=20}

引用类型 以下是自动装配

public static void main(String[] args) {
        ApplicationContext ioc=new ClassPathXmlApplicationContext("myspring.xml");
        UserService bean = ioc.getBean(UserService.class);
        System.out.println(bean);
        bean.insert();
    }
    控制台输出:
    com.bijianhua.dao.UserService@6073f712
	数据库保存了信息

完结!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值