• Spring获取Bean对象以及依赖注入的实现原理


    1、定义BeanDefinition,另外bean里面还有 <property>节点,这里把它抽象成PropertyDefinition

    代码如下:

    package com.laoxu.test.day02.springDemo.parseXml;
    
    /**
     * 在读取配置信息的时候,当读到<bean>节点的时候,需要把节点中的id,class 等等属性共同组成一个对象,
     * 这里定义成BeanDefinition,另外bean里面还有 <property>节点,这里把它抽象成PropertyDefinition
     */
    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * 1、BeanDefinition获取bean对象的id和对应的class的路径 2、PropertyDefinition
     * 表示bean下面的property属性
     */
    public class BeanDefinition {
        private String className;
        private String id;
        private List<PropertyDefinition> definitions = new ArrayList<PropertyDefinition>();
    
        public BeanDefinition(String className, String id) {
            super();
            this.className = className;
            this.id = id;
        }
    
        public String getClassName() {
            return className;
        }
    
        public void setClassName(String className) {
            this.className = className;
        }
    
        public String getId() {
            return id;
        }
    
        public void setId(String id) {
            this.id = id;
        }
    
        public List<PropertyDefinition> getDefinitions() {
            return definitions;
        }
    
        public void setDefinitions(List<PropertyDefinition> definitions) {
            this.definitions = definitions;
        }
    
    }
    
    package com.laoxu.test.day02.springDemo.parseXml;
    /**
     * bean里面有 <property>节点,这里把它抽象成PropertyDefinition
     */
    public class PropertyDefinition {
        
        public PropertyDefinition() {
            
        }
        private String name;
        private String ref;
        public String getRef() {
            return ref;
        }
        public void setRef(String ref) {
            this.ref = ref;
        }
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
    
    }

    2、首先配置XML文件,创建相应的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.0.xsd">
    <!-- 
    把业务bean交给Spring来管理,bean 的id是唯一的,name属性也是为bean起名的,id本身就是xml的属性
    但id的值是不能包含特殊字符的比如/,name是 可以指定特殊字符
    bean配置好之后,bean就会有spring容器来帮我们创建和维护
    -->
    
       <bean id="personService" class="com.laoxu.test.day02.springDemo.entity.PersonServiceBean" >
               <property name="personDao" ref="personDao"></property>
       </bean>
       
       <bean id="personDao" class="com.laoxu.test.day02.springDemo.dao.PersonDao">
       
       </bean>
    </beans>

    创建对象类代码,其中可以包含业务等信息:

    package com.laoxu.test.day02.springDemo.entity;
    
    import com.laoxu.test.day02.springDemo.dao.PersonDao;
    
    /**
     * bean对象
     */
    public class PersonServiceBean {
        private PersonDao personDao;
        
        public void say(String name){
            System.out.println("this is the person say:" + name);
            if(personDao==null){
                System.out.println("personDao is null");
                return ;
            }
            personDao.getDB(name);
        }
    
        public PersonDao getPersonDao() {
            return personDao;
        }
    
        public void setPersonDao(PersonDao personDao) {
            this.personDao = personDao;
        }
    }
    package com.laoxu.test.day02.springDemo.dao;
    
    public class PersonDao {
        
        public void getDB(String name){
            System.out.println("this is the DB:"+name);
        }
    }

    3、通过Dom4j读取XML的配置文件。代码如下:

    package com.laoxu.test.day02.springDemo.parseXml;
    
    import java.net.URL;
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    import org.dom4j.Document;
    import org.dom4j.DocumentException;
    import org.dom4j.Element;
    import org.dom4j.XPath;
    import org.dom4j.io.SAXReader;
    
    /**
     * 解析XML文件工具类
     */
    public class ParseXMLUtil {
        
        @SuppressWarnings("unchecked")
        public static List<BeanDefinition> readXML(String name) throws DocumentException{
            
            SAXReader saxReader = new SAXReader();//创建读取器
            Document document = null;
            /*
             * 注意此处不能使用this,因为方法是静态方法,解决方法:ParseXMLUtil.class
             */
            URL url = ParseXMLUtil.class.getClassLoader().getResource(name);
            if(url==null){
                System.out.println("this url is null");
                return null;
            }
            document = saxReader.read(url);//读取文件内容
            Map<String, String> nsMap = new HashMap<String, String>();
            nsMap.put("ns", "http://www.springframework.org/schema/beans");
            XPath path = document.createXPath("//ns:beans/ns:bean");//创建beans/bean查询路径
            path.setNamespaceURIs(nsMap);//设置命名空间, 其中的//ns:是根
            
            List<BeanDefinition> beanDefinitions = new ArrayList<BeanDefinition>();
            
            List<Element> elements = path.selectNodes(document);//获取当前文档下的所有bean节点
            List<Element> elementss = null;//Property属性集合
            List<PropertyDefinition> propertyDefinitions = null;
            PropertyDefinition propertyDefinition = null;
            BeanDefinition beanDefinition = null;
            for (Element element : elements) {
                beanDefinition = new BeanDefinition(element.attributeValue("class"), element.attributeValue("id"));//获取class属性与id属性
                /*
                 * 获取property属性集合
                 */
                elementss = element.elements();
                propertyDefinitions = new ArrayList<PropertyDefinition>();
                for (Element ele : elementss) {
                    propertyDefinition = new PropertyDefinition();
                    propertyDefinition.setName(ele.attributeValue("name"));
                    propertyDefinition.setRef(ele.attributeValue("ref"));
                    propertyDefinitions.add(propertyDefinition);
                }
                beanDefinition.setDefinitions(propertyDefinitions);
                beanDefinitions.add(beanDefinition);
            }
            return beanDefinitions;
        }
    }

    4、动态生成bean对象,并且通过set方法注入对象。代码如下:

    package com.laoxu.test.day02.springDemo.parseXml;
    
    import java.beans.IntrospectionException;
    import java.beans.Introspector;
    import java.beans.PropertyDescriptor;
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    import org.dom4j.DocumentException;
    
    /**
     * 通过读取的XML配置信息,获取相应的Bean对象
     *
     */
    public class ApplicationContextBeanUtil {
        
        private String fileName;
        private List<BeanDefinition> beanDefinitions;
        @SuppressWarnings("unused")
        private ApplicationContextBeanUtil(){
            
        }
        
        public ApplicationContextBeanUtil(String fileName) throws DocumentException{
            super();
            this.fileName = fileName;
            init();
        }
        
        public void init() throws DocumentException{
            /*
             * 读取XML文件
             */
            beanDefinitions = ParseXMLUtil.readXML(fileName);
            injectObject(beanDefinitions);
        }
        
        public Object getBeanForUser(String beanID){
            return injectObject(beanDefinitions).get(beanID);
        }
        
        /*
         * 获取Bean对象
         */
        private static Object getBean(String beanName,List<BeanDefinition> beanDefinitions){
            if(beanName == null)
                return beanName;
            Map<String, Object> beans = instanceBeans(beanDefinitions);
            return beans.get(beanName);
        }
        
        /*
         * 获取bean的实例对象,存放到Map中
         */
        public static Map<String,Object> instanceBeans(List<BeanDefinition> beanDefinitions){
            Map<String,Object> beans = new HashMap<String, Object>();
            if(beanDefinitions == null||beanDefinitions.size() == 0)
                return beans;
            /*
             * 循环将类实例化
             */
            for (BeanDefinition beanDefinition : beanDefinitions) {
                if(beanDefinition.getId()!=null&&beanDefinition.getClassName()!=null){
                    try {
                        try {
                            //通过Class.forName(className).newInstance()创建对象
                            /*
                             * Class.forName(xxx.xx.xx) 返回的是一个类, .newInstance() 后才创建一个对象 
                             * Class.forName(xxx.xx.xx);的作用是要求JVM查找并加载指定的类,也就是说JVM会执行该类的静态代码段
                             */
                            beans.put(beanDefinition.getId(), Class.forName(beanDefinition.getClassName()).newInstance());
                        } catch (InstantiationException e) {
                            e.printStackTrace();
                        } catch (IllegalAccessException e) {
                            e.printStackTrace();
                        }
                    } catch (ClassNotFoundException e) {
                        e.printStackTrace();
                    }
                }
            }
            return beans;
        }
        /*
         * 依赖注入的方法,实现对象的依赖注入(通过set方法实现注入)
         */
        public static Map<String, Object> injectObject(List<BeanDefinition> beanDefinitions){
            
            Map<String, Object> beans = new HashMap<String, Object>();//经过注入的bean对象的哈希
            if(beanDefinitions==null||beanDefinitions.size()==0)
                return null;
            for (BeanDefinition beanDefinition : beanDefinitions) {
                Object bean = getBean(beanDefinition.getId(), beanDefinitions);
                if(bean == null)
                    return null;
                try {
                    //可以获取当前bean下的所有属性,包括get、set方法
                    PropertyDescriptor[] pds = Introspector.getBeanInfo(bean.getClass()).getPropertyDescriptors();
                    //遍历当前配置对象中的所有的property属性
                    for (PropertyDefinition propertyDefinition : beanDefinition.getDefinitions()) {
                        //遍历当前bean对象中的所有属性
                        for (PropertyDescriptor propertyDescriptor : pds) {
                            /*
                             * 通过比较配置文件中的property的name值与当前bean对象中的name值是否相同
                             * 来获取当前的set方法,将属性注入
                             */
                            if(propertyDefinition.getName().equals(propertyDescriptor.getName())){
                                Method setter = propertyDescriptor.getWriteMethod();
                                if(setter==null)
                                    return null;
                                setter.setAccessible(true);
                                //根据当前set方法的属性,获取当前property下的ref所引的对象
                                Object value = instanceBeans(beanDefinitions).get(propertyDefinition.getRef());
                                try {
                                    setter.invoke(bean, value);
                                    beans.put(beanDefinition.getId(), bean);
                                } catch (IllegalArgumentException e) {
                                    e.printStackTrace();
                                } catch (IllegalAccessException e) {
                                    e.printStackTrace();
                                } catch (InvocationTargetException e) {
                                    e.printStackTrace();
                                }
                            }
                        }
                    }
                } catch (IntrospectionException e) {
                    e.printStackTrace();
                }
            }
            return beans;
        }
    
        public List<BeanDefinition> getBeanDefinitions() {
            return beanDefinitions;
        }
    
        public void setBeanDefinitions(List<BeanDefinition> beanDefinitions) {
            this.beanDefinitions = beanDefinitions;
        }
        
    }

    5、测试类:

    package com.laoxu.test.day02.springDemo.test;
    
    import org.dom4j.DocumentException;
    
    import com.laoxu.test.day02.springDemo.entity.PersonServiceBean;
    import com.laoxu.test.day02.springDemo.parseXml.ApplicationContextBeanUtil;
    
    /**
     * 测试类
     * @author Administrator
     *
     */
    public class SpringTest {
    
        public static void main(String[] args) {
            String fileName = "com/laoxu/test/day02/springDemo/config/bean.xml";
            try {
                ApplicationContextBeanUtil contextBeanUtil = new ApplicationContextBeanUtil(fileName);
                PersonServiceBean bean = (PersonServiceBean) contextBeanUtil.getBeanForUser("personService");
                bean.say("lily");
            } catch (DocumentException e) {
                e.printStackTrace();
            }
            
        }
        
    }
  • 相关阅读:
    240. Search a 2D Matrix II
    442. Find All Duplicates in an Array
    4. Median of Two Sorted Arrays
    3. Longest Substring Without Repeating Characters
    poj 3616
    cf 337 div2 c
    poj 2385
    poj 2229
    uvalive 3231
    Entity Framework 学习初级篇7--基本操作:增加、更新、删除、事务
  • 原文地址:https://www.cnblogs.com/xuzhenmin/p/3298944.html
Copyright © 2020-2023  润新知