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);
        }
    
    }

    代码附件下载

  • 相关阅读:
    DB2 for Z/os Statement prepare
    Foreign key (referential) constraints on DB2 LUW v105
    复制Informational constraints on LUW DB2 v105
    DB2 SQL Mixed data in character strings
    DB2 create partitioned table
    MVC中使用EF的技巧集(一)
    Asp.Net MVC 开发技巧(二)
    Linq使用技巧及查询示例(一)
    Asp.Net MVC 开发技巧(一)
    Asp.Net MVC Identity 2.2.1 使用技巧(八)
  • 原文地址:https://www.cnblogs.com/liqiu/p/3419420.html
Copyright © 2011-2022 走看看