Spring IOC详细配置与使用

前言:复习了解下Spring,顺便记录下这个过程以供日后翻阅。本篇将从Spring IOC的xml以及annotation两种配置进行。


SpringIOC:

    按照我个人的理解来说,SpringIOC(Inversion of Control)控制反转:指就是说原先在对象中要使用另一个对象就必须要显式的去创建另一个对象的实例,例如通过构造方法或者是调用工厂方法(工厂方法最终也是需要new,因为这是Java创建对象所必须的)来获得。而Spring提供了IOC容器来帮我们生成所需要的对象。也就是说在我们原先的对象中有用到其他对象的地方Spring会帮我们来注入。不用我们再去考虑这些问题。这边注入的实现手段就是DI(Dependency Injection)依赖注入。DI的方式有两种,一种是通过配置文件XML,一种是通过注解Annotation。下面会为两种进行说明。本次采用的结构目录可以参考基于SpringMVC+Spring+Hibernate+Maven+Bootstrap的简单Demo或者是SpringMVC整合Mybatis+Maven+Bootstrap的简单Demo


SpingIOC容器:

    容器所为SpringIOC的核心它主要有两种:

BeanFactory:BeanFactory为IOC容器提供了基础功能,Spring文档中提到,当前该类仅仅是为了向后兼容老的版本,除非你有更好的原因否则就应该使用第二种容器。

ApplicationContext:通过API文档可以知道,ApplicationContext是BeanFactory的子接口,并且从文档中也可以看到ApplicaionContext除了包含有BeanFactory的所有功能还支持了更多的功能。

ApplicationContext的实现有四种方式:

FileSystemXmlApplicationContext:加载配置文件的时候采用的是项目的路径。

ClassPathXmlApplicationContext:加载配置文件的时候根据ClassPath位置。

XmlWebApplicationContext:在Web环境下初始化监听器的时候会加载该类。

AnnotationConfigApplicationContext:根据注解的方式启动Spring 容器。


SpringDI的方式:

    Spring提供了三种方式来依赖注入,有构造方法注入,setter方法注入以及接口注入(属性)。其中Spring以往推荐使用Setter的方法现在改成推荐构造方法注入。使用构造方法注入需要注意的一点就是要避免循环依赖。所谓的循环依赖指的就是在A对象的构造方法中Spring要注入B,而在B对象中Spring要注入A。这个时候会形成一个闭环因为Spring不知道该先注入哪一个接着会抛出异常。而Spring建议的处理方式是说如果遇到这种情况的话就改用Setter方式注入。


SpringIOC之Xml:

    Bean:

    省去了所有的测试环境的搭建本次使用Junit进行单元测试使用ClassPathXmlApplication来管理bean。首先从把类交给Spring Ioc管理开始一步步深入。从下面实例可以看到我们要让Spring帮我们管理对象的生成需要在配置文件中进行注册。每一个标签bean对应的就一个类对象,通过id(或者Name)以及Class来定位一个类,这边Class要求是完全限定类名。因为Spring生成对象的过程就是使用反射机制所以你必要要提供一个正确的路径否则就会抛出异常。除了这两个属性外,Spring还提供了其他的属性来对Bean进行设置下面将对所有的属性进行测试。


   abstract以及parent:

   abstract以及parent是搭配使用的,如果bean定义了属性abstact=true,那么这个类就无法通过Spring容器拿到,而是作为一个模板存在。有点类似于设计模式中的模板方法。这个bean对应的类它定义的属性,方法可以被复用。通过Parent属性在子类中可以指向被abstract定义的bean。用法包括集合类的并集,类的继承等等。下面给出栗子,可以看到定义了一个父类UserAbstract还有它的子类UserExtendsAbs。运行的时候子类可以直接拿到父类中定义的属性name以及age。此外Spring允许我们对父类中的值进行覆盖,所以Name输出变成了test2。

    lazy-init,init-method,destroy-method:

    默认情况下容器中的所有bean在初始化容器的时候就被加载,但是我们可以指定lazy-init属性来让Spring实现懒加载。只有在调用的时候才添加进容器。而init-method以及destory-method顾名思义就是初始化以及销毁的时候调用,类似于Servlet的init以及destory。下面举个栗子。因为UserServiceImpl跟UserDaoImpl有关联关系所以注释掉。可以看到程序开始容器初始化的时候没有对userDaoImpl初始化,而当调用了userDaoImpl的时候才会被加入容器里面。此时也可以看到init方法被调用,在容器关闭的时候destory也被调用了。


    depends-on:

    一般情况下如果两个对象存在依赖的时候我们会通过上述提到的三种注入方式来注入。但是如果两个对象的关系没有那么直接,例如A对象在初始化的时候要调用B对象的一个静态参数,而这个静态参数只有B初始化的时候才会更新。而它们直接的依赖关系并没有那么直接。那么这个时候我们就可以使用depends-on。举个栗子。可以看到默认情况下userDaoImpl拿到number为0,而添加了depends-on后,Spring会先初始化userDaoImpl2然后再初始化userDaoImpl,所以number的值变成了10。




    factory-bean,factory-method:

    Spring除了通过class来拿到对象,同时也允许对象通过工厂的方法来获取。举个栗子。可以看到userDaoImpl通过DaoFactory工厂拿到。


 


    Scope:

    Spring的bean可以设置scope属性来确认它的作用域,可以看到默认情况下是singleton也就是单例,也可以设置成多例。而其他的几种情况都是在web环境下使用。举个栗子。可以看到默认情况下每次取出来的userDaoImpl都是同一个,而我们如果设置成prototype那么每次拿到的对象都是不一样的。


在介绍剩下的autowire,autowire-candidate以及primary属性之前,先介绍了xml中如何实现依赖注入。


    构造器注入:

    直接举个栗子。现在我们要在对象userServiceImpl中注入对象userDaoImpl。如果我们没有指定的话,默认情况下是调用默认的构造方法来初始化。可以看到属性值通过构造方法成功注入,这边Spring允许你通过name来对应构造器参数,也可以使用index表示对应的位置,从0开始。或者使用type,指定类型。



    setter方法注入:

    直接举个栗子。之前的例子通过构造方法注入,现在我们直接使用标签property的方式来注入。可以看到一样可以注入成功。但是切记,所以的成员变量必须实现它的setter方法,否则会抛出异常。


    Collection注入:

    在对象中经常要使用到Collection集合类型,Spring也提供了对象的方式来注入。举个栗子。



现在回过头来说说前面搁置的几个属性。

   autowire:

    Spring有个自动装配的机制会帮我们自动的把userDaoImpl注入到userServiceImpl中,通过配置autowire可以实现。直接举个栗子。可以看到我们在配置文件中删掉了userDaoImpl,但是Spring一样会帮我们成功注入。但是要注意的是,如果我们选择的是byType,那么对于存在两个相同Class的userDaoImpl Spring会不知道要注入哪一个,因此会抛出异常。


   


    autowire-candidate,primary:

    针对上述的问题,Spring提供了两个方法来解决。第一种如果你在id为userDaoImpl2上面添加了autowire-candidate,那么就说明如果自动装配的时候出现冲突,就会忽略当前这个bean即userDaoImpl2。而primary则是反过来,它表示的是一种优先级,如果遇到冲突情况优先使用带有该属性的bean。举个栗子。


SpringIOC之Annotation注解:

    使用注解的方式的话就不需要在配置文件中写这么多了,相对Ioc而言我认为使用注解更为方便。如果要使用Annotation的方式只需要在配置文件中添加<context:component-scan base-package="com.ctc" />,那么你的基本要求就可以实现了,Spring就根据base-package指定的路径去扫描下面所有的类。我们只需要在业务层数据层上的类添加上注解就可以了。Spring提供了多种注解:@Component,@Service(业务层),@Repository(持久层),@Controller(表现层)。当前我们可以在所以的类上面直接使用@Component一样可以实现。但是Spring建议你根据需要分开定义,因为在以后的版本中Spring可能会对他们添加一个特性,当前@Repository已经支持了针对异常的新特性。

    @Required:

    如果我们在userServiceImp中在针对userDaoImpl方法上面添加了Required那么说明你必须显示的配置文件中指定这个属性。否则就会抛出异常。而Spring的解释是说,这种情况是为了防止出现NPE。举个栗子。可以看到,一开始我们没有配置Required,Spring没有出现异常这个时候userDaoImpl为空,因此在调用addUser的时候出现了NPE。但是如果我们加入了该注解,可以看到这个时候Spring抛出异常了,说明你必须要在配置文件配置,否则无法进行下一步。





    @Autowired,@Resource;

    @Autowired跟@Resource都可以作用在构造方法,sette方法,以及属性值上面注入。它们的区别在于:

  1. Autowired是Spring的规范,而Resource是java的规范;
  2. Autowired默认按类型匹配但是可以搭配@Qualifier来指定名称,而Resource默认按名称;

     因为太简单了,就不提供栗子了~此外xml中提到了属性在annotation中都可以实现。需要的话自己查文档吧~


Spring在3.X之后使用Java来代替XML配置:

    Spring在3.X之后推荐使用Java 类的方式来代替XML的配置。下面将进行一个简单的实例。首先创建一个SpringConfig对应一个XML文件。这边Configuration表明当前这个类对应一个XML文件,另外在Junit中我们不再使用ClassPathXMLApplicationContext,而是改用了AnnotationConfigApplicationContext。因为我们不再通过XML的方式来获取Bean。

@Configuration
@ComponentScan(basePackages="com.ctc")
public class SpringConfig {

}


猜你喜欢

转载自blog.csdn.net/u010890358/article/details/80620898