内容源自:IOC理解   spring ioc注入的三种方式  ioc工厂bean深入理解

耦合性,在java中表现为类之间的关系,耦合性强说明类之间的依赖关系强;

侵入性:框架对代码的侵入;

在传统的java开发中具有高度的耦合性和侵入型。一个项目中,一般一个类都要依赖很多其他的类来完成自己的操作,我们往往采用new这个类的对象来调用他的方法,这样就造成了两个类的依赖关系太强,改一个地方,往往牵扯很多类牵扯大量的代码。可以说在这样的背景下,spring应运而生,一个轻量级的框架,解决传统企业开发的复杂性;使用普通的javaBean代替EJB技术。可以管理对象和对象之间的依赖关系,我们不需要自己建立对象,把这部分工作全部转交给容器完成,具有低耦合,对代码没有侵略性,对服务器没有依赖性特点的框架。 
而这个容器,即IOC.

理解IOC思想

使用ioc方式创建对象的目的,是为了以“被动”的方式形成对象之间的依赖关系。传统的开发过程中,不管是new,还是普通工厂,都需要目标对象主动创建、主动查找其需要的依赖对象 , 目标对象会将他的精力分散在不必要的非业务逻辑方面。IOC通过DI(依赖注入)把建立好的对象注入到目标对象中。

Spring IOC具体如何实现?

spring IOC容器的关键点: 
* 必须将被管理的对象定义到spring配置文件中 
* 必须定义构造函数或setter方法,让spring将对象注入过来

1.配置applicationContext.xml

<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-3.2.xsd">
    <bean id="userDao4MySqlImpl" class="com.bjsxt.spring.dao.UserDao4MySqlImpl"/>
    <bean id="userDao4OracleImpl" class="com.bjsxt.spring.dao.UserDao4OracleImpl"/>
    <bean id="userManager" class="com.bjsxt.spring.manager.UserManagerImpl">
        <!-- 构造方法注入
        <constructor-arg ref="userDao4OracleImpl"/>
         -->
         <!-- setter方法注入 -->
         <property name="userDao" ref="userDao4OracleImpl"/>
    </bean>
</beans>

2.注入的类:

package com.bjsxt.spring.dao;

public interface UserDao {

    public void save(String username, String password);
}
package com.bjsxt.spring.dao;

public class UserDao4MySqlImpl implements UserDao {

    public void save(String username, String password) {
        System.out.println("--------UserDao4MySqlImpl.save()-------");
    }
}
package com.bjsxt.spring.dao;

public class UserDao4OracleImpl implements UserDao {

    public void save(String username, String password) {
        System.out.println("--------UserDao4OracleImpl.save()-------");
    }
}

3.被注入的类:

package com.bjsxt.spring.manager;

public interface UserManager {
    public void save(String username, String password);
}
package com.bjsxt.spring.manager;

import com.bjsxt.spring.dao.UserDao;

public class UserManagerImpl implements UserManager {
    /**
     * 两种方式:如果这个类中需要注入对象,先建立对象属性,
     *      在写构造方法或者settet方法。
     *
     */
    private UserDao userDao;

/*  public UserManagerImpl(UserDao userDao) {
        this.userDao = userDao;
    } */

    public void save(String username, String password) {
        this.userDao.save(username, password);
    }

    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }
}

4.测试类:

package com.bjsxt.spring.client;

import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.bjsxt.spring.manager.UserManager;

public class Client {

    public static void main(String[] args) {
/*  传统的通过new对象建立类之间的关系
 * UserManager userManager = new UserManagerImpl(new UserDao4OracleImpl());
        UserManager userManager = new UserManagerImpl(new UserDao4MySqlImpl());
        userManager.save("张三", "123");*/
/**
 * IOC思想     通过工厂类解析xml文件,以“反射”的方式创建对象:
 */
        BeanFactory factory = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserManager userManager = (UserManager)factory.getBean("userManager");
        userManager.save("张三", "123");
/**
 * IOC思想   实际的执行过程,这也是为什么需要setter方法或构造方法的原因:
 */
//      UserManagerImpl userManager = new UserManagerImpl();
//      userManager.setUserDao(new UserDao4MySqlImpl());
//      userManager.save("张三", "123");
    }
}

spring ioc注入方式:

  • setter 原理 : 在目标对象中,定义需要注入的依赖对象对应的属性和setter方法;“让ioc容器调用该setter方法”,将ioc容器实例化的依赖对象通过setter注入给目标对象,封装在目标对象的属性中。
  • 构造器 原理 : 为目标对象提供一个构造方法,在构造方法中添加一个依赖对象对应的参数。ioc容器解析时,实例化目标对象时会自动调用构造方法,ioc只需要为构造器中的参数进行赋值;将ioc实例化的依赖对象作为构造器的参数传入。【接口注入 原理 : 为依赖对象提供一个接口实现,将接口注入给目标对象,实现将接口的实现类注入的效果。比如HttpServletRequest HttpServletResponse接口 注意:这是ioc提供的方式,spring中的ioc技术并没有实现该种注入方式】
  • 方法注入 原理 : 在目标对象中定义一个普通的方法,将方法的返回值设置为需要注入的依赖对象类型。通过ioc容器调用该方法,将其创建的依赖对象作为方法的返回值返回给目标对象。

具体实现

三种方法在实现上主要是被注入类以及applicationContext.xml不同,具体写法包括参数配置如下: 
action:

package com.etoak.action;

import com.etoak.dao.UserDaoImpl;

public class LoginAction {
    /*
     * 1 setter注入   struts2表单项封装就是用了setter注入
     *
       private UserDaoImpl ud;

       public void setUd(UserDaoImpl ud,String name) {
           this.ud = ud;
       }
    */
    /*
     * 2 构造器方式   构造器参数不固定,在xml中描述
       private UserDaoImpl ud;
       private String name;

       public LoginAction(UserDaoImpl ud,String name){
           this.ud = ud;
           this.name = name;
       }
    */
    /*
     * 3 方法注入:方法的返回值为要注入的对象类型
    */
    public UserDaoImpl etoak(){
        return null;
    }
    public void init(){
        System.out.println("loginActoin初始化了");
    }
    public String execute() throws Exception{
        etoak().login();
        /*ud.login();
        System.out.println("name---->"+name);*/
        return "success";
    }
}

applicationContext.xml:

<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-3.2.xsd"
    default-lazy-init="true">
    <!--
        default-lazy-init="true"
        将bean对象初始化延迟到getBean(),而不是容器启动时自动初始化
     -->

    <!--
        目的:使用spring的ioc技术管理LoginAction、UserDaoImpl
            实现被动注入
        被动注入前提:两个对象都需要交由ioc容器管理
        init-method:在bean初始化时自动执行
        property:setter方法注入
        constructor-arg : 为当前调用的构造器赋值
                    index值为构造器第几个参数
        ref: 表示赋值的类型为自定义的类型(引用)
        value: 为String 、 基本数据类型、 class类型赋值
        lookup-method  : 方法注入,bean值为要注入的对象, name为方法名
        scope : singleton 单例
                prototype 原型
                request   ioc实例化的bean对象存储在request还是在session范围内,这两个取值仅在web环境下
                session
         -->
    <bean id="action" class="com.etoak.action.LoginAction" init-method="init" lazy-init="true" scope="singleton">
        <!-- <property name="ud" ref="dao"></property>  setter注入-->
        <!-- <constructor-arg index="0" ref="dao"></constructor-arg> 构造器注入:有几个参数赋几个
        <constructor-arg index="1" value="aaa"></constructor-arg>    -->
        <lookup-method name="etoak" bean="dao"/> <!-- 方法注入 -->
    </bean>  <!-- lazy-init单独这个bean延迟初始化 -->
    <bean id="dao" class="com.etoak.dao.UserDaoImpl"></bean>
</beans>

> 我所理解的工厂bean:

我们在使用ioc容器形成类之间的依赖关系,也就是在配置文件中配置bean的时候,一般是class指向的是实体bean类,通过ref将另外一个bean对象注入到这个类中。如下图示:

这里圆圈里面的就是一个类,所以这个id为action的bean对象可以直接通过ref注入别的类中。然而当我们要注入一个接口,这个接口没有实现类的时候就不能这样操作了。因为无法实例化一个对象。这时我们就要采用工厂bean。像图中所示(整个例子下文有),要将UserDaoIf这个接口注入到LoginAction中,我们让DaoFactoryBean实现FactoryBean接口,这个类就会自动调用getObject()方法,返回我们需要的UserDaoIf实例,这时就可以注入到action里面了。 
所以,工厂bean解决了ioc容器无法直接实例化某个对象的问题

一、ioc工厂配置的bean分类:

划分依据: getBean("xx") 调用某个bean对象返回的对象实例类型是否是class属性指向的类型

1、普通bean getBean("xxx") == class 属性

2、工厂bean getBean("xxx") != class属性 (class属性中指向的是一个工厂类,调用这个bean对象,想要的并不是class属性指向的工厂 ,而是该工厂负责创建的实例对象。)

二、工厂bean的必要性:

当ioc无法或者不能直接实例化某个对象时,需要一个第三方工厂帮助其实例化该对象,将这个第三方工厂配置在ioc环境下,实现 ioc直接管理的对象(普通对象) 和 第三方工厂创建的对象(ioc无法直接实例的对象) 之间的依赖关系。

  • ioc无法实例化什么对象?
  • 接口类型对象,并且本工程中不允许提供接口的实现类。(因为ioc通过反射机制创建对象,接口不能反射)

下面,通过这个例子 来了解1 、 3这两种方式: 
applicationContext.xml:

<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-3.2.xsd">
    <!--
        使用ioc依赖注入实现LoginAction、UserDaoIf依赖关系

     -->
     <bean id="action" class="com.etoak.action.LoginAction">
        <!-- <property name="dao" ref="fb"></property> -->
        <property name="dao" ref="factory"></property>
     </bean>
     <!--
                1 静态工厂 ~ 工厂模式
            factory-method : 指向工厂类中提供的静态方法
                a  ioc容器会将具备改属性的bean当作工厂bean对待
                b  调用这个工厂bean时,返回的对象实例不在是class属性指向的对象类型
                    而是该工厂自动调用factory-method属性指向的方法(必须是静态的)返回的对象类型
                    所以这里getBean()得到的是UserDaoIf对象
        2 动态工厂(忽略)
      -->
      <bean id="factory" class="com.etoak.factory.DaoFactory"
            factory-method="getDao"></bean>
      <!--
        3 FactoryBean接口
            (UserDaoIf)getBean("fb")
            ioc容器会将所有实现了FactoryBean接口的类作为工厂bean对象
        调用工厂bean时返回的对象实例 是 该工厂自动调用其getObject()返回的对象实例
       -->
      <bean id="fb" class="com.etoak.factory.DaoFactoryBean"></bean>
</beans>

UserDaoIf.java

package com.etoak.dao;
/**
 * 以接口的方式为LoginAction提供登录检查服务
 * 只需要知道LoginAction要实现登录操作需要一个login()方法
 * 不需要知道login()方法如何实现
 * 用到的时候只需要远程调用其他服务器上的实现方法
 * @author D_xiao
 *
 */
public interface UserDaoIf  {
    public boolean login();
}

DaoFactory.java

package com.etoak.factory;

import com.etoak.dao.UserDaoIf;
/**
 * 静态工厂
 * @author D_xiao
 *
 */
public class DaoFactory {
    //UserDaoIf
    private static UserDaoIf dao;
    static{
        dao = new UserDaoIf(){
            public boolean login(){
                //不能实例化具体对象,但能调用远程的东西
                System.out.println("使用webservice技术远程调用其他服务器中的具体实现");
                return true;
            }
        };
    }
    public static UserDaoIf getDao(){
        return dao;
    }
}

DaoFactoryBean.java

package com.etoak.factory;

import org.springframework.beans.factory.FactoryBean;
import com.etoak.dao.UserDaoIf;
/**
 * FactoryBean接口,第三方工厂
 * @author D_xiao
 *
 */
public class DaoFactoryBean implements FactoryBean{

    @Override
    public Object getObject() throws Exception {
        // 当前工厂需要创建的对象实例
        return new UserDaoIf(){
            public boolean login(){
                System.out.println("使用webservice调用其他服务器方法");
                return true;
            }
        };
    }

    @Override
    public Class getObjectType() {
        // 描述当前工厂创建的实例类型
        return UserDaoIf.class;
    }

    @Override
    public boolean isSingleton() {
        // 描述创建的单例状态  单例/ 非单例
        return false;
    }

}

LoginAction.java

package com.etoak.action;

import com.etoak.dao.UserDaoIf;

public class LoginAction {

    private UserDaoIf dao;

    public void setDao(UserDaoIf dao) {
        this.dao = dao;
    }

    public String execute() throws Exception{
        dao.login();
        return "success";
    }
}

Test.java (测试)

package com.etoak.test;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;

import com.etoak.action.LoginAction;

public class Test {
    public static void main(String[] args) throws Exception{
        ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
          ac = new FileSystemXmlApplicationContext("src/applicationContext.xml");
         LoginAction la = (LoginAction)ac.getBean("action");
         //UserDaoImpl ud = ac.getBean(UserDaoImpl.class);
         la.execute();
    }
}

Spring框架学习(2)IOC学习的更多相关文章

  1. Spring MVC -- Spring框架入门(IoC和DI)

    Spring MVC是Spring框架中用于Web应用开发的一个模块.Spring MVC的MVC是Model-View-Controller的缩写.它是一个广泛应用于图像化用户交互开发中的设计模式, ...

  2. Spring框架annotation实现IOC介绍

    Spring学习笔记(三) 续Spring 学习笔记(二)之后,对Spring框架的annotation实现方法进行整理 本文目录 @Autowire 1 @Autowire+@Qualifier t ...

  3. Spring框架中的IOC?

    Spring中的org.springframework.beans包和org.SpringframeWork.context包构成了Spring框架IOC容器的基础.BeanFactory接口提供了一 ...

  4. 一、Spring的控制反转(IOC)学习

    一.控制反转 1.什么是控制反转? 控制反转(Inversion of Control,缩写为IoC),是面向对象中的一种设计原则,可以用来减低计算机代码之间的耦合度.其中最常见的方式叫做依赖注入(D ...

  5. Spring框架系列(四)--IOC控制反转和DI依赖注入

    背景: 如果对象的引用或者依赖关系的管理由具体对象完成,代码的耦合性就会很高,代码测试也变得困难.而IOC可以很好的解决这个问题,把这 些依赖关系交给框架或者IOC容器进行管理,简化了开发. IOC是 ...

  6. Spring框架中的IOC和DI的区别

    上次面试被问到IOC和DI的区别时,没怎么在意,昨天又被问到,感觉有点可惜.今晚总算抽点时间,查看了spring官方文档.发现,IoC更像是一种思想,DI是一种行为.为了降低程序的耦合度,利用spri ...

  7. 第四课:通过配置文件获取对象(Spring框架中的IOC和DI的底层就是基于这样的机制)

    首先在D盘创建一个文件hero.txt,内容为:com.hero.Hero(此处必须是Hero的完整路径) 接下来是Hero类 package com.hero; public class Hero ...

  8. spring学习12 -Spring 框架模块以及面试常见问题注解等

    以下为spring常见面试问题: 1.Spring 框架中都用到了哪些设计模式? Spring框架中使用到了大量的设计模式,下面列举了比较有代表性的: 代理模式—在AOP和remoting中被用的比较 ...

  9. Spring Framework 官方文档学习(二)之IoC容器与bean lifecycle

    到目前为止,已经看了一百页.再次感慨下,如果想使用Spring,那可以看视频或者找例子,但如果想深入理解Spring,最好还是看官方文档. 原计划是把一些基本接口的功能.层次以及彼此的关系罗列一下.同 ...

  10. Spring框架之IOC(控制反转)

    [TOC] 第一章Spring框架简介 IOC(控制反转)和AOP(面向方面编程)作为Spring框架的两个核心,很好地实现了解耦合.所以,简单来说,Spring是一个轻量级的控制反转(IoC)和面向 ...

随机推荐

  1. 寻找与网页内容相关的图片(二)reddit的做法

    正如前文所述,内容聚合网站,比如新浪微博.推特.facebook等网站对于网页的缩略图是刚需.为了让分享的内容引人入胜,网页的图片缩略图是必不可少的.年轻人的聚集地.社交新闻网站reddit也是一个这 ...

  2. LoadRunner Agent Runtime Settings Configuration启动报错

    解决方法: 关闭负载机器上的防火墙功能即可解决

  3. HDU 4348.To the moon SPOJ - TTM To the moon -可持久化线段树(带修改在线区间更新(增减)、区间求和、查询历史版本、回退到历史版本、延时标记不下放(空间优化))

    To the moon Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total ...

  4. 转:初探Windows Fuzzing神器----Winafl

    转:http://www.tuicool.com/articles/j2eqym6 小结:找到感兴趣的函数,计算偏移,自动化fuzz. 这是一篇客座文章,作者是乌云二进制漏洞挖掘白帽子 k0shl . ...

  5. 51nod 1052 (dp)

    最大M子段和 N个整数组成的序列a[1],a[2],a[3],…,a[n],将这N个数划分为互不相交的M个子段,并且这M个子段的和是最大的.如果M >= N个数中正数的个数,那么输出所有正数的和 ...

  6. HZAU 1199 Little Red Riding Hood(DP)

    Little Red Riding Hood Time Limit: 1 Sec  Memory Limit: 1280 MBSubmit: 853  Solved: 129[Submit][Stat ...

  7. 【BZOJ 3166】【HEOI 2013】Alo

    http://www.lydsy.com/JudgeOnline/problem.php?id=3166 这道题难点在于求能对一个次大值有贡献的区间. 设这个次大值为\(a_i\),\(a_i\)左边 ...

  8. AGC 012 C - Tautonym Puzzle

    题面在这里! 神仙构造啊qwqwq. 窝一开始只想到一个字符串长度是 O(log(N)^2) 的做法:可以发现一段相同的长度为n的字符串的贡献是 2^(n-1)-1 ,可以把它看成类二进制,枚举用了多 ...

  9. 【博弈论】【SG函数】【线段树】Petrozavodsk Summer Training Camp 2016 Day 9: AtCoder Japanese Problems Selection, Thursday, September 1, 2016 Problem H. Cups and Beans

    一开始有n个杯子,每个杯子里有一些豆子,两个人轮流操作,每次只能将一个豆子移动到其所在杯子之前的某个杯子里,不过可以移动到的范围只有一段区间.问你是否先手必胜. 一个杯子里的豆子全都等价的,因为sg函 ...

  10. 重拾vue2

    Vue组件 一.组件介绍 每一个组件都是一个vue实例 每个组件均具有自身的模板template,根组件的模板就是挂载点 每个组件模板只能拥有一个根标签 子组件的数据具有作用域,以达到组件的复用 二. ...