控制反转依赖注入。对象仅通过构造方法参数、工厂方法参数或在对象实例被构造或被工厂方法返回后设置的属性来定义他们的依赖项(即他们使用的其他对象)。然后容器在创建bean时注入这些依赖项。从根本上说这个过程是bean本身通过直接构造类或Service Locator模式等机制来控制依赖项的实例化或位置的相反过程(因此的名控制反转)。
1、控制反转(管理对象的生命周期,实例化对象)
控制反转(inversion of contorl)是一种面向对象编程中的设计原则,用来降低代码之间的耦合度。(耦合就是模块之间的依赖程度)
基本思想:借助于第三方,实现具有依赖关系的对象之间的解耦。在java开发中,ioc思想意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制。
不管是依赖注入还是控制反转,都说明Spring采用动态、灵活的方式来管理各类对象。对象与对象之间的具体实现互相透明。
2、依赖注入(建立实例对象之间的关系)
依赖注入(Dependency injection)是IOC容器中非常重要的,在系统运行中动态的向某个对象提供它所依赖的其他对象。典型的企业应用程序不是由单个对象组成的。即使是最简单的应用程序,也有几个对象协同工作,以呈现最终用户看到的一致应用程序。
使用依赖注入的代码原则更清晰,并且向对象提供依赖是解耦更有效。对象不查找他的依赖项,也不知道依赖项的位置或类。因此你的类变得更易于测试。
依赖注入有两种主要方式:基于构造器的依赖注入和基于setter的依赖注入
构造器注入
基于构造器的依赖注入是通过容器调用带有许多参数的构造器来实现的,每个参数表示一个依赖项。调用带有特定参数的静态工厂方法来构造bean几乎是等效的,类似方式对待构造函数和静态工厂方法的参数。
<bean id="bean标签的id" class="实现类">
<constructor-arg ref="参数id"/>
</bean>
<bean id="参数id" class="参数的实体类"/>
setter注入
基于setter的依赖注入是由容器在调用无参数构造函数或无参数静态工厂方法实例化bean后,调用bean上的setter方法来实现的。
<bean id="bean标签的id" class="需要实例的类">
<property name="参数name" ref="参数类id"/>
</bean>
<bean id="参数类id" class="参数实体类"/>
注入类型
对象类型用ref标签
<!--ref类型-->
<bean id="标签名" class="实现类">
<property name="参数名" ref="参数对应的bean标签id"/>
</bean>
<bean id="参数bean标签id" class="参数实体类"/>
<!--bean类型-->
<bean id="标签名" class="实现类">
<property name="参数名" >
<bean class="参数实体类"/>
</property>
</bean>
<!--lst类型-->
<bean id="标签名" class="实现类">
<property name="list" >
<list>1</list>
<ref bean="参数bean标签id">
</property>
</bean>
基础类型用value
<!--基本类型-->
<bean id="标签名" class="实现类">
<property name="参数名" value="值"/>
</bean>
3、实现方式
3.1、基于配置
<?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默认的配置名称为ApplicationContext.xml -->
<!-- 创建ioc逻辑层实现类对象 并且交给ioc管理生命周期 控制反转 -->
<bean id="标签id" class="实体类">
<!-- 在调用逻辑层实现类构造方法的时候通过ref得到数据层实现类 注入依赖-->
<constructor-arg ref="aaa"/>
//一个代表一个参数,多个代表多个
</bean>
<!-- 创建ioc数据层实现类对象-->
<bean id="aaa" class="com.javkc.spring.ioc.dao.impl.iocDaoImpl"></bean>
</beans>
3.2、基于注解
1、@Controller:声明表现层实现类
2、@Service:声明逻辑层实现类
3、@Repository:声明数据层实现类
4、@Component:声明公共组件
5、@Resource
1、引入annotation-api依赖(java8后开始)
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>1.3.2</version>
</dependency>
2、注入实现
如果配置了name属性,就会根据name值(类)完成依赖注入,如果name配置错误就会报出NoUniqueBeanDefinitionException。
当配置了type属性,如果属性是类就会实现本身,如果是接口就是实现实体类,如果接口有多个实现类时需要配置实现类优先装配,否则也会报出NoUniqueBeanDefinitionException。
当同时配置两个属性,按照name属性判断,正确执行,否则报错。
当两个属性均未配置时,先按照iocService的name属性来找,如果找不到按照type属性来找。找到一个或多个中配置了有限则正常执行,否则报错。
//配置name属性
@Resource(name = "iocServiceImpl")
private IocService iocService;
//配置type属性
@Resource(type = IocServiceImpl.class)
@Resource(type = IocService.class)
private IocService iocService;
//同时配置name和type属性
@Resource(name = "iocServiceImpl",type = IocService.class)
private IocService iocService;
6、@Primary
依赖注入时优先装配注解。
7、@Autowried自动装配
按照类型装配,如果只找到一个则成功,如果多个则抛异常(可以通过@Primary解决)
@Autowired
private IocDao iocDao;
与@Resource相比,可以修饰构造方法
8、@Qualifier按名称自动装配(搭配@Autowried使用)
按照Qualifier指定类的名称进行装配。
@Autowired
@Qualifier("userDaoImpl")
private IocDao iocDao;
9、@Value
为对象赋值
//读取固定值
@Value("aaaaa")
private String username;
//动态读取
@Value("#{properties.path}")
private String username;
//配置文件
<util:properties id="对象id" location="classpath:配置文件名称"/>
10、@lazy
控制单例模式的实现模式,默认为懒汉。
11、Scope作用域
1、singleton 单例
单例作用域,无需配置,默认单例。
<bean id="" class="" lazy-init="true" scope="singleton"/><!--不写默认singleton-->
@Scope()<!--不写默认singleton-->
public void init(){}
2、prototype 原型
在应用中调用一次则创建一个全新的对象,用完立即销毁。
不会在服务器启动阶段实例化,new的对象不会被ioc容器管理
3、request 请求
同一个请求范围内创建一次类的实例
4、session 会话
同一个会话范围内创建一次类的实例
5、application 应用
同一个应用范围内创建一次类的实例
6、websocket
双工通信:建立客户端和服务器的一个不间断的通道。比如打电话、聊天等。
12、@PostConstruct
初始化方法,优先级比较低,所有构造方法执行结束后执行。
13、@PreConstruct
销毁方法,优先级高,在ioc容器准备销毁改对象前调用的方法。