Spring-IOC简单原理 + 实现

本文深入探讨Spring框架的核心特性IOC和AOP,详细解释了AOP的概念和使用动态代理实现的方式,同时介绍了如何使用Java反射技术解析配置文件中的注解来实现IOC。文中提供了一个简化配置文件的类示例,并详细阐述了注解解析程序的工作流程,包括配置文件类的检查、方法的获取、实例化和依赖注入的过程。

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

Spring的核心是IOC和AOP
AOP之前介绍了,核心是使用动态代理包装了一层。
IOC使用到的Java技术是用反射去解析注解。

代码下载

下面这个类是模拟xml的配置文件,省略对xml文件解析的麻烦。其中的注解都可以自己定义,具体可下载代码查看

package annocation.my;
@Configuration
public class BeansXML {

    @Bean("bookHotel")
    public IBook bookHotel() {
        return new BookHotelImpl();
    }

    @Bean
    //注册的Bean名称为方法名
    public IBook bookRestaurant() {
        return new BookRestaurantImpl();
    }

    @Bean("holiday")
    public Holiday funnyHoliday() {
        return new Holiday();
    }
}

注解解析程序,注解的获取是从class类得到。处理流程:解析xml(类),用map保存name和类地址的映射。getBean时,对那个类进行解析,类中有Bean注解的方法/属性获取到和Map中的对比。然后注入加载即可。

package annocation.my;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

public class ApplicationContext {
    // 配置文件类
    private Class<?> configClass;
    // 配置文件类中Bean,只处理使用@Bean标注的方法,没有注解的方法将被忽略
    // Map<注解名称,注解方法>
    private Map<String, Method> mapMethods;

    // 构造函数
    public ApplicationContext(Class<?> configClass) {
        this.configClass = configClass;
        // 检查配置文件类
        if (checkConfigClass()) {
            // 读取配置文件类的方法
            mapMethods = getDeclaredMethods(configClass);
        }
    }

    // 判断配置文件类是否使用了@Configuration注解
    private boolean checkConfigClass() {
        Boolean useConfiguration = false;
        try {
            useConfiguration = configClass
                    .isAnnotationPresent(Configuration.class);
            if (!useConfiguration) {
                System.out.println("[配置文件类:" + configClass.getName()
                        + " 缺少@Configuration注解]");
            }
        } catch (Exception e) {
            System.out.println("[读取配置文件类失败]" + e);
        }
        return useConfiguration;
    }

    // 获取一个类中所有使用了@Bean注解的方法
    private Map<String, Method> getDeclaredMethods(Class<?> clazz) {
        Map<String, Method> resultMap = new HashMap<String, Method>();
        try {
            for (Method m : clazz.getDeclaredMethods()) {
                // 获取每个方法的@bean注解
                Bean beanMethod = m.getAnnotation(Bean.class);
                if (null != beanMethod) {
                    // @Bean没有自定义value,使用方法名称作为value
                    String annoName = beanMethod.value();
                    annoName = ("".equals(annoName)) ? m.getName() : annoName;
                    resultMap.put(annoName, m);
                }
            }
        } catch (Exception e) {
            System.out.println("[读取配置文件类Bean定义出错]" + e);
        }
        return resultMap;
    }

    // 获取类实例,只能调用无参的构造函数
    private <T> T getInstance(Class<T> clazz) {
        T instance = null;
        try {
            instance = clazz.newInstance();
        } catch (Exception e) {
            System.out.println("[实例化配置文件类失败,类名称: " + clazz.getName() + "]" + e);
        }
        return instance;
    }

    // 字符串的第一个字母转换为大写
    private String getMethodName(String fildeName) {
        byte[] items = fildeName.getBytes();
        items[0] = (byte) ((char) items[0] - 'a' + 'A');
        return new String(items);
    }

    /**
     * 根据bean名称获取bean
     * 
     * @param beanName
     *            注册的Bean名称
     */
    @SuppressWarnings("unchecked")
    public <T> T getBean(String beanName) {
        // Bean实例
        T instance = null;
        // 配置文件类的实例
        Object configObj = getInstance(configClass);
        // 遍历所有定义的Bean
        Set<String> annoNames = (Set<String>) mapMethods.keySet();
        for (String annoName : annoNames) {
            // 对应的方法
            Method m = mapMethods.get(annoName);
            // 对入参进行匹配
            if (beanName.equals(annoName)) {
                try {
                    // 获取实例
                    instance = (T) m.invoke(configObj);
                    // 实例对象对应的Class类型
                    Class<?> instanceClass = instance.getClass();
                    // 注入依赖(实例化@Resource引用的Bean)
                    for (Field fs : instanceClass.getDeclaredFields()) {
                        // 读取属性上的@Resource注解信息
                        Resource resField = fs.getAnnotation(Resource.class);
                        if (null != resField) {
                            // 获取注解值
                            String ResValue = resField.value();
                            // 判断是否已在配置文件类中已注册
                            Method refM = mapMethods.get(ResValue);
                            if (null != refM) {
                                try {
                                    // 获取属性对应的标准setter方法名称
                                    String setterName = "set"
                                            + getMethodName(fs.getName());
                                    // 根据名称和入参类型获取setter方法
                                    Method setter = instanceClass.getMethod(
                                            setterName, fs.getType());
                                    // 执行setter方法注入属性值
                                    // refM.invoke(configObj) 将返回一个配置文件类中的实例
                                    setter.invoke(instance,
                                            refM.invoke(configObj));
                                } catch (Exception e) {
                                    System.out.println("[类:"
                                            + instance.getClass().getName()
                                            + ",属性:" + fs.getName()
                                            + " 缺少标准的setter()方法]" + e);
                                }
                            } else {
                                System.out.println("[配置文件类中未找到对应的Bean:"
                                        + ResValue + "]");
                            }
                        }
                    }
                } catch (Exception e) {
                    System.out.println("[实例化bean失败,名称:" + beanName + "]" + e);
                }
            }
        }
        return instance;
    }
}

XML解析版

package test;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import org.dom4j.Attribute;  
import org.dom4j.Document;  
import org.dom4j.Element;  
import org.dom4j.io.SAXReader; 

public class BeanFactory {
    private Map<String, Object> beanMap = new HashMap<String, Object>();

    public void init(String xml) {
        try {
            // 读取指定的配置文件
            SAXReader reader = new SAXReader();
            ClassLoader classLoader = Thread.currentThread()
                    .getContextClassLoader();
            // 从class目录下获取指定的xml文件
            InputStream ins = classLoader.getResourceAsStream(xml);
            Document doc = reader.read(ins);
            Element root = doc.getRootElement();
            Element foo;
            // 遍历bean
            for (Iterator i = root.elementIterator("bean"); i.hasNext();) {
                foo = (Element) i.next();
                // 获取bean的属性id和class
                Attribute id = foo.attribute("id");
                Attribute cls = foo.attribute("class");
                // 利用Java反射机制,通过class的名称获取Class对象
                Class bean = Class.forName(cls.getText());
                // 获取对应class的信息
                java.beans.BeanInfo info = java.beans.Introspector
                        .getBeanInfo(bean);
                // 获取其属性描述
                java.beans.PropertyDescriptor pd[] = info
                        .getPropertyDescriptors();
                // 设置值的方法
                Method mSet = null;
                // 创建一个对象
                Object obj = bean.newInstance();
                // 遍历该bean的property属性
                for (Iterator ite = foo.elementIterator("property"); ite
                        .hasNext();) {
                    Element foo2 = (Element) ite.next();
                    // 获取该property的name属性
                    Attribute name = foo2.attribute("name");
                    String value = null;
                    // 获取该property的子元素value的值
                    for (Iterator ite1 = foo2.elementIterator("value"); ite1
                            .hasNext();) {
                        Element node = (Element) ite1.next();
                        value = node.getText();
                        break;
                    }
                    for (int k = 0; k < pd.length; k++) {
                        if (pd[k].getName().equalsIgnoreCase(name.getText())) {
                            mSet = pd[k].getWriteMethod();
                            // 利用Java的反射极致调用对象的某个set方法,并将值设置进去 mSet.invoke(obj,
                            // value);
                            mSet.invoke(obj, value);
                        }
                    }
                }

                // 将对象放入beanMap中,其中key为id值,value为对象
                beanMap.put(id.getText(), obj);
            }
        } catch (Exception e) {
            System.out.println(e.toString());
        }
    }

    public Object getBean(String beanName) {
        Object obj = beanMap.get(beanName);
        return obj;
    }

    public static void main(String[] args) {
        BeanFactory factory = new BeanFactory();
        factory.init("classpath:config.xml");
        JavaBean javaBean = (JavaBean) factory.getBean("javaBean");
        System.out.println("userName=" + javaBean.getUserName());
        System.out.println("password=" + javaBean.getPassword());
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值