JAVA的Spring注入机制事例详解

一、前言

最近使用Spring里面的依赖注入,比如StudentServiceImple2.java代码:

package di.service.imple;

import com.mengya.spring.annotation.MyResource;

import di.dao.StudentDao;
import di.service.StudentService;

public class StudentServiceImple2 implements StudentService {
    
    @MyResource
    private StudentDao stuDao;
    
    public void save() {
        stuDao.add();
    }

}

就是向属性stuDao注入一个StudengDao对象,那么这是怎么实现的哪?如果想要彻底了解它,需要提前知道两个知识点,反射和注解:http://www.cnblogs.com/rollenholt/archive/2011/09/02/2163758.html

二、实现过程

据我的理解,他的过程如下:

  1. 扫描XML文件,把里面的Bean实例对象保存在HashMap内,对应的KEY的值即为BeanId
  2. 扫描JAVA类的注解,找到需要注入的地方,比如:@MyResource
  3. 将已经保存的Bean实例赋值给注解对应的属性

那么让我们根据事例来逐条分析。

三、详细分析

3.1 扫描XML文件

这需要三个文件来实现:bean3.xml、MySpringAnnotationTest.java、MengyaClassPathXMLApplicationContext.java

bean3.xml

这就是一个普普通通的xml文件,里面包含了stuDao和stuService两个Bean。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">

    <bean id="stuDao" class="di.dao.imple.StudentDaoImple"></bean>

    <bean id="stuService" class="di.service.imple.StudentServiceImple2"></bean>

</beans>

MySpringAnnotationTest.java

这个是解析XML的一个类,没啥说的

package com.test;

import com.mengya.context.MengyaClassPathXMLApplicationContext;

import di.service.StudentService;

public class MySpringAnnotationTest {
    public static void main(String[] args) {
        MengyaClassPathXMLApplicationContext ctx = new MengyaClassPathXMLApplicationContext("beans3.xml");
        StudentService stuService = (StudentService) ctx.getBean("stuService");
        stuService.save();
    }
}

MengyaClassPathXMLApplicationContext.java

这个是重点的核心了。

injectObject() 函数是将stuDao和stuService两个Bean保存在属性sigletons里面

annotationInject() 函数是查找StudentServiceImple2类内的@Resource注解,并将StudentDao注入给stuDao属性

package com.mengya.context;

import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.beanutils.BeanUtils;

import com.mengya.spring.annotation.MyResource;
import com.mengya.spring.bean.BeanDefinition;
import com.mengya.spring.bean.PropertyDefinition;
import com.mengya.spring.util.ReadXMLUtil;

public class MengyaClassPathXMLApplicationContext {

    private List<BeanDefinition> beanDefintionList = null;

    private Map<String, Object> sigletons = new HashMap<String, Object>();

    /**
     * 容器初始化时 传入配置文件名称 读取配置文件..实例化bean
     * 
     * @param configFileName
     */
    public MengyaClassPathXMLApplicationContext(String configFileName) {
        beanDefintionList = ReadXMLUtil.readXMLBeanDefintion(configFileName);
        this.instanceBeans();
        this.injectObject();
        this.annotationInject();
    }

    /**
     * 注解实现依赖注入
     * 
     */
    private void annotationInject() {
        /**
         * 遍历bean,获取bean里的所有属性描述对象,遍历属性描述对象数组.
         * ---获取属性的setter方法.如果该属性setter方法存在,判断方法上是否有MyResource注解,
         * 如果有,获取注解对象,通过注解对象获取name值
         * 如果name值存在:根据name值查找Map中是否有该名称的bean,如果有,调用该属性的setter方法执行注入.
         * 如果name值不存在:获取该属性的名称,从map中查找是否有此名称的bean. 如果有:调用setter方法注入
         * 没有:获取该属性的类型,遍历map查找map中是否有和此属性类型一致的bean,如果有,则执行注入
         * 
         * ---获取该属性,判断该属性上是否有MyResource注解 如果有:获取该注解的对象,通过该对象获取name值
         * 如果name值存在:根据name值查找map中是否有该bean如果有则执行注入
         * 如果name值不存在:获取该属性的名称,查找map中是否有该名称的bean 如果有:执行注入 没有:获取该属性的类型
         * 遍历map中判断是否有和该类型一致的bean
         * 
         */
        for (String beanName : sigletons.keySet()) {
            System.out.println("beanName: " + beanName);
            Object bean = getBean(beanName);
            System.out.println("bean:" + bean.toString());
            if (null != bean) {
                try {
                    // 获取所有的属性
                    PropertyDescriptor pd[] = Introspector.getBeanInfo(bean.getClass()).getPropertyDescriptors();
                    for (PropertyDescriptor descriptor : pd) {
                        // 获取set方法
                        Method setter = descriptor.getWriteMethod();
                        // 若在set方法设置了MyResource注解
                        if (null != setter && setter.isAnnotationPresent(MyResource.class)) {
                            MyResource myResource = setter.getAnnotation(MyResource.class);
                            String diName = null;
                            Object diObject = null;
                            // 设置了name属性值
                            if (null != myResource.name() && !"".equals(myResource.name())) {
                                diName = myResource.name();
                            } else {// 按默认的属性值装配置
                                diName = descriptor.getName();
                            }
                            diObject = getBean(diName);
                            setter.setAccessible(true);
                            setter.invoke(bean, diObject);
                        }
                    }
                    // 获取所有字段
                    Field[] fields = bean.getClass().getDeclaredFields();
                    for (Field field : fields) {
                        if (field.isAnnotationPresent(MyResource.class)) {
                            MyResource myResource = field.getAnnotation(MyResource.class);
                            String diName = null;
                            Object diObject = null;
                            // 设置了name属性值
                            if (null != myResource.name() && !"".equals(myResource.name())) {
                                diName = myResource.name();
                            } else {// 按默认的属性值装配置
                                diName = field.getName();
                            }
                            diObject = getBean(diName);
                            field.setAccessible(true);
                            field.set(bean, diObject);
                        }
                    }

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

    /**
     * 注入Bean
     * 
     */
    private void injectObject() {
        for (BeanDefinition beanDefinition : beanDefintionList) {
            Object obj = getBean(beanDefinition.getId());
            if (null != obj) {
                List<PropertyDefinition> propertys = beanDefinition.getPropertys();
                if (null != propertys && propertys.size() > 0) {
                    try {
                        //通过Java的内省机制获取到对象中所有属性的描述信息
                        PropertyDescriptor[] ps = Introspector.getBeanInfo(obj.getClass()).getPropertyDescriptors();
                        for (PropertyDescriptor descriptor : ps) {
                            for (PropertyDefinition property : propertys) {
                                //判断XML文件中解析出来的属性和对象中的属性名称是否一样
                                if (descriptor.getName().equals(property.getName())) {
                                    if (null != property.getRef() && !"".equals(property.getRef())) {
                                        Object diObject = getBean(property.getRef());
                                        descriptor.getWriteMethod().invoke(obj, diObject);
                                    } else {
                                        BeanUtils.setProperty(obj, property.getName(), property.getValue());
                                    }

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

    /**
     * 实例化Bean
     * 
     */
    private void instanceBeans() {
        for (BeanDefinition beanDefinition : beanDefintionList) {
            try {
                Object obj = Class.forName(beanDefinition.getClassName()).newInstance();
                this.sigletons.put(beanDefinition.getId(), obj);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        System.out.println("this.sigletons: " + this.sigletons.toString());
    }

    /**
     * 获取Bean实例
     * 
     * @param beanName
     * @return
     */
    public Object getBean(String beanName) {
        return this.sigletons.get(beanName);
    }

}

代码附件下载

原文地址:https://www.cnblogs.com/liqiu/p/3419420.html