zoukankan      html  css  js  c++  java
  • 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);
        }
    
    }

    代码附件下载

  • 相关阅读:
    web通信浅析(上B/S交互)转载
    tomcat内部运行原理浅析转载
    oracle集合运算
    Oracle 游标使用全解
    oracle 一些基本概念
    1.搭建项目环境之TestDirector 8.0
    修改Win7远程桌面端口
    从第二份工作开始
    2.搭建项目环境之源代码管理SVN
    How to Get IIS Web Sites Information Programmatically
  • 原文地址:https://www.cnblogs.com/liqiu/p/3419420.html
Copyright © 2011-2022 走看看