spring如何实现注入

spring如何实现注入

IOC(Inverse of Control)可翻译为“控制反转”,但大多数人都习惯将它称为“依赖注入”。在Spring中,通过IOC可以将实现类 、参数信息等配置在其对应的配置文件中 ,那么当需要更改实现类或参数信息时,只需要修改配置文件即可,这种方法在上例的基础上更进一步的降低了类与类之间的耦合。我们还可以对某对象所需要的其它对象进行注入 ,这种注入都是在配置文件中做的,Spring的IOC的实现原理利用的就是Java的反射机制,Spring还充当了工厂的角色,我们不需要自己建立工厂类 。Spring的工厂类会帮我们完成配置文件的读取、利用反射机制注入对象等工作,我们可以通过bean的名称获取对应的对象。

定义一个bean src/main/java/spring_IOC/JavaBean.java

package spring_IOC;

/**
 * Created by tom on 2016/5/18.
 */
public class JavaBean {
    String username;
    String password;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}

实例化一个类,利用反射,将其注入值 src/main/java/spring_IOC/SetValueByReflection.java

package spring_IOC;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * Created by tom on 2016/5/18.
 */
public class SetValueByReflection {
    /**
     * 实例化一个类,利用反射,将其注入值
     */
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        JavaBean bean = new JavaBean();
        //获取指定类的指定方法,
        Class c = Class.forName("spring_IOC.JavaBean");
        Method method = c.getMethod("setUsername", new Class[]{String.class});
        //对带有指定参数的指定对象调用由此 Method 对象表示的底层方法,调用对象javaBean的setuserName方法,参数为"hello world"
        method.invoke(bean, "hello world");
        System.out.println(bean.getUsername());
    }
}

实例化一个类,利用反射,用个map来摸拟在xml获取的属性名及值 src/main/java/spring_IOC/SetValueByReflectionLoop.java

package spring_IOC;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.beans.BeanInfo;
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.Map;

/**
 * Created by tom on 2016/5/18.
 */
public class SetValueByReflectionLoop {
    static Logger log = LoggerFactory.getLogger(BeanFactory.class);

    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException, IntrospectionException {
        //这个map对象用来模拟对属性文件解析获了的属性名与值
        Map<String, Object> map = new HashMap<>();
        map.put("username", "tomLuo");
        map.put("password", "954");

        Class bean = Class.forName("spring_IOC.JavaBean");
        Object obj = bean.newInstance();
        //获取对应class信息
        BeanInfo info = Introspector.getBeanInfo(bean);
        // 遍历指定类的属性
        PropertyDescriptor[] propertys = info.getPropertyDescriptors();
        for (int j = 0; j < propertys.length; j++) {
            System.out.println("属性:" + propertys[j].getName());
        }
        //获取其属性描述
        java.beans.PropertyDescriptor pd[] = info.getPropertyDescriptors();
        Method mSet = null;
        for (int k = 0; k < pd.length; k++) {
            if (map.containsKey(pd[k].getName())) {
                Object value=map.get(pd[k].getName());//将对应的属性值取出来
                mSet = pd[k].getWriteMethod();
                log.info("{} {} {}", pd[k].getName(), pd[k].getWriteMethod().getName(), pd[k].getReadMethod().getName());//password setPassword getPassword
                mSet.invoke(obj, value);//利用反射将567注入到bean 这儿实验将每个set方法的值都设置为567
            }
        }
        //将对象放入beanMap中,其中key为id值,value为对象
        JavaBean javaBean1 = (JavaBean) obj;
        System.out.println("userName=" + javaBean1.getUsername());
        System.out.println("password=" + javaBean1.getPassword());

    }
}

加载xml文件,利用反射,将其注入值 src/main/resources/config.xml

<?xml version="1.0" encoding="utf-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans">
    <bean id="javaBean" class="spring_IOC.JavaBean">
        <property name="username" value="tom"/>

        <property name="password" value="123"/>

    </bean>
</beans>

Bean工厂主要用来解析xml文件,获取属性名及值,然后利用反射,将其注入值 src/main/java/spring_IOC/BeanFactory.java

package spring_IOC;

import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

/**
 * Created by tom on 2016/5/18.
 */
public class BeanFactory {

    static Logger log = LoggerFactory.getLogger(BeanFactory.class);
    private Map<String, Object> beanMap = new HashMap<String, Object>();

    /**
     * bean工厂的初始化
     *
     * @param xml
     */
    public void init(String xml) {
        try {
            //读取指定的配置文件
            SAXReader reader = new SAXReader();
            //从class目录下获取指定的配置文件
            ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
            InputStream inputStream = classLoader.getResourceAsStream(xml);

            //读取xml文件
            Document document = reader.read(inputStream);
            //获取跟节点
            Element root = document.getRootElement();
            //遍历bean节点
            Element foo;
            for (Iterator iteBean = root.elementIterator("bean"); iteBean.hasNext(); ) {
                foo = (Element) iteBean.next();
                //获取bean的属性id和class
                Attribute id = foo.attribute("id");
                Attribute cls = foo.attribute("class");
                //利用java反射机制,通过class的名称获取Class对象
                log.debug("{}", cls.getText());
                Class bean = Class.forName(cls.getText());
                //获取对应class信息
                java.beans.BeanInfo info = java.beans.Introspector.getBeanInfo(bean);
                //获取其属性描述
                java.beans.PropertyDescriptor pd[] = info.getPropertyDescriptors();
                //设置值的方法
                Method mSet = null;
                //创建一个对象(创建此 Class 对象所表示的类的一个新实例。如同用一个带有一个空参数列表的 new 表达式实例化该类。如果该类尚未初始化,则初始化这个类。)
                Object obj = bean.newInstance();

                //遍历该bean的property属性
                for (Iterator iteProperty = foo.elementIterator("property"); iteProperty.hasNext(); ) {
                    Element elementProperty = (Element) iteProperty.next();
                    //获取该property的name属性
                    Attribute name = elementProperty.attribute("name");
                    //读取该属性值
                    String value = elementProperty.attribute("value").getText();
                    //String value = null;
                    //获取该property的子元素value的值
                    //for(Iterator iteValue = elementProperty.elementIterator("value");iteValue.hasNext();){
                    //      Element elementValue = (Element)iteValue.next();
                    //      value = elementValue.getText();
                    //      break;
                    //}
                    for (int k = 0; k < pd.length; k++) {
                        log.info(pd[k].getName());
                        if (pd[k].getName().equalsIgnoreCase(name.getText())) {
                            mSet = pd[k].getWriteMethod();//
                            log.info(mSet.getName());
                            //利用Java的反射机制调用对象的某个set方法,并将值设置进去
                            mSet.invoke(obj, value);//通过invoke方法来调用特定对象的特定方法,实现的原理都是基于Java的反射机制
                        }
                    }
                }
                //将对象放入beanMap中,其中key为id值,value为对象
                beanMap.put(id.getText(), obj);
            }

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

    /**
     * 通过bean的id获取bean的对象.
     *
     * @param beanName bean的id
     * @return 返回对应对象
     */
    public Object getBean(String beanName) {
        Object obj = beanMap.get(beanName);
        return obj;
    }

    public static void main(String[] args) {
        BeanFactory factory = new BeanFactory();
        factory.init("config.xml");
        JavaBean javaBean = (JavaBean) factory.getBean("javaBean");
        System.out.println("userName=" + javaBean.getUsername());
        System.out.println("password=" + javaBean.getPassword());
    }
}

可以看到,虽然在main()方法中没有对属性赋值,但属性值已经被注入,在BeanFactory类中的Class bean = Class.forName(cls.getText()); 通过类名来获取对应的类,mSet.invoke(obj, value);通过invoke方法来调用特定对象的特定方法,实现的原理都是基于Java的反射机制

源码浏览: https://github.com/tomlxq/job-test/tree/master/java-base/src/main/java/spring_IOC

时间: 2024-11-05 23:28:25

spring如何实现注入的相关文章

【Spring】Construcotrer注入和setter注入不同的XML写法方式

林炳文Evankaka原创作品.转载请注明出处http://blog.csdn.net/evankaka 本文主要讲解了Spring中constructor注入的4种不同写法和sette的3种不同写法 一.constructor注入4种不同写法 通过构造方法注入,就相当于给构造方法的参数传值set注入的缺点是无法清晰表达哪些属性是必须的,哪些是可选的,构造注入的优势是通过构造强制依赖关系,不可能实例化不完全的或无法使用的bean. 第1种方法:直接传值 <!-- constructor方式注入写

spring中依赖注入方式总结

Spring中依赖注入的四种方式 在Spring容器中为一个bean配置依赖注入有三种方式: · 使用属性的setter方法注入  这是最常用的方式: · 使用构造器注入: · 使用Filed注入(用于注解方式). 使用属性的setter方法注入 首先要配置被注入的bean,在该bean对应的类中,应该有要注入的对象属性或者基本数据类型的属性.例如:为UserBiz类注入UserDAO,同时为UserBiz注入基本数据类型String,那么这时,就要为UserDAO对象和String类型设置se

(spring-第3回)spring的依赖注入-属性、构造函数、工厂方法等的注入

Spring要把xml配置中bean的属性实例化为具体的bean,"依赖注入"是关卡.所谓的"依赖注入",就是把应用程序对bean的属性依赖都注入到spring容器中,由spring容器实例化bean然后交给程序员.spring的依赖注入有属性注入.构造函数注入.工厂方法注入等多种方式,下面用几个简单的栗子来一一道来. 一.首先是属性注入: 代码001 1 <?xml version="1.0" encoding="UTF-8&q

java的反射原理与Spring的自动注入(转载)

Java反射原理与Spring的自动注入 反射的定义 java的反射机制就是在运行状态中, 对于任意一个类都能够知道这个类的所有属性和方法; 对于任意一个对象,都能够调用它的任意一个方法和属性. 这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制. Sping的自动注入原理 一个Bean的类: public class User{ private String username; private String mobile; public String getUsernam

使用spring注解,注入sessionFactory类

简述 目前使用spring hibernate作为项目的框架,并且使用注解方式进行对象装载.在装载Dao对象的时候常常需要注入sessionFactory对象,通常的做法是Dao继承至HibernateDaoSuppor,t然后在Dao中添加setSuperSessionFactory 方法进行注入的,这几天网上又看到一种更好的方法,所以这里就把这两种方法都记录一下. 方法一(继承HibernateDaoSupport) 这个是比较常用的方法,看到很多文章中都使用这种方式. 前置条件: sess

第二十七天 春之细雨润物于无形 —Spring的依赖注入

6月11日,晴."夏条绿已密,朱萼缀明鲜.炎炎日正午,灼灼火俱燃." IT人习惯把具体的事物加工成的形状一致的类,正是这样的一致,加上合适的规范,才能彰显对象筋道的牙感和bean清香的味道.Spring比谁都清楚OO的奥妙,让组件之间的依赖关系由容器在运行时期决定,称作依赖注入(Dependency Injection). 下面用一通俗的例子,一探依赖注入奥妙. 设计模式中的一个原则:针对接口编程,不要针对实现编程. 一.设计两个接口: (1)奶制品接口-MilkProductInte

Spring的依赖注入(DI)三种方式

Spring依赖注入(DI)的三种方式,分别为: 1.  接口注入 2.  Setter方法注入 3.  构造方法注入 下面介绍一下这三种依赖注入在Spring中是怎么样实现的. 首先我们需要以下几个类: 接口 Logic.java 接口实现类 LogicImpl.java 一个处理类 LoginAction.java 还有一个测试类 TestMain.java Logic.java如下: package com.spring.test.di; public interface Logic {

spring的依赖注入的最常见的两种方法

1 package com.lsz.spring.action; 2 3 public class User { 4 /** 5 * set注入 6 */ 7 private String username; 8 public void setUsername(String username) { 9 this.username=username; 10 } 11 public String getUsername() { 12 return username; 13 } 14 /* 15 <b

spring的依赖注入【NC产品中也用到spring的依赖注入】

下面设计到的类有EditPsndocAction跟RefreshPsndocAction这个两个类, 而我想要的最终效果是: 下面解释一下流程“ 如下图所示:因为NC产品中使用了spring的的依赖注入.所以我这里可以这样子调用.直接调用定刷新按钮的bean . 在EditPsndocAction这个类中,用spring的依赖注入的一个方式.给对象赋值 注意一点就是:RefreshPsndocAction 是刷新按钮对应的ben的名称.也就是 最后在EdictPsndocAction这个类的do

二、Spring的依赖注入

Spring的依赖注入 1.理解依赖注入 (1)A对象需要调用B对象的方法,这种情形被称为依赖注入,即A对象依赖B对象:依赖注入(DI)也被成为控制反转(IoC): (2)依赖注入的两种方式: 1)设值注入:IoC容器通过使用成员变量的setter方法来注入被依赖对象: 2)构造注入:IoC容器通过使用构造器来注入被依赖的对象: 2.设置注入 (1)Bean与Bean之间的依赖关系由Spring管理,Spring采用setter方法为目标Bean注入所需要的值,这种注入方式被称为设值注入: (2