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");
//从容器中取出bean
Food 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;
}
@Override
public String toString() {
return "Food [name=" + name + ", price=" + price + ", type=" + type + "]";
}
}
web.xml中:
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;
}
@Override
public String toString() {
return "User [name=" + name + ", food=" + food + "]";
}
}
Food类就是上面的。
xml配置。1.通过setter方法注入。通过在类中写依赖类的set方法。在xml配置中通过ref表示两个对象间的关联关系
//要把food对象动态注入到User对象中,需在容器中创建一个food对象
//在容器中创建一个user对象
2.通过构造器注入依赖对象,java代码中就可以不用写food的setter方法,加入相应的构造器即可。
在讲注解方式注入前,先说一下什么是自动装配(autowire)。自动装配是指,Spring 在装配 Bean 的时候,根据指定的自动装配规则,将某个 Bean 所需要引用类型的 Bean 注入进来。注意,目前只支持自动装配一个依赖对象,对于基本的属性类型如string,int等不支持。
对于上面的例子,可以简化为:
//使用autowire属性,则不用再配对象的依赖对象,当然对于基本属性还是可以继续配的
3.1 @Autowired 注解进行自动装配,只能是根据类型进行匹配。@Autowired 注解可以用于 Setter 方法、构造函数、字段,甚至普通方法,前提是方法必须有至少一个参数。@Autowired 可以用于数组和使用泛型的集合类型。然后 Spring 会将容器中所有类型符合的 Bean 注入进来。
xml中:
java代码中:
public class User {
private String name;
@Autowired
private Food food; //使用@Autowired注解,不用写Food对象的set方法.则xml中配置user对象时也不用写
//来进行装配
public User() {
super();
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public 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文件中配写这个类的
package com.yxj.spring.entity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component //使用@Component注解后,就不用在xml中写 了,会自动把这个类注入到容器中
public class User {
private String name;
@Autowired
private Food food;
public User() {
super();
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "User [name=" + name + ", food=" + food + "]";
}
}