Spring IoC
控制反转(IoC)也称为依赖注入(DI),这是一种对象通过构造函数参数、工厂方法的参数或在对象实例构造或从工厂方法返回后设置的属性来定义它们的依赖关系的过程,然后容器在创建bean时注入这些依赖关系。这个过程基本上是与bean本身通过直接构造类或使用Service Locator模式等机制来控制其依赖项的实例化或定位的逆过程,因此得名控制反转。
org.springframework.beans和org.springframework.context包是Spring框架IoC容器的基础。BeanFactory接口提供了一个高级配置机制,能够管理任何类型的对象。ApplicationContext是BeanFactory的子接口。它增加了:
- 与Spring的AOP特性更轻松的集成
- 消息资源处理(用于国际化)
- 事件发布
- 用于在Web应用程序中的特定应用层上下文,如WebApplicationContext。
在Spring中,构成应用程序骨架并由Spring IoC容器管理的对象称为"beans"。一个bean是由Spring IoC容器实例化、组装和管理的对象。否则,bean只是应用程序中的众多对象之一。Beans及其之间的依赖关系反映在容器使用的配置元数据中。
Spring 框架
Spring框架概念
Spring框架是一个开源的Java框架,用于构建企业级应用程序。它提供了广泛的基础设施支持和许多可重用的库,以简化Java开发。以下是Spring框架的一些核心概念:
- 控制反转(IoC): Spring框架通过IoC容器实现了控制反转。在传统的应用程序中,对象的创建和管理通常是由程序代码直接控制的。而在Spring中,IoC容器负责创建、组装和管理应用程序中的对象。这种控制权的反转使得应用程序更加灵活、松散耦合,并易于测试。
- 依赖注入(DI): DI是IoC的一种具体实现,它是指将一个对象的依赖关系注入到对象本身而不是由对象自己创建或查找依赖。在Spring中,通过构造函数、属性或方法注入来实现依赖注入,使得对象更易于维护和测试。
- Bean: 在Spring中,对象被称为"bean"。一个bean是由Spring IoC容器管理的对象,它通常代表应用程序中的一个组件。Beans由容器实例化、组装和管理。
- AOP(面向切面编程): Spring提供了对AOP的支持,允许开发人员通过切面将横切关注点(如日志、事务管理等)从主业务逻辑中分离出来,以提高代码的模块化性和可维护性。
- 模块化: Spring框架被设计成一组相互协作的模块,每个模块解决特定的问题。例如,Spring的数据访问模块(Spring Data)处理数据访问层,Spring MVC负责处理Web应用程序的MVC架构。
- 数据访问与事务管理: Spring提供了对数据访问的支持,包括对ORM框架的集成。它还支持声明式事务管理,使得开发人员可以通过注解或XML配置来管理事务。
- Spring MVC: Spring提供了一个灵活的MVC框架,用于构建Web应用程序。Spring MVC通过使用控制器、模型和视图来实现松耦合的Web应用程序。
- Spring Boot: Spring Boot是Spring框架的一个子项目,旨在简化Spring应用程序的开发和部署。它通过默认配置和自动化的方式,使得开发者可以更轻松地创建独立的、生产级别的Spring应用程序。
这些概念共同构成了Spring框架的基础,使得开发者能够更轻松地构建可维护、可扩展和松散耦合的企业级应用程序。
Spring的优点
Spring框架具有许多优点,这些优点使得它成为Java企业级应用程序开发中的首选框架之一。以下是一些Spring框架的主要优点:
- 轻量级: Spring框架是轻量级的,不会强迫应用程序使用大量的基础设施代码。它使用松散耦合的方式,只关注你需要的部分,可以选择性地集成其他框架。
- 控制反转(IoC)和依赖注入(DI): Spring的IoC容器负责对象的创建和管理,通过DI将对象的依赖关系注入到对象本身,使得应用程序更加灵活、可维护,降低了组件之间的耦合度。
- 面向切面编程(AOP): Spring支持AOP,使得开发者能够更方便地处理横切关注点,如日志、事务管理等。AOP可以提高代码的模块化性和可维护性。
- 模块化和可扩展性: Spring框架是模块化的,包含多个子模块,每个模块解决特定的问题。这种模块化的设计使得开发者能够选择需要的功能,同时也支持容易扩展。
- 声明式事务管理: Spring提供了声明式事务管理的支持,开发者可以通过注解或XML配置简单地管理事务,而不需要显式编写事务管理代码。
- 灵活性和可配置性: Spring框架采用了基于接口的编程,使得应用程序更容易进行单元测试和集成测试。同时,Spring的配置是可扩展和可配置的,可以通过XML、注解或Java配置进行。
- 简化JEE开发: Spring简化了Java企业应用程序的开发,提供了对JDBC、JMS、JTA等JEE规范的封装,减少了开发者在使用这些规范时的工作量。
- 丰富的生态系统: Spring框架有着庞大的社区和丰富的生态系统,支持多种数据库、消息中间件、Web框架等,使得开发者可以更轻松地集成其他技术和工具。
- Spring Boot的简化开发: Spring Boot是Spring框架的一个子项目,通过默认配置和自动化的方式,使得开发者可以更轻松地创建独立的、生产级别的Spring应用程序,减少了繁琐的配置工作。
总体而言,Spring框架的这些优点使得它成为企业级Java应用程序开发的首选,提高了开发效率、代码质量和系统的可维护性。
Spring IoC 注入
1.Spring IoC手动装配
Spring ⽀持的注⼊⽅式共有四种:set 注⼊、构造器注⼊、静态⼯⼚注⼊、实例化⼯⼚注⼊。
1.1 set方法注入
注意:属性字段需要提供set⽅法
1.1.1 业务对象 JavaBean
(1)属性字段提供set⽅法
public class UserService {
// 业务对象UserDao set注⼊(提供set⽅法)
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
}
(2)配置⽂件的bean标签设置property标签
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!--
IOC通过property标签⼿动装配(注⼊):
Set⽅法注⼊
name:bean对象中属性字段的名称
ref:指定bean标签的id属性值
-->
<bean id="userDao" class="com.suntao.dao.UserDao"></bean>
<bean id="userService" class="com.suntao.service.UserService">
<!--业务对象注⼊-->
<property name="userDao" ref="userDao"/>
</bean>
</beans>
1.1.2 常⽤对象和基本类型
(1)属性字段提供set⽅法
public class UserService {
// 常⽤对象String set注⼊(提供set⽅法)
private String host;
public void setHost(String host) {
this.host = host;
}
// 基本类型Integer set注⼊(提供set⽅法)
private Integer port;
public void setPort(Integer port) {
this.port = port;
}
}
(2)配置⽂件的bean标签设置property标签
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!--
IOC通过property标签⼿动装配(注⼊):
Set⽅法注⼊
name:bean对象中属性字段的名称
value:具体的值(基本类型 常⽤对象|⽇期 集合)
-->
<bean id="userService" class="com.suntao.service.UserService">
<!--常⽤对象String 注⼊-->
<property name="host" value="127.0.0.1"/>
<!--基本类型注⼊-->
<property name="port" value="8080"/>
</bean>
</beans>
1.1.3 集合类型和属性对象
(1)属性字段提供set⽅法
public class UserService {
// List集合 set注⼊(提供set⽅法)
public List<String> list;
public void setList(List<String> list) {
this.list = list;
}
// Set集合 set注⼊(提供set⽅法)
private Set<String> set;
public void setSet(Set<String> set) {
this.set = set;
}
// Map set注⼊(提供set⽅法)
private Map<String,Object> map;
public void setMap(Map<String, Object> map) {
this.map = map;
}
// Properties set注⼊(提供set⽅法)
private Properties properties;
public void setProperties(Properties properties) {
this.properties = properties;
}
}
(2)配置⽂件的bean标签设置property标签
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!--
IOC通过property标签⼿动装配(注⼊):
Set⽅法注⼊
name:bean对象中属性字段的名称
value:具体的值(基本类型 常⽤对象|⽇期 集合)
-->
<!--List集合 注⼊-->
<property name="list">
<list>
<value>上海</value>
<value>北京</value>
<value>杭州</value>
</list>
</property>
<!--Set集合注⼊-->
<property name="set">
<set>
<value>上海SH</value>
<value>北京BJ</value>
<value>杭州HZ</value>
</set>
</property>
<!--Map注⼊-->
<property name="map">
<map>
<entry>
<key><value>周杰伦</value></key>
<value>我是如此相信</value>
</entry>
<entry>
<key><value>林俊杰</value></key>
<value>可惜没如果</value>
</entry>
<entry>
<key><value>陈奕迅</value></key>
<value>⼗年</value>
</entry>
</map>
</property>
<!--Properties注⼊-->
<property name="properties">
<props>
<prop key="上海">东⽅明珠</prop>
<prop key="北京">天安⻔</prop>
<prop key="杭州">⻄湖</prop>
</props>
</property>
</beans>
1.2 构造器注⼊
注意:提供带参构造器
1.2.1 单个Bean对象作为参数
public class UserService {
private UserDao userDao; // JavaBean 对象
public UserService(UserDao userDao) {
this.userDao = userDao;
}
public void test(){
System.out.println("UserService Test...");
userDao.test();
}
}
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!--
IOC通过构造器注⼊:
通过constructor-arg标签进⾏注⼊
name:属性名称
ref:指定bean标签的id属性值
-->
<bean id="userDao" class="com.xxxx.dao.UserDao" ></bean>
<bean id="accountDao" class="com.xxxx.dao.AccountDao" ></bean>
<bean id="userService" class="com.xxxx.service.UserService">
<constructor-arg name="userDao" ref="userDao"></constructor-arg>
<constructor-arg name="accountDao" ref="accountDao"></constructor-arg>
</bean>
</beans>
1.2.2 Bean对象和常⽤对象作为参数
public class UserService {
private UserDao userDao; // JavaBean 对象
private AccountDao accountDao; // JavaBean 对象
private String uname; // 字符串类型
public UserService(UserDao userDao, AccountDao accountDao, String uname) {
this.userDao = userDao;
this.accountDao = accountDao;
this.uname = uname;
}
public void test(){
System.out.println("UserService Test...");
userDao.test();
accountDao.test();
System.out.println("uname:" + uname);
}
}
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!--
IOC通过构造器注⼊:
通过constructor-arg标签进⾏注⼊
name:属性名称
ref:指定bean标签的id属性值
value:基本类型 常⽤对象的值
index:构造器中参数的下标,从0开始
-->
<bean id="userDao" class="com.xxxx.dao.UserDao" ></bean>
<bean id="accountDao" class="com.xxxx.dao.AccountDao" ></bean>
<bean id="userService" class="com.xxxx.service.UserService">
<constructor-arg name="userDao" ref="userDao"></constructor-arg>
<constructor-arg name="accountDao" ref="accountDao"></constructor-arg>
<constructor-arg name="uname" value="admin"></constructor-arg>
</bean>
</beans>
1.3 静态⼯⼚注⼊
1.3.1 定义静态⼯⼚类
public class StaticFactory {
// 定义静态⽅法
public static TypeDao createTypeDao() {
return new TypeDao();
}
}
1.3.2 Java代码
public class TypeService {
private TypeDao typeDao;
public void setTypeDao(TypeDao typeDao) {
this.typeDao = typeDao;
}
public void test() {
System.out.println("TypeService Test...");
}
}
1.3.3 XML配置
<bean id="typeService" class="com.suntao.service.TypeService">
<property name="typeDao" ref="typeDao"/>
</bean>
<!--
静态⼯⼚注⼊:
静态⼯⼚注⼊也是借助set⽅法注⼊,只是被注⼊的bean对象的实例化是通过静态⼯⼚实例化的
-->
<bean id="typeDao" class="com.suntao.factory.StaticFactory" factorymethod="createTypeDao"></bean
1.4实例化⼯⼚注⼊
1.4.1 定义工厂类
public class InstanceFactory {
public TypeDao createTypeDao() {
return new TypeDao();
}
}
1.4.2 Java代码
public class TypeService {
private TypeDao typeDao;
public void setTypeDao(TypeDao typeDao) {
this.typeDao = typeDao;
}
public void test() {
System.out.println("TypeService Test...");
}
}
1.4.3 XML代码
<bean id="typeService" class="com.suntao.service.TypeService">
<property name="typeDao" ref="typeDao"/>
</bean>
<!--
实例化⼯⼚注⼊:
实例化⼯⼚注⼊也是借助set⽅法注⼊,只是被注⼊的bean对象的实例化是通过实例化⼯⼚实例
化的
-->
<bean id="instanceFactory" class="com.suntao.factory.InstanceFactory">
</bean>
<bean id="typeDao" factory-bean="instanceFactory" factorymethod="createTypeDao"></bean>
2、Spring Ioc自动装配
注解⽅式注⼊ Bean
对于 bean 的注⼊,除了使⽤ xml 配置以外,可以使⽤注解配置。注解的配置,可以简化配置⽂件,提⾼开发的速度,使程序看上去更简洁。对于注解的解释,Spring对于注解有专⻔的解释器,对定义的注解进⾏解析,实现对应bean对象的注⼊。通过反射技术实现。
2.1 基本步骤
2.1.1 修改配置文件
<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
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
2.1.2 开启自动化注入
<!--开启⾃动化装配(注⼊)-->
<context:annotation-config/>
<bean id="userDao" class="com.xxxx.dao.UserDao"></bean>
<bean id="userService" class="com.xxxx.service.UserService"></bean>
2.1.3 给注⼊的bean对象添加注解
2.2 @Resource注解
@Resource注解实现⾃动注⼊(反射)
- 默认根据属性字段名称查找对应的bean对象 (属性字段的名称与bean标签的id属性值相等)
- 如果属性字段名称未找到,则会通过类型(Class类型)查找
- 属性可以提供set⽅法,也可以不提供set⽅法
- 注解可以声明在属性级别 或 set⽅法级别
- 可以设置name属性,name属性值必须与bean标签的id属性值⼀致;如果设置了name属性值,就只会按照name属性值查找bean对象
- 当注⼊接⼝时,如果接⼝只有⼀个实现则正常实例化;如果接⼝存在多个实现,则需要使⽤name属性指定需要被实例化的bean对象
2.3 @Autowired注解
@Autowired注解实现⾃动化注⼊:
- 默认通过类型(Class类型)查找bean对象 与属性字段的名称⽆关
- 属性可以提供set⽅法,也可以不提供set⽅法
- 注解可以声明在属性级别 或 set⽅法级别
- 可以添加@Qualifier结合使⽤,通过value属性值查找bean对象(value属性值必须要设置,且值要与bean标签的id属性值对应)