spring之IOC总结

来源:互联网 发布:oracle数据库查询语句 编辑:程序博客网 时间:2024/06/05 23:40

spring中,对于IOC(控制反转)和DI(依赖注入)。

控制反转和依赖注入,说的都是一个东西。控制反转是说java对象中依赖对象的创建,由原来通过new创建,变成由第三方spring容器创建,用时直接在代码中声明,容器会主动把创建好的对象动态的注入到代码中(依赖注入)。不管是创建一个依赖另一个对象的对象,还是创建一个简单的对象,spring容器都可以做到。  用控制反转的好处当然就是实现代码间的松耦合啦,现实的例子就是:我需要一把斧子,以前的方式是自己去生产一个,而现在就是由斧子工厂生产,我直接从工厂里拿来用,这样达到了人和斧子对象之间很好的解耦。因为控制反转不容易理解,所以后来改为依赖注入,因为依赖注入说明了这样思想的实现方式。

为了实现这样的功能,在代码中又是怎呀实现的呢?首先,我们需要考虑两个问题:1.在spring容器中的bean是怎样创建的?2.创建好的bean又是怎样动态注入到代码中的?

如果这两个问题解决了,那么就可以实现上面说的那种控制反转的思想了。

首先,讲bean的创建前先说spring容器,spring框架提供给我们一个spring容器,也叫IOC容器。这个容器就是用来创建bean的,不仅可以创建对象,还维护对象间的关系,管理对象的生命周期。代码中由BeanFactory来表示,但是我们开发一般用它的子接口ApplicationContext,因为它里面的方法更多一些,比如更易 与Spring AOP集成、资源处理(国际化处理)、事件传递及各种不同应用层的context实现 (如针对web应用的WebApplicationContext)。简而言之,BeanFactory提供了配制框架及基本功能,而 ApplicationContext 则增加了更多支持企业核心内容的功能。除了功能不同外,还有个区别,ApplicationContext是在初始化容器时就直接创建在里面注册的bean,而BeanFactory容器是延迟加载的,即容器初始化时,里面的bean不是立即创建,而是代码中用到bean时才创建实例化。而对于接口ApplicationContext,他的实现类有两种ClassPathXmlApplicationContext(从类路径下加载配置文件)和FileSysytemApplicationContext(从文件系统加载配置文件)

代码实现:1.创建一个spring容器

         //从类路径下加载配置文件,配置文件里就是一些需要注册进容器的bean。此句表示创建一个spring容器并初始化里面的bean。        ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");          //从容器中取出beanFood food=(Food) context.getBean("food22");  //food22已经在容器中注册过才能拿来用,后面会讲bean如何注册进容器

spring容器中的bean是怎样创建的呢?---有3种。1.通过构造函数(实质就是通过反射机制实现的),一般我们用的是这种方式。2.通过静态工厂方法。3.通过实例工厂方法。

1.通过构造器,可以用默认的无参构造器,也可以用自定义的有参构造器

package com.yxj.spring.entity;public class Food {private String name;private int price;private String type;//1.此处用默认构造器创建一个bean对象public Food() {super();}//2.同样是构造器创建一个bean,可以根据自己需求设置一个有参构造器public Food(String name, int price, String type) {super();this.name = name;this.price = price;this.type = type;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getPrice() {return price;}public void setPrice(int price) {this.price = price;}public String getType() {return type;}public void setType(String type) {this.type = type;}@Overridepublic String toString() {return "Food [name=" + name + ", price=" + price + ", type=" + type + "]";}}
web.xml中:
<?xml version="1.0" encoding="UTF-8"?><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.xsd">
<!--spring容器通过java代码中的默认构造器(上1),在容器中创建一个实例bean(反射机制实现) 。 --><bean id="food" class="com.yxj.spring.entity.Food"/><!--通过自定义构造器参数(上2),实例化一个bean。注意!此处属性的顺序要和自定义构造函数的参数的一样,否则会报错。 此处写法表示已经给对象初始化了 --><bean id="food22" class="com.yxj.spring.entity.Food"><constructor-arg value="巧克力"></constructor-arg><constructor-arg value="120"></constructor-arg><constructor-arg value="sweet"></constructor-arg></bean></beans>

2和3,通过工厂方式创建bean就不作多说明,想要了解的请自行百度。


上面只是注入一个简单的java对象,对于对象需要依赖另一个对象的情景,则需要用到依赖注入来实现另一个对象注入到对象中。比如,User这个对象,依赖食物Food这个对象,怎样把食物对象注入到人对象中呢?----3种方式。1,通过setter方法注入 ;2,通过构造器注入 3.基于注解的注入

package com.yxj.spring.entity;public class User {private String name;private Food food;public User() {super();}public User(String name, Food food) {super();this.name = name;this.food = food;}
public Food getFood() {return food;}
//通过setter方法,将Food这个对象注入进来public void setFood(Food food) {this.food = food;}public String getName() {return name;}public void setName(String name) {this.name = name;}@Overridepublic String toString() {return "User [name=" + name + ", food=" + food + "]";}}
Food类就是上面的。

xml配置。1.通过setter方法注入。通过在类中写依赖类的set方法。在xml配置中通过ref表示两个对象间的关联关系

<bean id="food" class="com.yxj.spring.entity.Food"/>  //要把food对象动态注入到User对象中,需在容器中创建一个food对象<bean id="user" class="com.yxj.spring.entity.User">   //在容器中创建一个user对象 <!--通过property元素来表示对象的属性。--><property name="name" value="这是name属性的值"></property><!--两个对象间的关联,由ref指定 --><property name="food" ref="food"></property></bean>


               2.通过构造器注入依赖对象,java代码中就可以不用写food的setter方法,加入相应的构造器即可。

<bean id="food" class="com.yxj.spring.entity.Food"/> 

<bean id="user" class="com.yxj.spring.entity.User"><constructor-arg value="Jack"></constructor-arg>        <constructor-arg ref="food" ></constructor-arg></bean>

3.注解方式注入。从spring2.5开始支持,现在很流行这种方式,注解使整个代码量减少了。主要由@Autowired   @Resource  @Inject  

在讲注解方式注入前,先说一下什么是自动装配(autowire)。自动装配是指,Spring 在装配 Bean 的时候,根据指定的自动装配规则,将某个 Bean 所需要引用类型的 Bean 注入进来。注意,目前只支持自动装配一个依赖对象,对于基本的属性类型如string,int等不支持。<bean> 元素提供了一个指定自动装配类型的 autowire 属性。autowire由几个属性,byName,byType等,之间区别就不详说了。主要是说autowire的功能。

对于上面的例子,可以简化为:

<bean id="food" class="com.yxj.spring.entity.Food"/> 

<bean id="user" class="com.yxj.spring.entity.User" autowire="byName"/> //使用autowire属性,则不用再配对象的依赖对象,当然对于基本属性还是可以继续配的

使用@Autowired @Resource @Inject等注解实现自动注入---替代setter方法或是构造器,用于类中依赖对象的自动注入。

   3.1 @Autowired 注解进行自动装配,只能是根据类型进行匹配。@Autowired 注解可以用于 Setter 方法、构造函数、字段,甚至普通方法,前提是方法必须有至少一个参数。@Autowired 可以用于数组和使用泛型的集合类型。然后 Spring 会将容器中所有类型符合的 Bean 注入进来。

xml中:

<bean id="food" class="com.yxj.spring.entity.Food" /><bean id="user" class="com.yxj.spring.entity.User"/>
java代码中:

public class User {private String name;@Autowiredprivate Food food;   //使用@Autowired注解,不用写Food对象的set方法.则xml中配置user对象时也不用写
     //<property name="food" ref="food">来进行装配

public User() {super();}public String getName() {return name;}public void setName(String name) {this.name = name;}@Overridepublic String toString() {return "User [name=" + name + ", food=" + food + "]";}}
如果food类没有在容器中注册,那么会报错。解决这一问题,只需这样写@Autowired(required=false),这样不会报错,只是表示这个依赖对象为null。

如果在xml文件中出现多个类型相同的bean,比如注册了food1,food2等,则在使用@Autowired时也会出错,因为@Autowired是根据类型匹配的,当出现多个类型相同的bean时,容器会不知道匹配哪个bean。解决方案,用@Qualifier注解指明装配哪个bean。

 3.2  @Resource 是根据bean的name名字进行自动装配的,而不是像@Autowired和@Qualifier结合根据类型装配。可以作用于带一个参数的 Setter 方法、字段,以及带一个参数的普通方法上。@Resource会先根据bean的名字装配,如果没有符合的bean则退居根据类型装配。

 3.3  @Inject注解几乎可以完全替代Spring的@Autowired注解。所以除了使用Spring特定的@Autowired注解,我们可以选择@Inject。和@Autowired一样,@Inject可以用来自动装配属性、方法和构造器;与@Autowired不同的是,@Inject没有required属性。因此@Inject注解注入的依赖关系必须存在,否则报异常。


上面所说的@Autowired   @Resource  @Inject  都是用于实现对象中依赖对象的装配。而对于一个类的自动装配,可以用下面的注解。

@Service @Component @Controller @Repository,用他们放在类上,就不用在xml文件中配写这个类的<bean />了。容器会扫描到后自动注册进容器。(用于类的自动注入)

package com.yxj.spring.entity;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Component;@Component   //使用@Component注解后,就不用在xml中写<bean  />了,会自动把这个类注入到容器中public class User {private String name;@Autowiredprivate Food food;public User() {super();}public String getName() {return name;}public void setName(String name) {this.name = name;}@Overridepublic String toString() {return "User [name=" + name + ", food=" + food + "]";}}

<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd"><context:component-scan base-package="com.yxj.spring.entity"></context:component-scan>  </beans>

还有其他功能的注解,后面会继续补充。
                                             
0 0
原创粉丝点击