一.IOC/DI概念
参考博客:
IOC(inversion of control, 控制反转)是一种设计思想,而不是一种技术. IOC意味着将我们设计好的对象交给容器控制,而不是交给对象内部控制.它指导我们设计出松耦合,更优良的程序. 传统程序都是由在类内部主动创建依赖对象来使用, 从而导致类与类之间高耦合, 难于测试; 有了IOC容器,把创建和查找依赖对象的控制权交给了容器, 由容器进行注入组合对象,所以对象和对象之间是松耦合, 这样使得程序的整个体系结构非常灵活.
实际上,IOC可以看做是一个大型中介, 将对象的信息登记其中,这个对象是什么, 这个对象又需要什么 ,由中介公司给对象分配它需要的资源, 以及将对象分配给需要它的对象.Spring在这个过程中控制着对象的生命周期和对象间的关系, 所有类的创建和销毁都由Spring控制, 而不是需要它们的类控制, 这就是控制反转.
DI(Dependency Injection, 依赖注入)是IOC的一个重点,它实现IOC的一种方法,或者说DI是IOC的另一种说法 , 它负责实现IOC动态地向某个对象提供它所需要的其他对象. 比如一个人需要一根扫把, 不是由这个人自己去做扫把, 而是由Spring将做好的扫把给他, 而这个人全程需要做的,就是喊我要一根扫把. 什么叫做依赖, 人需要扫把, 人就对扫把有了依赖. 而DI就是根据这个依赖,将扫把分配给这个人的.
二.IOC的使用
参考博客:
IOC实现的两种方式: XML配置 , Spring注解
依赖注入的两种形式: Setter依赖注入, 构造方法依赖注入
1.XML配置的两种依赖注入形式:
(1)Setter依赖注入: 首先创建一个Book类,将其属性设置好setter,getter方法
public class Book { private int id; private String name; private User user; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public User getUser() { return user; } public void setUser(User user) { this.user = user; }}
然后在applicationContext.xml中添加bean, 告诉Spring两者的依赖关系,实现注入
(2)构造方法依赖注入:
我们将BOOK类中添加了一个两个参数的构造方法,然后在xml文件中确定两个参数的值,从而让spring容器能够创造对象
public class Book { private int id; private String name; private User user; //Constructor public Book(String name,User user){ this.name = name; this.user = user; }}
xml文件中的配置为: 指定了构造器有两个参数, 第一个参数是String , 第二个参数指向了另一个bean
或者可以这样写构造参数:
又或者这样写:
(3) Scope对象作用域: 从Spring容器中获取的对象的作用域可以修改,默认的作用域为单例, 具体如下
- Singleton : 每个Spring容器作用域中,一个bean定义 只对应一个对象实例
- Prototype: 一个bean定义对应多个对象实例
- Request: 一个bean定义作用于HTTP request 生命周期, 指每个HTTP request 从Spring获取的对象实例不一样. 仅在基于web的Spring ApplicationContext中有效.
- Session: 一个bean定义作用域HTTP session 生命周期,
- Global Session: 一个bean定义作用域全局的HTTP session 生命周期.
- Application: 一个bean定义作用于整个ServletContext生命周期
其在配置中写在bean的属性Scope中:
(4)延迟初始化bean: 通常ApplicationContext默认在启动时将所有singleton bean提前实例化. 通常提前实例化是好事,避免某些错误因为延迟实例化而不被提前发现. 但是如果想防止提前实例化, 比如你只需要用到book对象, 而不需要它初始化它的user对象, 就可以用lazy-init属性来控制
(5)回调方法: 初始化回调函数init
public class Book { private int id; private String name; private User user;// Constructor public Book(String name,User user){ this.name = name; this.user = user; } public void init(){ System.out.println("创建了一本书"); } public void destroy(){ System.out.println("销毁了一本书"); }}
在xml文件中设置初始化回调函数,就会在创建时调用
2.Spring注解:
注解会削减一些配置的工作量, 但是代码的耦合度会增加, 应当根据需要使用注解
(1)@Component注解: 这个注解和<bean>作用类似, 通过增加@Component()注解中的参数,指定其在Spring容器中的名称. 如果不写,则是默认其在Spring容器中的名称为类名的小写 如User类 在Spring容器中默认名称为 user
@Component("user")public class User { private int id; private int age; private String name; public int getId() { return id; } public void setId(int id) { this.id = id; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; }}
在配置文件中,即使没有user这个bean , 其它bean也可以用到
(2)@Auotowired 注解: 在Spring中,可以使用 @Autowired 注解通过setter方法,构造函数或字段自动装配Bean。
public class Book { private int id; private String name; private User user; public User getUser() { return user; } @Autowired public void setUser(User user) { this.user = user; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; }}
这样,即使在applicationContext.xml文件中没有设置要在book中user依赖哪个对象, Spring容器也会自动装配
通过构造函数:
public class Book { private int id; private String name; private User user;// Constructor @Autowired public Book(User user){ this.user = user; }}
通过字段:
public class Book { private int id; private String name; @Autowired private User user;}
(3)@Resource注解 : 这个注解与@Autowired不同是, 它可以指定装配对象的名称,或者类型,或者两者都指定
如book和user
@Component("u")public class User { private int id; private int age; private String name; //setter 和 getter }
@Component("b")public class Book { private int id; private String name; @Resource(name = "u") private User user;//setter和getter}
@Component("b")public class Book { private int id; private String name; @Resource(name = "u",type = User.class) private User user;}
或者这样
@Component("b")public class Book { private int id; private String name; @Resource(name = "u",type = User.class) private User user;
@Service用于注解业务层组件(我们通常定义的service层就用这个)
@Controller用于注解控制层组件(如struts中的action)
@Repository用于注解数据访问组件,即DAO组件
@Component泛指组件,当组件不好归类的时候,我们可以使用这个注解进行注解。
装配注解主要有:@Autowired、@Qualifier、@Resource,它们的特点是:
1、@Resource默认是按照名称来装配注入的,只有当找不到与名称匹配的bean才会按照类型来装配注入;
2、@Autowired默认是按照类型装配注入的,如果想按照名称来转配注入,则需要结合@Qualifier一起使用;
3、@Resource注解是由J2EE提供,而@Autowired是由spring提供,故减少系统对spring的依赖建议使用@Resource的方式;如果Maven项目是1.5的JRE则需换成更高版本的。
4、@Resource和@Autowired都可以书写注解在字段或者该字段的setter方法之上
5、@Autowired 可以对成员变量、方法以及构造函数进行注释,而 @Qualifier 的注解对象是成员变量、方法入参、构造函数入参。
6、@Qualifier("XXX") 中的 XX是 Bean 的名称,所以 @Autowired 和 @Qualifier 结合使用时,自动注入的策略就从 byType 转变成 byName 了。
7、@Autowired 注释进行自动注入时,Spring 容器中匹配的候选 Bean 数目必须有且仅有一个,通过属性required可以设置非必要。
8、@Resource装配顺序
8.1. 如果同时指定了name和type,则从Spring上下文中找到唯一匹配的bean进行装配,找不到则抛出异常 8.2. 如果指定了name,则从上下文中查找名称(id)匹配的bean进行装配,找不到则抛出异常 8.3. 如果指定了type,则从上下文中找到类型匹配的唯一bean进行装配,找不到或者找到多个,都会抛出异常 8.4. 如果既没有指定name,又没有指定type,则自动按照byName方式进行装配;如果没有匹配,则回退为一个原始类型进行匹配,如果匹配则自动装配;
以下转自博客:https://blog.csdn.net/qq_22583741/article/details/79589910
1.@Component取代<bean class="">
@Component("id") 取代 <bean id="" class=""> 2.web开发,提供3个@Component注解衍生注解(功能一样)取代 @Repository :dao层 @Service:service层 @Controller:web层 3.依赖注入,给私有字段设值,也可以给setter方法设值普通值:@Value(" ")
引用值: 方式1:按照【类型】注入 @Autowired 方式2:按照【名称】注入1 @Autowired @Qualifier("名称") 方式3:按照【名称】注入2 @Resource("名称") 4.生命周期 初始化:@PostConstruct 销毁:@PreDestroy 5.作用域 @Scope("prototype") 多例 注解使用前提,添加命名空间,让spring扫描含有注解类