内容源自: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. 201. Non Absorbing DFA

    题意好难看懂的说... 有限状态自动机DFA是这么一个有序组<Σ, U, s, T, phi>:Σ代表输入字符集,表示此自动机的工作范围:U代表所有的状态集合:s是初始状态:T是最终状态: ...

  2. 云平台学习--GitLab

    今天和师父还有孙老师一起,两位大神给我讲了下全世界最先进的云平台架构(Tigzx). 废话不多说,直接说代码的GitLab 第一步: 访问路径:http://git.dlanqi.com:30503, ...

  3. Java Control Statements

    Java Control Statements Java For Loop public class ForExample1 { public static void main(String[] ar ...

  4. Java实现下载BLOB字段中的文件

    概述 web项目的文件下载实现:servlet接收请求,spring工具类访问数据库及简化大字段内容获取. 虽然文章的demo中是以sevlet为平台,想必在spring mvc中也有参考意义. 核心 ...

  5. 2017 Hackatari Codeathon B. 2Trees(深搜)(想法)

    B. 2Trees time limit per test 0.75 seconds memory limit per test 256 megabytes input standard input ...

  6. 【Vijos 1607】【NOI 2009】植物大战僵尸

    https://vijos.org/p/1607 vijos界面好漂亮O(∩_∩)O~~ 对于一个植物x,和一个它保护的植物y,连一条边<x,y>表示x保护y,对于每个植物再向它左方的植物 ...

  7. [USACO 2018 Feb Gold] Tutorial

    Link: USACO 2018 Feb Gold 传送门 A: $dp[i][j][k]$表示前$i$个中有$j$个0且末位为$k$的最优解 状态数$O(n^3)$ #include <bit ...

  8. 【Tarjan】【LCA】【动态规划】【推导】hdu6065 RXD, tree and sequence

    划分出来的每个区间的答案,其实就是连续两个的lca的最小值. 即5 2 3 4 这个区间的答案是min(dep(lca(5,2)),dep(lca(2,3),dep(lca(3,4)))). 于是dp ...

  9. 【费用流】hdu5988 Coding Contest

    从源点向每个点连接容量为该点人数,费用为1的边, 把原图中的每条边拆成两条,一条容量为1,费用为1,另一条容量为ci-1,费用为1-pi 从每个点向汇点连接容量为该点面包数量,费用为1的边. 跑的费用 ...

  10. Problem J: 零起点学算法89——程序设计竞赛

    #include<stdio.h> //选择排序法 int main(){ ]; while(scanf("%d",&n)!=EOF){ ;i<n;i++ ...