spring IOC
spring是java的众多开源项目的中的一员,主要核⼼是IOC(控制反转/依赖注⼊)与 AOP(⾯向切⾯) 两⼤技术,实现项目开发过程的解耦,提高项目的开发效率。
首先我们先来学习下IOC的知识。
环境配置
1>创建一个maven的项目,目前因为我们还不用与网页的交互,可以先创建一个quickstart的项目.
2>项目环境的修改(pom.xml中)
jdk版本的修改;JUnit 版本的修改(可以改为4.12);删除build标签中的pluginManagement标签
3>添加依赖(pom.xml中的< dependencies>标签中添加)
添加Spring框架的核⼼依赖(spring-context)
其他的spring依赖之后用到时,再添加
4>创建完善目录文件
一般我们的目录:
main–java–package(com.xxx)—包controller|dao|service|po–类UserController|UserDao|UserService|User
和java的同一级目录下新建resources文件(标记为Resources Root)—spring.xml
dao层:数据访问层,操作数据库相关的操作
Service层叫服务层,被称为服务,对一个或多个DAO进行的再次封装,封装成一个服务
Controler负责请求转发,接受页面过来的参数,传给Service处理,接到返回值,再传给页面。
5>编写 Bean 对象
下面代码中是写在UserService中的,写在其他类中也是可以运行的
package com.xxxx.service;
public class UserService {
public void test(){
System.out.println("Hello Spring!");
}
}
6>配置spring.xml
spring.xml的配置:我们可以到官网上复制,之后配置bean到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">
<!--
id:bean对象的id,唯⼀标识。⼀般是Bean对象的名称的⾸字⺟⼩写
class:bean对象的类路径
-->
<bean id="userSer" class="com.xxxx.service.UserSer"></bean>
</beans>
7>加载配置文件,实例化对象
可以直接在自动生成的App类中写
public class App {
public static void main( String[] args ) {
// 获取Spring上下⽂环境 (加载配置⽂件)
ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");
// 通过getBean⽅法得到Spring容器中实例化好的Bean对象 (实例化Bean对象)
// userService代表的是配置⽂件中bean标签的id属性值
UserService userService = (UserService) ac.getBean("userService");
// 调⽤⽅法 (使⽤实例化对象)
userService.test();
}
}
实例化bean对象
实例化bean有构造器|静态工厂|实例化工厂 实例化;这边主要讲下构造器实例化.
开发中项⽬⼀般使⽤ 构造器实例化 ⽅式实例化bean,项⽬开发基本采⽤构造器⽅式,交给Spring托管,使⽤时直接拿来使⽤即可。
构造器实例化
通过默认构造器创建 空构造⽅法必须存在 否则创建失败
和前边我们在环境配置中的应用是差不多的.
1>设置配置⽂件 spring.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">
<bean id="userService" class="com.xxxx.service.UserService"></bean>
</beans>
2>获取实例化对象
ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");
UserService userService = (UserService) ac.getBean("userService");
userService.test();
三种实例化的区别
构造器:通过bean的缺省构造函数创建,当各个bean的业务逻辑相互⽐较独⽴的时候或者和外界
关联较少的时候可以使⽤。
静态工厂:利⽤静态factory⽅法创建,可以统⼀管理各个bean的创建,如各个bean在创建之前需要
相同的初始化处理,则可⽤这个factory⽅法险进⾏统⼀的处理等等。
实例化工厂:利⽤实例化factory⽅法创建,即将factory⽅法也作为了业务bean来控制,1可⽤于集成
其他框架的bean创建管理⽅法,2能够使bean和factory的⻆⾊互换。
依赖注入
手动注入
Spring ⽀持的注⼊⽅式共有四种:set 注⼊、构造器注⼊、静态⼯⼚注⼊、实例化⼯⼚注⼊。同样这边只介绍下set和构造器注入.另外两种在项目中也使用的不多,这边就不介绍了.
set注入
前提:属性字段需要提供set⽅法
这里需要将dao层的注入的service层,因此需要先写下dao层
package com.xxxx.dao;
public class UserDao {
public void test(){
System.out.println("连接数据库,查询数据");
}
}
1>属性字段提供set方法
public class UserService {
// 业务对象UserDao set注⼊(提供set⽅法)
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
}
2>配置⽂件的bean标签设置property标签
<!--
IOC通过property标签⼿动装配(注⼊):
Set⽅法注⼊
name:bean对象中属性字段的名称
ref:指定bean标签的id属性值 | value:具体的值(基本类型 常⽤对象|⽇期 集合)
-->
<bean id="userDao" class="com.xxxx.dao.UserDao"></bean>
<bean id="userService" class="com.xxxx.service.UserService">
<!--业务对象 注⼊-->
<property name="userDao" ref="userDao"/>
</bean>
spring2.5以后,为了简化setter⽅法属性注⼊,引⽤p名称空间的概念,可以将 ⼦元素,简化为元素
属性配置。
构造器注入
提供带参构造器
java代码和xml配置
public class UserService {
private UserDao userDao; // JavaBean 对象
public UserService(UserDao userDao) {
this.userDao = userDao;
}
public void test(){
System.out.println("UserService Test...");
}
<bean id="userDao" class="com.xxxx.dao.UserDao" ></bean>
<bean id="userService" class="com.xxxx.service.UserService">
<constructor-arg name="userDao" ref="userDao"></constructor-arg>
</bean>
循环问题产⽣的原因:
Bean通过构造器注⼊,之间彼此相互依赖对⽅导致bean⽆法实例化。
解决:将构造器注⼊改为set⽅法注⼊
自动注入
准备环境
<!--开启⾃动化装配(注⼊)-->
<context:annotation-config/>
<bean id="userDao" class="com.xxxx.dao.UserDao"></bean>
<bean id="userService" class="com.xxxx.service.UserService"></bean>
@Resource注解
@Resource注解实现⾃动注⼊(反射)
如果报错,可以试下导入javax.annotation-api依赖
- 默认根据属性字段名称查找对应的bean对象
- 如果属性字段名称未找到,则会通过类型(Class类型)查找
- 属性可以提供set⽅法,也可以不提供set⽅法
- 注解可以声明在属性级别 或 set⽅法级别
- 可以设置name属性,name属性值必须与bean标签的id属性值⼀致;如果设置了name属性值, 就只会按照name属性值查找bean对象
- 当注⼊接⼝时,如果接⼝只有⼀个实现则正常实例化;如果接⼝存在多个实现,则需要使⽤name 属性指定需要被实例化的bean对象
public class UserService {
@Resource //@Resource(name = "userDao")
private UserDao userDao; // 属性字段的名称与bean标签的id属性值相等
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public void test() {
// 调⽤UserDao的⽅法
userDao.test();
}
@Autowired注解
@Autowired注解实现⾃动化注⼊:
- 默认通过类型(Class类型)查找bean对象 与属性字段的名称⽆关
- 属性可以提供set⽅法,也可以不提供set⽅法
- 注解可以声明在属性级别 或 set⽅法级别
- 可以添加@Qualifier结合使⽤,通过value属性值查找bean对象(value属性值必须要设置,且值 要与bean标签的id属性值对应)
public class UserService {
@Autowired
// value属性值必须要设置,且值要与bean标签的id属性值对应
//@Qualifier(value="userDao")
private UserDao userDao; // 默认通过类型(Class类型)查找bean对象 与属性字段的名称⽆关
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public void test() {
// 调⽤UserDao的⽅法
userDao.test();
}
}
扫描器
实际的开发中,bean的数量⾮常多,采⽤⼿动配置bean的⽅式已⽆法满⾜⽣产需要,Spring这时候
同样提供了扫描的⽅式,对扫描到的bean对象统⼀进⾏管理,简化开发配置,提⾼开发效率。
Spring IOC 扫描器
作⽤:bean对象统⼀进⾏管理,简化开发配置,提⾼开发效率
1、设置⾃动化扫描的范围
如果bean对象未在指定包范围,即使声明了注解,也⽆法实例化
2、使⽤指定的注解(声明在类级别) bean对象的id属性默认是 类的⾸字⺟⼩写
Dao层:
@Repository
Service层:
@Service
Controller层:
@Controller
任意类:
@Component
注:开发过程中建议按照指定规则声明注解
xml配置
<!-- 设置⾃动化扫描的范围 -->
<context:component-scan base-package="com.xxxx"/>
bean的作用域和生命周期
作用域
singleton 作⽤域
lazy-init是懒加载, 如果等于true时作⽤是指Spring容器启动的时候不会去实例化这个bean,
⽽是在程序调⽤时才去实例化. 默认是false即Spring容器启动时实例化.
默认情况下,被管理的bean只会IOC容器中存在⼀个实例,对于所有获取该Bean的操作Spring容器
将只返回同⼀个Bean。
容器在启动的情况下就实例化所有singleton 的 bean对象,并缓存与容器中
prototype 作⽤域
通过scope=“prototype” 设置bean的类型 ,每次向Spring容器请求获取Bean都返回⼀个全新的
Bean,相对于"singleton"来说就是不缓存Bean,每次都是⼀个根据Bean定义创建的全新Bean。
Web应⽤中的作⽤域
request作⽤域:表示每个请求需要容器创建⼀个全新Bean。
session作⽤域:表示每个会话需要容器创建⼀个全新Bean。
globalSession作⽤域:类似于session作⽤域,其⽤于portlet
生命周期
Bean的定义、初始化、使⽤和销毁4个阶段
定义:在配置文件中定义,⼀个配置⽂档中,可以定义多个Bean。
初始化:通过指定 init-method 属性来完成
实现 org.springframework.beans.factory.InitializingBean 接⼝
使用:使⽤ BeanFactory ,使⽤ ApplicationContext
销毁: 实现销毁⽅式(Spring容器会维护bean对象的管理,可以指定bean对象的销毁所要执⾏的⽅
法)
通过 AbstractApplicationContext 对象,调⽤其close⽅法实现bean的销毁过程