Spring IoC基础
IoC控制反转
- loC控制反转,全称Inverse of Control,是一种设计理念
由代理人来创建与管理对象,消费者通过代理人来获取对象
loC的目的是降低对象之间直接耦合
加入loC容器将对象统一管理,让对象关联变为弱耦合
DI依赖注入
- loC是设计理念,是现代程序设计遵循的标准,是宏观目标
DI(Dependency Injection)是具体技术实现,是微观实现
DI在Java中利用反射技术实现对象注入(Injection)
Spring简介
- Spring框架是企业开发复杂性的一站式解决方案
Spring框架的核心是loC容器与AOP面向切面编程
Spring loC负责创建与管理系统对象,并在此基础上扩展功能
Bean的三种配置方式
- 基于XML配置Bean
applicationContext.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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 在Ioc容器启动时,自动由Spring实例化Apple对象,取名sweetApple放入到容器中 -->
<!-- bean标签默认通过默认构造方法创建对象 -->
<bean id="sweetApple" class="com.imooc.spring.ioc.entity.Apple">
<property name="title" value="红富士"></property>
<property name="origin" value="欧洲"></property>
<property name="color" value="红色"></property>
</bean>
XML方式创建IoC容器
// 创建spring Ioc容器,并根据配置文件在容器中实例化对象
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
- 利用构造方法参数名实例化
<bean id="sweetApple" class="com.imooc.spring.ioc.entity.Apple">
<!-- 没有constructor-arg则代表调用默认构造方法实例化 -->
<constructor-arg name="title" value="红富士"/>
<constructor-arg name="origin" value="欧洲"/>
<constructor-arg name="color" value="红色"/>
</bean>
- 利用构造方参数位置实例化
<bean id="sweetApple" class="com.imooc.spring.ioc.entity.Apple">
<constructor-arg index="0" value="红富士"/>
<constructor-arg index="1" value="欧洲"/>
<constructor-arg index="2" value="红色"/>
</bean>
- 利用静态工厂的静态方法实例化
/**
* 静态工厂通过静态方法创建对象,隐藏创建对象的细节
*/
public class AppleStaticFactory {
public static Apple createSweetApple(){
//logger.info("")
Apple apple = new Apple();
apple.setTitle("红富士");
apple.setOrigin("欧洲");
apple.setColor("红色");
return apple;
}
}
<!--利用静态工厂获取对象-->
<bean id="apple4" class="com.imooc.spring.ioc.factory.AppleStaticFactory"
factory-method="createSweetApple"/>
- 利用工厂实例方法创建对象
**
* 工厂实例方法创建对象是指IoC容器对工厂类进行实例化并调用对应的实例方法创建对象的过程
*/
public class AppleFactoryInstance {
public Apple createSweetApple(){
Apple apple = new Apple();
apple.setTitle("红富士");
apple.setOrigin("欧洲");
apple.setColor("红色");
return apple;
}
}
<!--利用工厂实例方法获取对象-->
<bean id="factoryInstance" class="com.imooc.spring.ioc.factory.AppleFactoryInstance"/>
<bean id="apple5" factory-bean="factoryInstance" factory-method="createSweetApple"/>
- 从IoC容器中获取Bean
// 初始化spring Ioc容器,并根据配置文件在容器中实例化对象
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
Apple sweetApple = context.getBean("sweetApple", Apple.class);
// 单参数方法获得Bean
Apple sweetApple1 = (Apple) context.getBean("sweetApple");
System.out.println(sweetApple.getTitle());
- bean标签中id与name属性相同点
bean id与name都是设置对象在loC容器中唯一标识
两者在同一个配置文件中都不允许出现重复
两者允许在多个配置文件中出现重复,新对象覆盖旧对象- bean标签中id与name属性不同点
id要求更为严格,一次只能定义一个对象标识(推荐)
name更为宽松,—次允许定义多个对象标识
tips: id与name的命名要求有意义,按驼峰命名书写- 在IoC容器初始化时加载多个配置文件
String[] configLocations = new String[]{"classpath:applicationContext.xml", "classpath:applicationContext-1.xml"};
ApplicationContext context = new ClassPathXmlApplicationContext(configLocations);
注:没有id与name的bean默认使用类名全称作为bean标识,即class属性的值。
- 路径表达式
classpath: 指向了target目录下的classes文件夹。
classpath:config.xml: 扫描classpath根路径(不包含jar)的config.xml
classpath:com/imooc/config.xml: 扫描classpath下(不包含jar)com.imooc包中的config.xml
classpath*:com/imooc/config.xml: 扫描classpath下(包含jar)com.imooc包中的
config.xml
classpath:config-*.xml: 扫描classpath根路径下所有以config-开头的XML文件
classpath:com/**/config.xml: 扫描com包下(包含任何子包)的config.xml
file:c:/config.xml: 扫描c盘根路径config.xml
- 对象依赖注入
依赖注入是指运行时将容器内对象利用反射赋给其他对象的操作
基于setter方法注入对象
基于构造方法注入对象
使用stter方法注入对象有两种情况:
- 利用setter实现静态数值注入
<bean id="sweetApple" class="com.imooc.spring.ioc.entity.Apple">
<! -- Ioc容器自动利用反射机制运行时调用setXXX方法为属性赋值-->
<property name="title" value="红富士"/>
<property name="color" value="红色"/>
<property name="origin" value="欧洲"/>
// Ioc 的value属性可以自动调用Apple.java类中的set方法,将"红富士"赋值给了title属性,所以在getTitle时可以直接得到title的值。
Apple sweetApple = context.getBean ( s: "sweetApple",Apple.class);
system.out.println (sweetApple.getTitle ( ) ) ;
// 输出是红富士
- 利用setter实现对象注入
<bean id="lily" class="com. imooe.spring.ioc.entity.Child">
<property name="nane" value="莉莉" />
<!-- 利门rel注入依赖对象 -->
<property name="apple" ref="sweetApple" />
</bean>
- 注入集合对象
注入List
<!-- 生成的数据类型为ArrayList -->
<bean id="..." class="...">
<property name= "someList" >
<list>
<value>具体值</value>
<ref bean="beanld"></ref>
</list>
</property>
</bean>
注入Set
<!-- 生成的数据类型为LinkedHashSet -->
<bean id="..." class="...">
<property name="someSet" >
<set>
<value>具体值</value>
<ref bean="beanld"></ref>
</set>
</property></bean>
注入Map
<!-- 生成的数据类型为LinkedHashMap -->
<bean id="..." class="..." >
<property name="someMap">
<map>
<entry key="k1" value="v1"></entry>
<entry key="k2" value-ref="beanld" ></entry >
<!-- 内部bean,没有beanid只能在这个map标签中使用,不能被外部引用 -->
<entry key="dev-88173">
<bean class="com.imooc.spring.ioc.entity.Computer">
<constructor-arg name="brand" value="联想"/>
<constructor-arg name="type" value="笔记本"/><constructor-arg name="sn" value="1280258012"/><constructor-arg name="price" value="5060" />
</bean>
</entry>
</map>
</property>
</bean>
注入Properties
<!-- 用于保存String字符串类型 -->
<bean id="..." class="...">
<property name= "someProperties">
<props>
<prop key="k1">v1</prop>
<prop key="k2" >v2</prop>
</props>
</property>
</bean>
- 查看Ioc 容器里的Bean内容
//返回一个获取容器内所有beanId的String数组
string[] beanNames = context.getBeanDefinitionNames();
- bean scope 属性
bean scope属性用于决定对象何时被创建与作用范围
bean scope配置将影响容器内对象的数量
默认情况下bean会在loC容器创建后自动实例化,全局唯一
<bean id="bookDao"
class="com.imooc.spring.ioc.bookshop.dao.BookDaoOraclelmpl"scope="prototype" />
singleton
单例(默认值),每一个容器有且只有唯一的实例,实例被全局共享
prototype
多例,每次使用时都是创建一个实例
request
web环境下,每一次独立请求存在唯一实例
session
web环境下,每一个session存在有唯一实例
global session
portlet的web应用的共享session中
websocket
每一次WebSocket连接中存在唯一实例
- singleton 与 prototype 对比
默认的singleton属性会让bean在配置文件加载的时候就初始化。
prototype属性会让配置的bean只在被关联到或者getbean方法调用的时候才初始化- bean的生命周期
prototype时对象创建与init-method延迟至执行业务代码阶段
prototype时对象不再受loC容器管理,不会触发destroy-method
延迟加载lazy-init属性可让对象创建与初始化延迟到执行代码阶段
- 基于注解配置Bean
摆脱繁琐的XML形式的bean与依赖注入配置
基于"声明式"的原则,更适合轻量级的现代企业应用
让代码可读性变得更好,研发人员拥有更好的开发体验- 三类注解
组件类型注解-声明当前类的功能与职责
自动装配注解-根据属性特征自动注入对象
元数据注解-更细化的辅助loC容器管理对象的注解- 组件类型注解
@Component: 组件注解,通用注解,被该注解描述的类将被loC容器管理并实例化
@Controller: 语义注解,说明当前类是MVC应用中的控制器类
@Service: 语义注解,说明当前类是Service业务服务类
@Repository: 语义注解,说明当前类用于业务持久层,通常描述对应Dao类
开启组件扫描
<!--XML配置开启组件扫描,才能使用注解-->
<context:component-scan base-package="com.imooc">
<!-- 对一些文件排除在组件扫描之外 -->
<context:exclude-filter type="regex" expression="com.imooc.exl.*" /></context:component-scan>
例子:
<?xml version="1.0" encoding="UTF-8"?>
<!-- 基于注解的schema约束和xml的不同。 -->
<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
https://www.springframework.org/schema/context/spring-context.xsd">
<!-- xmlns:context="http://www.springframework.org/schema/context" 为设置一个叫context的命名空间。 -->
<context:annotation-config/>
<!-- 在Ioc容器初始化时自动扫描四种组件类型注解并完成实例化
@Repository
@Service
@controller
@Component
-->
<context:component-scan base-package="com.imooc"/>
</beans>
import org.springframework.stereotype.Repository;
// 组件类型注解默认beanId为类名首字母小写
// beadld = userDao
// 设置指定的beanUd: @Repository("udao")
@Repository
public class UserDao {
}
- 自动注解装配
按类型装配:
@Autowired: 按容器内对象类型动态注入属性,由Spring机构提供
@Inject: 基于JSR-330(Dependency lnjection for Java)标准, 其他同@Autowired,但不支持required属性
按名称装配:
@Named: 与@Inject配合使用,JSR-330规范,按属性名自动装配属性
@Resource: 基于JSR-250规范,优先按名称、再按类型智能匹配
// Spring IoC容器会自动通过反射技术将属性private修饰符自动改为public,直接进行赋值
//不再执行set方法
@Autowired
private UserDao udao ;
public UserDao getUdao (){
return udao;
@Autowired
//如果装配注解放在set方法上,则自动按类型
//名称对set方法参数进行注入
public void setUdao (UserDao udao){
System.out.println ( "setUdao : " t udao) ;
this.udao = udao;
)
}
/**
* 1.@Resource设置name属性,则按name在IoC容器中将bean注入* 2.@Resource未设置name属性
* 2.1以属性名作为bean name在Ioc容器中匹配bean ,如有匹配则注入
* 2.2按属性名未匹配,则按类型进行匹配,同@Autowired,需加入ePrimary解决类型冲突*使用建议:在使用@Resource对象时推荐设置name或保证属性名与bean名称一致
**/
// @Resource (name = "useroracleDao")
@Resource
private IUserDao userOracleDao;
- 元数据注解
@Primary: 按类型装配时出现多个相同类型对象,拥有此注解对象优先被注入
@PostConstruct: 描述方法,相当于XML中init-method配置的注解版本
@PreDestroy: 描述方法,相当于XML中destroy-method配置的注解版本
@Scope: 设置对象的scope属性
@Value: 为属性注入静态数据- 基于Java Config代码配置Bean
完全摆脱XML的束缚,使用独立Java类管理对象与依赖
注解配置相对分散,利用Java Config可对配置集中管理
可以在编译时进行依赖检查,不容易出错
Java Config核心注解
@Configuration: 描述类,说明当前类是Java Config配置类,完全替代XML文件
@Bean: 描述方法,方法返回对象将被loC容器管理,beanld默认为方法名
@lmportResource: 描述类,加载静态文件,可使用@Value注解获取
ComponentScan: 描述类,同XML的<context:compoment-scan>标签
// 配置类的代码
@Configuration
//当前类是一个配置类,用于替代applicationContext.xml
public class Config {
@Bean //Java Config利用方法创建对象,将方法返回对象放入容器, beanId=方法名
public UserDao userDao(){
UserDao userDao = new UserDao();
return userDao;
}
@Bean
public Userservice userservice() {
UserService userService = new UserService();return userService;
}
@Bean
public UserController userController() {
UserController userController = new UserController() ;return userController;
}
}
// 加载配置类的代码
//基于Java Config配置ioc容器的初始化
ApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
- Spring Test 测试模块
Spring Test是Spring中用于测试的模块
Spring Test对JUnit单元测试框架有良好的整合
通过Spring Test可在JUnit在单元测试时自动初始化loC容器
Spring 与 JUnit4 整合
Maven工程依赖spring-test
利用@RunWith与@ContextConfiguration描述测试用例类
测试用例类从容器获取对象完成测试用例的执行
需要的依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.2.6.RELEASE</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
例子测试代码
在这里插入代码片// 将Junit4的执行权交由spring Test,在测试用例执行前自动初始化IoC容器
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:applicationContext.xml"})
public class SpringTestor {
@Resource
private UserService userService;
@Test
public void testUserService(){
userService.createUser();
}
}