码迷,mamicode.com
首页 > 编程语言 > 详细

spring-ioc

时间:2015-07-30 00:44:45      阅读:228      评论:0      收藏:0      [点我收藏+]

标签:ioc   spring   spring framework   

Spring IOC

        Spring Framework简介中介绍了spring的整体框架,这篇文章主要介绍Spring Ioc。那么,什么是IOC呢?IOC是Inversion of Control的缩写,是一个非常重要的面向对象法则,主要目的是用来消减计算机程序的耦合问题,同样也是Spring框架的核心。IOC一般分为两种类型,依赖注入(Dependency Injection)和依赖查找(Dependency Lookup)作为spring的核心,那IOC到底是什么呢?
      在揭开谜底之前,下面先看看传统模式下的编程风格,如下代码所示
public class User{
    private String id;
    private String name;
    private String password;
    private Date birthday;
    //ignore other properties...
    //ignore setter getter method	
}

public interface IUserDao{
    public void add(User user);
    public void delete(User user);
    public List<User> findAll();
}

public class UserDaoImpl{
    public void add(User user){
        //ignore the implementation
    }
        
    public void delete(User user){
        //ignore the implementation
    }

    public List<User> findAll(){
        //ignore the implementation
    } 
}

public class UserController{
    private IUserDao userDao = new UserDaoImpl();

    @RequestMapping("/user/add")
    public void add(User user){
        userDao.add(user);
    }

    @RequestMapping("/user/delete")
    public void delete(User user){
        userDao.add(user);
    }
    
    @RequestMapping("/user/findAll")
    public void findAll(User user){
        List<User> allUser = userDao.findAll();
    }
}
       在这里面,UserController调用private IUserDao userDao = new UserDaoImpl()来初始化userDao。由于java是一门编译语言,也就是将.java变成.class的过程。在这个过程中捆绑了IUserDao的实现,也就是UserDaoImpl。虽然开发者使用了面向接口编程的风格来书写代码,但是还是和UserDaoImpl捆绑在了一起。如果后期开发中,为IUserDao提供另外一种实现,比如:将orm框架由mybatis换成了hibernate,那么就需要修改源码UserController的实现。传统模式中,一个类依赖的其他类都由自己维护,需要什么类,就new一个。这种开发方式的耦合性比较高,不利于后期的维护。那么既然这种方式不好,那么有没有一种其他办法来解决这个问题呢?没错,IOC可以非常好的解决这个问题。
       IOC是一个容器,将所有的java bean对象交给IOC来管理,其他类在初始化时,依赖的类不是自己主动new一个,而是由IOC主动注入,这个过程恰好与传统模式相反,所以我们称之为控制反转。由于控制反转这个词语非常的抽象,所以IOC也叫做依赖注入,按字面意思理解就是:这个类依赖其他什么类,那么IOC就帮你注入这个类。下面看如下代码
public class User{
    private String id;
    private String name;
    private String password;
    private Date birthday;
    //ignore other properties...
    //ignore setter getter method<span style="white-space:pre">	</span>
}


public interface IUserDao{
    public void add(User user);
    public void delete(User user);
    public List<User> findAll();
}

@Repository
public class UserDaoImpl{
    public void add(User user){
        //ignore the implementation
    }
        
    public void delete(User user){
        //ignore the implementation
    }


    public List<User> findAll(){
        //ignore the implementation
    } 
}

@Controller
public class UserController{
    //主动注入这个类
      @Autowired
    private IUserDao userDao userDao;


    @RequestMapping("/user/add")
    public void add(User user){
        userDao.add(user);
    }


    @RequestMapping("/user/delete")
    public void delete(User user){
        userDao.add(user);
    }
    
    @RequestMapping("/user/findAll")
    public void findAll(User user){
        List<User> allUser = userDao.findAll();
    }
}
       从代码中我们可以看到,这两份代码几乎是一样的,就只是去掉了userDao的实现类,在userDao变量中加入了@Autowired注解而已。没错,这就是spring的厉害之处,因为spring是一种无侵入式的轻量级框架。那么spring是如何实现控制反转的呢?下面先给出一个spring ioc图
技术分享

       
       从图中可以看到,图中一种由三个元素构成:configuration metadata(源信息),business object,spring container。由三者可以产生一个fully configured system(可运行的系统)。其中business object为业务逻辑代码,也就是前面例子中的UserDaoImpl,UserController。configuration metadata为源信息,也就是告诉spring container如何去实例化bean,注入bean依赖的类,在前面的例子中,@Controller,@Repository,@Autowired就是告诉spring container UserController与UserDaoImpl为java bean对象,然后UserController依赖于IUserDao。spring container拿到这些源信息后,就会尝试去完成任务,如果成功了,那么系统就准备就绪了。
       下面深入到源码处去观察下spring container是如何完成任务的。在IOC模块中,大量使用了工厂设计模式来完成类的初始化。整个IOC中,最大的工厂接口便是BeanFactory,里面定义了了一些基本的方法去获取java bean,如下代码所示
       
/*
 * Copyright 2002-2013 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.beans.factory;

import org.springframework.beans.BeansException;

/**
 * The root interface for accessing a Spring bean container.
 * This is the basic client view of a bean container;
 * further interfaces such as {@link ListableBeanFactory} and
 * {@link org.springframework.beans.factory.config.ConfigurableBeanFactory}
 * are available for specific purposes.
 *
 * <p>This interface is implemented by objects that hold a number of bean definitions,
 * each uniquely identified by a String name. Depending on the bean definition,
 * the factory will return either an independent instance of a contained object
 * (the Prototype design pattern), or a single shared instance (a superior
 * alternative to the Singleton design pattern, in which the instance is a
 * singleton in the scope of the factory). Which type of instance will be returned
 * depends on the bean factory configuration: the API is the same. Since Spring
 * 2.0, further scopes are available depending on the concrete application
 * context (e.g. "request" and "session" scopes in a web environment).
 *
 * <p>The point of this approach is that the BeanFactory is a central registry
 * of application components, and centralizes configuration of application
 * components (no more do individual objects need to read properties files,
 * for example). See chapters 4 and 11 of "Expert One-on-One J2EE Design and
 * Development" for a discussion of the benefits of this approach.
 *
 * <p>Note that it is generally better to rely on Dependency Injection
 * ("push" configuration) to configure application objects through setters
 * or constructors, rather than use any form of "pull" configuration like a
 * BeanFactory lookup. Spring's Dependency Injection functionality is
 * implemented using this BeanFactory interface and its subinterfaces.
 *
 * <p>Normally a BeanFactory will load bean definitions stored in a configuration
 * source (such as an XML document), and use the {@code org.springframework.beans}
 * package to configure the beans. However, an implementation could simply return
 * Java objects it creates as necessary directly in Java code. There are no
 * constraints on how the definitions could be stored: LDAP, RDBMS, XML,
 * properties file, etc. Implementations are encouraged to support references
 * amongst beans (Dependency Injection).
 *
 * <p>In contrast to the methods in {@link ListableBeanFactory}, all of the
 * operations in this interface will also check parent factories if this is a
 * {@link HierarchicalBeanFactory}. If a bean is not found in this factory instance,
 * the immediate parent factory will be asked. Beans in this factory instance
 * are supposed to override beans of the same name in any parent factory.
 *
 * <p>Bean factory implementations should support the standard bean lifecycle interfaces
 * as far as possible. The full set of initialization methods and their standard order is:<br>
 * 1. BeanNameAware's {@code setBeanName}<br>
 * 2. BeanClassLoaderAware's {@code setBeanClassLoader}<br>
 * 3. BeanFactoryAware's {@code setBeanFactory}<br>
 * 4. ResourceLoaderAware's {@code setResourceLoader}
 * (only applicable when running in an application context)<br>
 * 5. ApplicationEventPublisherAware's {@code setApplicationEventPublisher}
 * (only applicable when running in an application context)<br>
 * 6. MessageSourceAware's {@code setMessageSource}
 * (only applicable when running in an application context)<br>
 * 7. ApplicationContextAware's {@code setApplicationContext}
 * (only applicable when running in an application context)<br>
 * 8. ServletContextAware's {@code setServletContext}
 * (only applicable when running in a web application context)<br>
 * 9. {@code postProcessBeforeInitialization} methods of BeanPostProcessors<br>
 * 10. InitializingBean's {@code afterPropertiesSet}<br>
 * 11. a custom init-method definition<br>
 * 12. {@code postProcessAfterInitialization} methods of BeanPostProcessors
 *
 * <p>On shutdown of a bean factory, the following lifecycle methods apply:<br>
 * 1. DisposableBean's {@code destroy}<br>
 * 2. a custom destroy-method definition
 *
 */
public interface BeanFactory {

	/**
	 * Used to dereference a {@link FactoryBean} instance and distinguish it from
	 * beans <i>created</i> by the FactoryBean. For example, if the bean named
	 * {@code myJndiObject} is a FactoryBean, getting {@code &myJndiObject}
	 * will return the factory, not the instance returned by the factory.
	 */
	String FACTORY_BEAN_PREFIX = "&";

	/**
	 * Return an instance, which may be shared or independent, of the specified bean.
	 * <p>This method allows a Spring BeanFactory to be used as a replacement for the
	 * Singleton or Prototype design pattern. Callers may retain references to
	 * returned objects in the case of Singleton beans.
	 * <p>Translates aliases back to the corresponding canonical bean name.
	 * Will ask the parent factory if the bean cannot be found in this factory instance.
	 * @param name the name of the bean to retrieve
	 * @return an instance of the bean
	 * @throws NoSuchBeanDefinitionException if there is no bean definition
	 * with the specified name
	 * @throws BeansException if the bean could not be obtained
	 */
	Object getBean(String name) throws BeansException;

	/**
	 * Return an instance, which may be shared or independent, of the specified bean.
	 * <p>Behaves the same as {@link #getBean(String)}, but provides a measure of type
	 * safety by throwing a BeanNotOfRequiredTypeException if the bean is not of the
	 * required type. This means that ClassCastException can't be thrown on casting
	 * the result correctly, as can happen with {@link #getBean(String)}.
	 * <p>Translates aliases back to the corresponding canonical bean name.
	 * Will ask the parent factory if the bean cannot be found in this factory instance.
	 * @param name the name of the bean to retrieve
	 * @param requiredType type the bean must match. Can be an interface or superclass
	 * of the actual class, or {@code null} for any match. For example, if the value
	 * is {@code Object.class}, this method will succeed whatever the class of the
	 * returned instance.
	 * @return an instance of the bean
	 * @throws NoSuchBeanDefinitionException if there is no such bean definition
	 * @throws BeanNotOfRequiredTypeException if the bean is not of the required type
	 * @throws BeansException if the bean could not be created
	 */
	<T> T getBean(String name, Class<T> requiredType) throws BeansException;

	/**
	 * Return the bean instance that uniquely matches the given object type, if any.
	 * @param requiredType type the bean must match; can be an interface or superclass.
	 * {@code null} is disallowed.
	 * <p>This method goes into {@link ListableBeanFactory} by-type lookup territory
	 * but may also be translated into a conventional by-name lookup based on the name
	 * of the given type. For more extensive retrieval operations across sets of beans,
	 * use {@link ListableBeanFactory} and/or {@link BeanFactoryUtils}.
	 * @return an instance of the single bean matching the required type
	 * @throws NoSuchBeanDefinitionException if no bean of the given type was found
	 * @throws NoUniqueBeanDefinitionException if more than one bean of the given type was found
	 * @since 3.0
	 * @see ListableBeanFactory
	 */
	<T> T getBean(Class<T> requiredType) throws BeansException;

	/**
	 * Return an instance, which may be shared or independent, of the specified bean.
	 * <p>Allows for specifying explicit constructor arguments / factory method arguments,
	 * overriding the specified default arguments (if any) in the bean definition.
	 * @param name the name of the bean to retrieve
	 * @param args arguments to use if creating a prototype using explicit arguments to a
	 * static factory method. It is invalid to use a non-null args value in any other case.
	 * @return an instance of the bean
	 * @throws NoSuchBeanDefinitionException if there is no such bean definition
	 * @throws BeanDefinitionStoreException if arguments have been given but
	 * the affected bean isn't a prototype
	 * @throws BeansException if the bean could not be created
	 * @since 2.5
	 */
	Object getBean(String name, Object... args) throws BeansException;

	/**
	 * Does this bean factory contain a bean definition or externally registered singleton
	 * instance with the given name?
	 * <p>If the given name is an alias, it will be translated back to the corresponding
	 * canonical bean name.
	 * <p>If this factory is hierarchical, will ask any parent factory if the bean cannot
	 * be found in this factory instance.
	 * <p>If a bean definition or singleton instance matching the given name is found,
	 * this method will return {@code true} whether the named bean definition is concrete
	 * or abstract, lazy or eager, in scope or not. Therefore, note that a {@code true}
	 * return value from this method does not necessarily indicate that {@link #getBean}
	 * will be able to obtain an instance for the same name.
	 * @param name the name of the bean to query
	 * @return whether a bean with the given name is present
	 */
	boolean containsBean(String name);

	/**
	 * Is this bean a shared singleton? That is, will {@link #getBean} always
	 * return the same instance?
	 * <p>Note: This method returning {@code false} does not clearly indicate
	 * independent instances. It indicates non-singleton instances, which may correspond
	 * to a scoped bean as well. Use the {@link #isPrototype} operation to explicitly
	 * check for independent instances.
	 * <p>Translates aliases back to the corresponding canonical bean name.
	 * Will ask the parent factory if the bean cannot be found in this factory instance.
	 * @param name the name of the bean to query
	 * @return whether this bean corresponds to a singleton instance
	 * @throws NoSuchBeanDefinitionException if there is no bean with the given name
	 * @see #getBean
	 * @see #isPrototype
	 */
	boolean isSingleton(String name) throws NoSuchBeanDefinitionException;

	/**
	 * Is this bean a prototype? That is, will {@link #getBean} always return
	 * independent instances?
	 * <p>Note: This method returning {@code false} does not clearly indicate
	 * a singleton object. It indicates non-independent instances, which may correspond
	 * to a scoped bean as well. Use the {@link #isSingleton} operation to explicitly
	 * check for a shared singleton instance.
	 * <p>Translates aliases back to the corresponding canonical bean name.
	 * Will ask the parent factory if the bean cannot be found in this factory instance.
	 * @param name the name of the bean to query
	 * @return whether this bean will always deliver independent instances
	 * @throws NoSuchBeanDefinitionException if there is no bean with the given name
	 * @since 2.0.3
	 * @see #getBean
	 * @see #isSingleton
	 */
	boolean isPrototype(String name) throws NoSuchBeanDefinitionException;

	/**
	 * Check whether the bean with the given name matches the specified type.
	 * More specifically, check whether a {@link #getBean} call for the given name
	 * would return an object that is assignable to the specified target type.
	 * <p>Translates aliases back to the corresponding canonical bean name.
	 * Will ask the parent factory if the bean cannot be found in this factory instance.
	 * @param name the name of the bean to query
	 * @param targetType the type to match against
	 * @return {@code true} if the bean type matches,
	 * {@code false} if it doesn't match or cannot be determined yet
	 * @throws NoSuchBeanDefinitionException if there is no bean with the given name
	 * @since 2.0.1
	 * @see #getBean
	 * @see #getType
	 */
	boolean isTypeMatch(String name, Class<?> targetType) throws NoSuchBeanDefinitionException;

	/**
	 * Determine the type of the bean with the given name. More specifically,
	 * determine the type of object that {@link #getBean} would return for the given name.
	 * <p>For a {@link FactoryBean}, return the type of object that the FactoryBean creates,
	 * as exposed by {@link FactoryBean#getObjectType()}.
	 * <p>Translates aliases back to the corresponding canonical bean name.
	 * Will ask the parent factory if the bean cannot be found in this factory instance.
	 * @param name the name of the bean to query
	 * @return the type of the bean, or {@code null} if not determinable
	 * @throws NoSuchBeanDefinitionException if there is no bean with the given name
	 * @since 1.1.2
	 * @see #getBean
	 * @see #isTypeMatch
	 */
	Class<?> getType(String name) throws NoSuchBeanDefinitionException;

	/**
	 * Return the aliases for the given bean name, if any.
	 * All of those aliases point to the same bean when used in a {@link #getBean} call.
	 * <p>If the given name is an alias, the corresponding original bean name
	 * and other aliases (if any) will be returned, with the original bean name
	 * being the first element in the array.
	 * <p>Will ask the parent factory if the bean cannot be found in this factory instance.
	 * @param name the bean name to check for aliases
	 * @return the aliases, or an empty array if none
	 * @see #getBean
	 */
	String[] getAliases(String name);

}
       当然,仅仅这几个普通的接口肯定是无法定义整个spring ioc需要的类的,但是BeanFactory作为基类,保持接口的精简是非常必要的,其他的BeanFactory根据特性继承该接口即可,下面贴出关于整个BeanFactory的继承体系。
    技术分享
        这里面还有几个类没有截图进来,具体的大家可以使用Eclipse快捷键F4查看下BeanFactory的继承体系。不过从类的名字,我们大概可以猜到这些类或者接口的功能。在spring中,bean可以配置的属性,如下表所示

class


name

类名

scope

生存周期

constructor arguments

构造参数

properties

属性

autowiring mode

注入模式(byName, byType, auto)

lazy-initialization mode

延迟加载模式

initialization method

初始化时调用的方法

destruction method

摧毁时调用的方法

    
       在IOC模块,使用者主要需要掌握的就是如下几点:
  • bean依赖对象的注入方式(以那种方式注入bean,比如通过setter,constructor,field等)
  • bean依赖对象的依赖方式(no,byName, byType,autowired
  • 选择使用那种configuration metadata(源数据)来管理bean(主要有两种,一种是xml方式,一种是注解方式)。如下代码如xml管理bean的方式
  • 懒加载模式
  • bean,spring为每个bean指定了一些生命周期的切入点,比如初始化时执行的方法,摧毁时执行的方法等。
  • bean对象的生命周期(singleton,prototype,request,session,global,application,其中request,session,global,application为web专用)。在这里面,singleton代表的是单例,也就是一个class,spring container中只用一个实例。prototype为原型模式,也就是一个class有多个实例,区别如下图所示
      下面的表格为spring bean可配置的属性
技术分享
技术分享       
       介绍完IOC的一些背景知识,下面使用具体的代码演示下系统是如何运行的。在demo中,使用注解的方式来管理configuration metadata(源信息)。为了让工程最小化,默认使用maven来管理系统的依赖jar。具体的大家可以直接下载源代码,github

总结

      在spring container中,大量使用了设计模式,需要好好学习下。当然,也不仅仅是设计模式,还包含了面向对象汇总常用的一些概念。
       依赖倒置法则的应用
       java bean规范的使用
       对象生命周期
       工厂设计模式
       面向接口编程
       

版权声明:本文为博主原创文章,未经博主允许不得转载。

spring-ioc

标签:ioc   spring   spring framework   

原文地址:http://blog.csdn.net/u010469003/article/details/47134533

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!