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

 

转载于:https://www.cnblogs.com/xuzhenmin/p/3298944.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值