菜单

Spring的IOC和DI

2018年11月15日 - jQuery

一、了解Spring IOC/DI

重要参照了http://www.cnblogs.com/xiaoxi/p/5930736.html、http://blog.csdn.net/it\_man/article/details/4402245

  1:Spring有有限非常核心技术,控制反转(Inversion of Control,
IOC)/依赖注入(Dependency Injection,DI)和面向切面编程(Aspect Oriented
Programming,AOP)

相同、谈谈IOC的了解?IOC是怎么落实之?

Ioc意味着将公计划好的目标交给容器控制,而非是人情的当公的对象中一直控制。如何掌握好Ioc呢?理解好Ioc的基本点是若明白“谁说了算谁,控制什么,为何是反转(有反转就应产生凑巧改变了),哪些方面反转了”,那咱们来深切解析一下:

Bromon对于因注入和控制反转的任课:

  2. IOC/DI:
它之所以来保管有的java类,类对象的缔造和负关系都是因为IOC/DI进行控制。控制反转(IOC)和倚重注入(DI)在spring中意味着一致种意思,只是看题目的角度不同,例如

其次、浅谈Spring的贯彻机制

IOC的重大是在系统运行过程中,动态的朝向有对象提供它所用之另对象。这个提供的法子是经DI(依赖注入)来贯彻之。比如,A类需要一个B类对象来形成有动作,以前是A类自己new一个B,有了Spring之后,只需要报告spring,A中要一个B,至于B怎么布局,何时构造,A完全无待care,只待以它需要的时候语要就行了。
以系运行时,spring会在宜时候做一个B,然后如打针一样,注射到A中,从而成就了目标之间的涉嫌控制。A需要借助B才得以健康运作,而B对象是由于spring注入及A中错过之。依赖注入就是这样来之。

  当以A类中new一个B类时,控制权由A掌握,可以了解啊操纵正转,当A类使用的B类实例有spring创建时,控制权由spring掌握,就是控制反转;

老三、屌丝版的Spring的IOC和DI实现

脚是一个Bean类,用来存放在一个Bean拥有的属性

   /* Bean Id */
    private String id;
    /* Bean Class */
    private String type;
    /* Bean Property */
    private Map<String, Object> properties = new HashMap<String, Object>();

一个Bean包括id,type(类全域名),和Properties(属性域)。

连通下Spring
就起加载我们的配置文件了,将我们安排的信息保存在一个HashMap中,HashMap的key就是Bean
的 Id ,HasMap
的value是这个Bean
,只有这么咱们才能够透过context.getBean(“animal”)这个方式赢得Animal这个看似。我们还懂得Spirng可以注入基本项目,而且得注入像List,Map这样的品种,接下去就是吃咱盖Map为例看看Spring是怎保存之吧。

<bean id="test" class="Test">
        <property name="testMap">
            <map>
                <entry key="a">
                    <value>1</value>
                </entry>
                <entry key="b">
                    <value>2</value>
                </entry>
            </map>
        </property>
    </bean>

Spring是哪些保存上面的配备也?代码如下:
Map配置可以像下的:

if (beanProperty.element("map") != null) {
                    Map<String, Object> propertiesMap = new HashMap<String, Object>();
                    Element propertiesListMap = (Element) beanProperty
                            .elements().get(0);
                    Iterator<?> propertiesIterator = propertiesListMap
                            .elements().iterator();
                    while (propertiesIterator.hasNext()) {
                        Element vet = (Element) propertiesIterator.next();
                        if (vet.getName().equals("entry")) {
                            String key = vet.attributeValue("key");
                            Iterator<?> valuesIterator = vet.elements()
                                    .iterator();
                            while (valuesIterator.hasNext()) {
                                Element value = (Element) valuesIterator.next();
                                if (value.getName().equals("value")) {
                                    propertiesMap.put(key, value.getText());
                                }
                                if (value.getName().equals("ref")) {
                                    propertiesMap.put(key, new String[] { value
                                            .attributeValue("bean") });
                                }
                            }
                        }
                    }
                    bean.getProperties().put(name, propertiesMap);
                }

连片下去便进去最中心组成部分了,让咱省Spring
到底是怎指注入的吧,实际据注入的思索也甚粗略,它是透过反射机制实现的,在实例化一个像样时,它通过反射调用类中set方法以预保存在HashMap中之类属性注入及类似吃。给我们看实际它是怎开的吧。
率先实例化一个好像,像这样:

public static Object newInstance(String className) {
        Class<?> cls = null;
        Object obj = null;
        try {
            cls = Class.forName(className);
            obj = cls.newInstance();
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        } catch (InstantiationException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
        return obj;
    }

继之她用这看似的乘注入进来,像这样:

public static void setProperty(Object obj, String name, String value) {
        Class<? extends Object> clazz = obj.getClass();
        try {
            String methodName = returnSetMthodName(name);
            Method[] ms = clazz.getMethods();
            for (Method m : ms) {
                if (m.getName().equals(methodName)) {
                    if (m.getParameterTypes().length == 1) {
                        Class<?> clazzParameterType = m.getParameterTypes()[0];
                        setFieldValue(clazzParameterType.getName(), value, m,
                                obj);
                        break;
                    }
                }
            }
        } catch (SecurityException e) {
            throw new RuntimeException(e);
        } catch (IllegalArgumentException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        } catch (InvocationTargetException e) {
            throw new RuntimeException(e);
        }
}

最后它们将这个近乎的实例返回给咱,我们就可据此了。我们要因为Map为条例看看她是怎么开的,我形容的代码里面凡是创办一个HashMap并把该HashMap注入到用注入的近乎中,像这么:

if (value instanceof Map) {
                Iterator<?> entryIterator = ((Map<?, ?>) value).entrySet()
                        .iterator();
                Map<String, Object> map = new HashMap<String, Object>();
                while (entryIterator.hasNext()) {
                    Entry<?, ?> entryMap = (Entry<?, ?>) entryIterator.next();
                    if (entryMap.getValue() instanceof String[]) {
                        map.put((String) entryMap.getKey(),
                                getBean(((String[]) entryMap.getValue())[0]));
                    }
                }
                BeanProcesser.setProperty(obj, property, map);
            }

然咱们就得据此Spring
给咱创建的类了本Spring能不负众望的远不止这些,这个示例程序仅仅提供了Spring最基本的凭注入力量中之平等有。

  依赖注入可以掌握吧A类依赖让spring,由spring注入B类。控制反转是空洞的定义,只是提出了一如既往种植“控制”的道,而借助注入是spring框架实现“控制反转”的具体方法。

  3. IOC/DI工作规律:spring
IOC/DI的愈益直观的叫法是容器,这是因spring可以管理很多近似,当得有一样近乎对象的实例时,spring就见面提供相应的实例,就如是一个器皿内

  可以放入很多东西,需要什么虽拿走什么。那么在spring容器中还来啊像样可应用啊?这要先定义在spring的配备文件中,默认的布文件名称是applicationContext.xml

  例如在部署文件被定义了A类以及B类,而A类吃利用到了B类,那么配置文件中重新定义好这种依赖关系,即可由Spring自动地管B类实例注入及A类中,但是,这种注入是发生规范的,

  类需要符合Javabean的概念规范,在A类吃需要定义对B类赋值的setter方法。这是Spring对保管的切近唯一的要求,不待像EJB那样实现框架本身的别样接口,也是spring被如

  也轻量级框架的由。

其次、IOC/DI使用及之技巧

  1.
JDOM:JDOM是对准xml文件进行剖析的技术,Spring的布局文件applicationContext.xml就是由于JDOM进行分析的,它好领到出xml文件中定义之标签和属性值。

  1.1 环境之搭建:

  图片 1

  1.2 StudentAction.java

public class StudentAction {
    private StudentService studentService;

    public void setStudentService(StudentService studentService) {
        this.studentService = studentService;
    }
    public void printName() {
        System.out.println(studentService.getName());
    }
}

  1.3 StudentServiceImpl.java

public class StudentServiceImpl implements StudentService{
    private StudentDao studentDao;

    public void setStudentDao(StudentDao studentDao) {
        this.studentDao = studentDao;
    }

    public String getName() {
        return studentDao.getName();
    }
}

  1.4 StudentService.java

public interface StudentService {
    public String getName();
}

  1.5 StudentDao.java

public interface StudentDao {
    public String getName();
}

  1.6 StudentDaoImpl.java

public class StudentDaoImpl implements StudentDao{

    public String getName() {
        return "Jike Wang";
    }
}

  1.7 测试

public class TestAction {
public static void main(String[] args) {
    //使用ApplicationContext接口的实现类ClassPathXmlApplicationContext加载spring配置文件
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("/applicationContext.xml");
    //通过ApplicationContext接口的getBean方法获取id或name为studentAction的Bean实例
    StudentAction studentAction = (StudentAction) applicationContext.getBean("studentAction");
    //调用方法
    studentAction.printName();
}
}

  1.8 使用jdom模拟spring解析xml文件,读取关键信息

  自定义XML代码:

<?xml version="1.0" encoding="UTF-8"?>
<beans>
    <!-- 定义StudentDaoImpl对象并指定id为studentDao -->
    <bean id="studentDao" class="com.IOC.dao.impl.StudentDaoImpl"></bean>
    <!-- 定义StudentServiceImpl对象并指定id为studentService-->
    <bean id="studentService" class="com.IOC.service.impl.StudentServiceImpl">
        <property name="studentDao" ref="studentDao"></property>
    </bean>
    <!-- 定义StudentAction对象并指定id为studentAction -->
    <bean id="studentAction" class="com.IOC.action.StudentAction">
        <property name="studentService" ref="studentService"></property>
    </bean>
</beans>

public class TestJDOM {
public static void main(String[] args) {
    String path = "src/main/resources/applicationContext.xml";//xml文件目录
    //用于创建文档对象
    SAXBuilder sb = new SAXBuilder();
    //构造的XML文档对象
    Document doc;
    try {
        //创建文档对象
        doc = sb.build(path);
        //得到文档的根元素<beans>
        Element rootElement = doc.getRootElement();

        //得到文档的所有<bean>
        List<Element> list = rootElement.getChildren("bean");
        for (Element element : list) {
            //得到<bean>的id属性值
            String id = element.getAttributeValue("id");
            //得到<bean>的class属性值
            String classValue = element.getAttributeValue("class");
            //得到<bean>的子元素<property>
            Element propertyElement = element.getChild("property");
            String propertyName = null;
            String propertyRef = null;
            if (propertyElement != null) {
                //得到<property>的name属性值
                propertyName = propertyElement.getAttributeValue("name");
                //得到property的内容
                propertyRef = propertyElement.getAttributeValue("ref");
            }
            System.out.println("========================");
            System.out.println("id="+id);
            System.out.println("class="+classValue);
            System.out.println("propertyName="+propertyName);
            System.out.println("propertyRef="+propertyRef);
            System.out.println("========================");
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}
}

测试结果:

图片 2

 

 2.
反光机制:对安排文件被的类名使用反射机制得以兑现类似加载初始化等工作,也足以调用类的办法进行性能注入,java.lang.reflect提供了照相关的工具

public class TestReflect {
    public static void main(String[] args) {
        //表示StudentDao接口全路径
        String studentDao = "com.IOC.dao.StudentDao";
        //表示StudentService接口全路径
        String studentService = "com.IOC.service.StudentService";
        //表示StudentDaoImpl类全路径
        String studentDaoImpl = "com.IOC.dao.impl.StudentDaoImpl";
        //表示StudentServiceImpl
        String studentServiceImpl = "com.IOC.service.impl.StudentServiceImpl";
        //表示StudentAction类全路径
        String studentAction = "com.IOC.action.StudentAction";

        //表示setStudentService方法的字符串
        String setStudentService = "setStudentService";
        //表示setStudentDao方法的字符串
        String setStudentDao = "setStudentDao";
        try {
            //使用全路径字符串加载StudentDao类别
            Class studentDaoClass = Class.forName(studentDao);
            //使用全路径字符串加载StudentService类别
            Class studentServiceClass = Class.forName(studentService);
            //使用全路径字符串加载StudentDaoImpl类别
            Class studentDaoImplClass = Class.forName(studentDaoImpl);
            //使用全路径字符串加载StudentServiceImpl类别
            Class studentServiceImplClass = Class.forName(studentServiceImpl);
            //使用全路径字符串加载StudentAction类别
            Class studentActionClass = Class.forName(studentAction);

            //setStudentDao方法签名,相当于获取次此方法,使用类别获取setStudentDao方法
            Method setDaoMethod = studentServiceImplClass.getMethod(setStudentDao, studentDaoClass);
            //setStudentService方法签名,使用类别获取setStudentService方法
            Method setServiceMethod = studentActionClass.getMethod(setStudentService, studentServiceClass);

            //创建StudentDaoImpl对象,相当于new StudentDaoImpl(),但返回的是Object对象
            Object studentDaoImplnstance = studentDaoImplClass.newInstance();
            //创建StudentServiceImpl对象,相当于new StudentServiceImpl(),但返回的是Object对象
            Object studentServiceImplInstance = studentServiceImplClass.newInstance();
            //创建StudentAction对象,相当于new StudentAction(),但返回的是Object对象
            Object studentActionInstance = studentActionClass.newInstance();

            //使用反射机制调用StudentServiceImpl的setStudentDao方法,参数是StudentDaoImpl对象,
            //第一个参数是执行方法的类实例,第二个参数是方法参数
            setDaoMethod.invoke(studentServiceImplInstance, studentDaoImplnstance);
            setServiceMethod.invoke(studentActionInstance, studentServiceImplInstance);
            //调用StudentAction的printName方法
            ((StudentAction)studentActionInstance).printName();

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

测试结果:

图片 3

 

相关文章

标签:

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图