文章目录
一、 Spring概述
## Spring是什么
Spring是分层的JavaSE/EE应用full-stack(全栈)轻量级开源框架;
Spring框架是J2EE企业级应用的轻量级开源框架,提供了表现层springmvc
和持久springJDBC(JDBCTemplate),以及业务层的事务管理等企业级应用解决方案;
Spring能将开源世界中众多优秀的第三方框架进行集成比如mybatis等
Spring是以IOC(Inversion Of Control)控制反转和AOP(Aspect Oriented Programming)面向切面编程为核心;
源码下载地址: https://repo.springsource.org/libs-release-local/org/springframework/spring/
##Spring的发展历史:
1997年IBM提出了EJB的思想
1998年,SUN制定开发标准规范EJB1.0
1999年,EJB1.1发布
2001年,EJB2.0发布
2003年,EJB2.1发布
2006年,EJB3.0发布
Rod Johnson(spring之父)
Expert One-to-One J2EE Design and Development(2002)
阐述了J2EE使用EJB开发设计的优点及解决方案
Expert One-to-One J2EE Development without EJB(2004)
阐述了J2EE开发不使用EJB的解决方式(Spring雏形)
2017年9月份发布了spring的最新版本--spring 5.0通用版(GA)
##Spring特点
【俗称Spring为开发架构的`粘合剂`。】
Spring 出现是为了解决JavaEE 实际问题:
1、方便解耦,简化开发 (IOC)
Spring就是一个大工厂【容器】,可以将所有对象创建和依赖关系维护交给Spring管理,
Spring工厂是用于生成bean
2、AOP编程的支持
Spring提供面向切面编程,可以方便的实现对程序进行权限拦截、运行监控等功能
3、声明式事务的支持
只需要通过配置就可以完成对事务的管理,而无需手动编程
4、方便程序的测试
Spring对Junit4支持,可以通过注解方便的测试Spring程序
5、方便集成各种优秀框架
Spring不排斥各种优秀的开源框架,其内部提供了对各种优秀框架(如:Struts、Hibernate、MyBatis、Quartz等)的直接支持
6、降低JavaEE API的使用难度
Spring 对JavaEE开发中非常难用的一些API,如:JDBC、JavaMail、远程调用等,都提供了封装,使这些API应用难度得到降低
##Spring体系结构
测试(Test)模块
核心容器(Core Container)
AOP(Aspect Oriented Programming)模块
数据访问/集成(Data Access/Integration)层
Web层
##Spring核心
Spring为企业级开发提供了丰富的功能,这些功能的底层都依赖于它的两个核心特性:
1、控制反转(Inversion of Control,**IOC**)
2、面向切面编程(aspect-oriented programming,**AOP**)
# 那么IOC和AOP是一种技术吗?不是的!他们是一种思想
二、高内聚低耦合【了解】
1、耦合与内聚概述
`代码的书写原则:高内聚低耦合
##耦合与内聚的概念
耦合(Coupling):代码书写过程中所使用技术的结合紧密度程序之间的依赖程度,
用于衡量软件中【各个模块之间的联系程度】。
内聚(Cohesion):代码书写过程中单个模块内部各组成部分间的联系,
用于衡量软件中各个【功能模块内部的功能联系】。
程序书写的原则:【高内聚,低耦合】。就是同一个模块内的各个元素之间要高度紧密,但是各个模块之间的相互依存度却不要那么紧密
##耦合的说明
耦合: 程序代码之间的依赖关系
低耦合: 降低程序代码之间的依赖关系,从而方便维护扩展和重用
解耦合: 在java程序代码中,耦合是不可能完全解开的,我们所说的"解耦合"指的是【解开程序编译期的耦合】
##耦合的弊端:
独立性差 可重用性不高 维护成本高
2、解耦过程(分析javaweb开发)
1、服务层与持久层存在紧耦合;
2、我们加入工厂模式后,服务层与持久层完成解耦,但是工厂类与持久层存在紧耦合;
3、于是通过工厂模式和静态资源配置将代码的耦合降到最低;
最终方案:工厂+反射+配置文件 --》解耦
3、解耦方案【工厂+反射+配置文件】
1)配置文件 bean.properties
# 格式:key=value
# key: 自定义,一般为当前类实现的接口的名称
# value: 当前需要使用的类的全限定名
userDao=com.exmple.dao.impl.UserDaoImpl
userService=com.exmple.service.UserServiceImpl
2)工厂模式-bean单实例 [饿汉模式/懒汉模式]
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.ResourceBundle;
/**
* bean工厂: 用于创建Bean对象(java对象)
*/
public class BeanFactory1 {
// 用于存放创建的bean对象(容器)
private static Map<String,Object> beansMap = new HashMap<>();
// 用于存放解析到的全限定名
private static Map<String,String> urlMap = new HashMap<>();
static {
// 1.解析配置文件,获取配置文件中配置的全限定名
// ResourceBundle: jdk提供的工具,专门用于解析properties配置文件
ResourceBundle bundle = ResourceBundle.getBundle("beans");
// 获取properties配置文件中所有的key
Enumeration<String> keys = bundle.getKeys();
while (keys.hasMoreElements()){
// 获取下一个key
String key = keys.nextElement();
// 根据key获取对应的全限定名
String value = bundle.getString(key);
// 存放到map集合中
urlMap.put(key,value);
-------------------------------------------------------------
// 立即加载的思想创建bean对象 【饿汉模式】
Object obj = Class.forName(value).newInstance();
// 将创建好的对象存放到beansMap容器中
beansMap.put(key,obj);
-------------------------------------------------------------
}
// 测试是否解析到了数据
for (String key:urlMap.keySet()){
System.out.println(key+" : "+urlMap.get(key));
}
}
// 反射创建类对象 【懒汉模式】
public static Object getBean(String id) {
try {
// 先从bean容器中获取对象
Object obj = beansMap.get(id);
if(obj==null){
// 根据id获取对应的类的全限定名
String className = urlMap.get(id);
// 反射创建类对象
obj = Class.forName(className).newInstance();
// 将创建好的bean对象存放到beansMap容器中
beansMap.put(id,obj);
}
return obj;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
3)工厂类代码-bean多实例
/**
* bean工厂: 专门用于创建Bean对象(java对象)
*/
public class BeanFactory {
// 用于存放解析到的全限定名
private static Map<String,String> urlMap = new HashMap<>();
static {
// 1.解析配置文件,获取配置文件中配置的全限定名
// ResourceBundle: jdk提供的工具,专门用于解析properties配置文件
ResourceBundle bundle = ResourceBundle.getBundle("beans");
// 获取properties配置文件中所有的key
Enumeration<String> keys = bundle.getKeys();
while (keys.hasMoreElements()){
// 获取下一个key
String key = keys.nextElement();
// 根据key获取对应的全限定名
String value = bundle.getString(key);
// 存放到map集合中
urlMap.put(key,value);
}
// 测试是否解析到了数据
for (String key:urlMap.keySet()){
System.out.println(key+" : "+urlMap.get(key));
}
}
// 反射创建类对象
public static Object getBean(String id) {
try {
// 根据id获取对应的类的全限定名
String className = urlMap.get(id);
// 反射创建类对象
Object obj = Class.forName(className).newInstance();
return obj;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
三、Spring核心之IOC
1、IOC概念和作用
IOC 全称为 Inversion of Control,翻译为 “控制反转”。
【1】控制什么
控制对象的创建和销毁
【2】反转什么
反转创建对象的控制权,将(创建和销毁)对象的控制权交给IOC容器
【3】IOC的作用
解耦
传统方式创建对象: new 对象(); 【主动创建】
IOC方式创建对象: 找容器(本质上就是一个Map集合)【被动接收】
分析解耦的过程:
通过标记(标记就是配置文件中的key)找工厂,工厂帮我们创建对应的类对象,并返回给我们使用。
当前类可以选择主动出击(new的方式)创建对象,但是此时耦合度高。
此时把主动创建改成被动接收,由工厂对象为当前类生产所必须的关联对象,此时降低了两个类的依赖关系。
2、IOC解耦分析
我们知道在面向对象设计的软件系统中,它的底层都是由N个对象构成的,
各个对象之间通过相互合作,最终实现系统地业务逻辑 ,如图所示:
IOC理论提出的观点:借助于“第三方”实现具有依赖关系的对象之间的解耦。 如图所示:
由于引进了中间位置的“第三方”,也就是IOC容器,使得A、B、C、D这4个对象没有了耦合关系,
齿轮之间的传动全部依靠“第三方”了,全部对象的控制权全部上缴给“第三方”IOC容器。
所以,IOC容器成了整个系统的关键核心,它起到了一种类似“粘合剂”的作用,
把系统中的所有对象粘合在一起发挥作用,如果没有这个“粘合剂”,对象与对象之间会彼此失去联系,
这就是有人把IOC容器比喻成“粘合剂”的由来。
我们把上图中间的IOC容器隐藏,然后再来看看这套系统 :
我们现在看到的画面,就是我们要实现整个系统所需要完成的全部内容。这时候,A、B、C、D这4个对象之间已经没有了耦合关系,彼此毫无联系,这样的话,当你在实现A的时候,根本无须再去考虑B、C和D了,对象之间的依赖关系已经降低到了最低程度。
3、手写IOC【工厂模式->解耦】
我们通过使用工厂模式,实现了表现层——业务层、业务层——持久层的解耦。
【实现思路】:
工厂+反射+配置文件
【核心思想】:
【1】读取配置文件中类的全限定名通过反射机制创建对象。
【2】把创建出来的对象事先都存起来,当我们使用时可以直接从存储容器中获取。
存哪去?
由于我们是很多对象,肯定要找个集合来存。这时候有 Map 和 List 供选择。
到底选 Map 还是 List 就看我们有没有查找需求。有查找需求,选 Map。
所以我们的答案就是在应用加载时,创建一个 Map,用于存放bean对象。
我们把这个 map 称之为容器。
什么是IOC工厂
事先加载bean,并且提供一个直接获取bean的方法。
什么是控制反转
主动new对象方式--被动从容器中获取
代码演示
1、创建项目及J2EE三层架构
2、创建pojo对象
3、创建dao对象
4、创建service对象
5、创建controller对象
6、创建properties文件
7、factory工厂类【重点】
【1】事先创建集合容器
【2】事先加载properties文件内容
【3】反射机制实例化bean对象,并且放入集合容器
【4】公共的访问方法
projo
Account类
/**
* @Description:账户实体类
*/
public class Account {
//账户编号
private String Id;
//账户所有者
private String accountName;
//账户余额
private Float money;
public Account() {
}
public String getId() {
return Id;
}
public void setId(String id) {
Id = id;
}
public String getAccountName() {
return accountName;
}
public void setAccountName(String accountName) {
this.accountName = accountName;
}
public Float getMoney() {
return money;
}
public void setMoney(Float money) {
this.money = money;
}
@Override
public String toString() {
return "Account{" +
"Id='" + Id + '\'' +
", accountName='" + accountName + '\'' +
", money=" + money +
'}';
}
}
dao层
AccountDao接口
/**
* @Description:账户dao层
*/
public interface AccountDao {
/**
* @Description 新增
*/
void saveAccount();
/**
* @Description 删除
*/
void delAccount();
/**
* @Description 修改
*/
void updateAccout();
/**
* @Description 查询
*/
void findAccount();
}
AccountDaoImpl实现类
/**
* @Description:
*/
public class AccountDaoImpl implements AccountDao {
private static Account account;
static {
account = new Account();
account.setId("010101");
account.setAccountName("张三");
account.setMoney(2000F);
}
@Override
public void saveAccount() {
System.out.println("保存:"+account.toString());
}
@Override
public void delAccount() {
System.out.println("删除:"+account.toString());
}
@Override
public void updateAccout() {
System.out.println("修改:"+account.toString());
}
@Override
public void findAccount() {
System.out.println("查询:"+account.toString());
}
}
servic层
AccountService接口
/**
* @Description:用户业务层接口
*/
public interface AccountService {
/**
* @Description 新增
*/
void saveAccount();
/**
* @Description 删除
*/
void delAccount();
/**
* @Description 修改
*/
void updateAccout();
/**
* @Description 查询
*/
void findAccount();
void setAccountDao(AccountDao accountDao);
}
AccountServiceImpl实现类
/**
* @Description:用户业务层接口实现
*/
public class AccountServiceImpl implements AccountService {
private AccountDao accountDao;
@Override
public void saveAccount() {
accountDao.saveAccount();
}
@Override
public void delAccount() {
accountDao.delAccount();
}
@Override
public void updateAccout() {
accountDao.updateAccout();
}
@Override
public void findAccount() {
accountDao.findAccount();
}
@Override
public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}
}
factory层
BeanFactory工厂类
在resources目录中建立db.properties
accountDao = com.example.spring.dao.impl.AccountDaoImpl
accountService = com.example.spring.service.impl.AccountServiceImpl
/**
* @Description:bean工厂
*/
public class BeanFactory {
//1、事先存储容器
private static Map<String, Object> map = new HashMap<>();
//2、加载配置文件
static {
Properties properties = new Properties();
try {
properties.load(BeanFactory.class.getClassLoader()
.getResourceAsStream("db.properties"));
Enumeration<?> enumeration = properties.propertyNames();
while (enumeration.hasMoreElements()) {
String key = (String) enumeration.nextElement();
String value = (String) properties.get(key);
//3、实例化bean
Object beanObject = Class.forName(value).newInstance();
//4、放入容器
map.put(key,beanObject);
}
} catch (Exception e) {
e.printStackTrace();
}
}
//5、公共方法获得bean
public static Object getBean(String calssName){
return map.get(calssName);
}
}
controller层
ClientController测试类
/**
* @Description:
*/
public class ClientController {
@Test
public void saveAccount() {
AccountService accountService = (AccountService) BeanFactory.getBean("accountService");
accountService.setAccountDao((AccountDao) BeanFactory.getBean("accountDao"));
accountService.saveAccount();
}
}
4、IOC入门案例
案例分析
##思考
1、我们采用工厂+反射的方式实现了手写IOC工厂,那么spring-IOC的工厂是不是也类似?
spring框架提供了一个大工厂接口:ApplicationContext==》Beanfactroy
2、手写IOC中的配置文件类型是properties,那么spring-IOC的配置采取的是什么类型?
spring使用XML格式的文件存储配置
<bean id="唯一标识"
class="实现类的全限定名">
</bean>
3、spring-IOC是怎么加载配置文件的呢?
ApplicationContext工厂使用ClassPathXmlApplicationContext加载配置文件
4、手写IOC中的BeanFactory提供一个公共获得bean的方法,那spring-ioc是不是有类似的方法?
ApplicationContext工厂使用getBean()方法,用于根据bean的名称获取实例化对象
##目标
1、掌握spring-IOC工厂的创建
2、掌握bean标签的基本配置
3、掌握spring-IOC工厂获得实例化对象的方式
##实现
步骤:
1、导入依赖
2、编写bean.xml文件替换bean.properties文件
3、使用ClassPathXmlApplicationContext加载bean.xml配置文件
4、使用ApplicationContext工厂的getBean()方法获得bean对象
代码演示
导入依赖pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example.spring</groupId>
<artifactId>spring-day01-04spring-ioc-xml</artifactId>
<version>1.0-SNAPSHOT</version>
<name>spring-day01-04spring-ioc-xml</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<!-- spring版本 -->
<spring.version>5.1.11.RELEASE</spring.version>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
</dependencies>
<build>
</build>
</project>
Spring配置文件bean.xml
<!--文件的类型 版本 编码-->
<?xml version="1.0" encoding="UTF-8"?>
<!--Spring的命名空间 -->
<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">
<!--
bean作用:声明类交给spring容器
属性: id: 唯一标识 class:全路径限定名称
细节:默认使用无参构造函数实例化
-->
<bean id="accountDao" class="com.example.spring.dao.Impl.AccountDaoImpl"/>
<bean id="accountService" class="com.example.spring.service.Impl.AccountServiceImpl"/>
</beans>
改造AccountService
/**
* @Description:账户操作接口
*/
public interface AccountService {
/**
* @Description 创建账户
*/
void createAccount();
/**
* @Description 传入accountDao
* @param
* @return
*/
void setAccountDao(AccountDao accountDao);
}
/**
* @Description:账户操作实现
*/
public class AccountServiceImpl implements AccountService {
AccountDao accountDao ;
@Override
public void createAccount() {
accountDao.createAccount();
}
@Override
public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}
}
改造ClientController
/**
* @Description:客户端
*/
public class ClientContrller {
/**
* ApplicationContext:spring-IOC容器
* ClassPathXmlApplicationContext:容器实现类,加载配置文件
* applicationContext.getBean:获得容器中的bean对象
*/
@Test
public void createAccount(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml");
AccountDao accountDao = (AccountDao) applicationContext.getBean("accountDao");
AccountService accountService = (AccountService) applicationContext.getBean("accountService");
accountService.setAccountDao(accountDao);
accountService.createAccount();
}
}
四、Spring之IOC工厂类【了解】
IDEA中查看类的层级结构,快捷方式: ctrl + alt + U
BeanFactory:
它是spring中ioc容器的顶层接口,ApplicationContext只是它的子接口。
提供创建容器中对象的时机,使用延迟加载(懒加载)的思想。
ApplicationContext:
继承了BeanFactory的加载方式,而且还扩展出来了立即加载思想的创建容器的方式。
每次在使用时它才真正的创建对象。
1、BeanFactory接口
1)作用
Spring里面最顶层的接口,提供了最简单的容器的功能,只定义了实例化对象和拿对象的功能;
2)方法
public interface BeanFactory {
//对FactoryBean的转义定义,因为如果使用bean的名字检索FactoryBean得到的对象是工厂生成的对象
String FACTORY_BEAN_PREFIX = "&";
//根据bean的名字,在IOC容器中得到bean实例,
*Object getBean(String name) throws BeansException;
//根据bean的名字,在IOC容器中得到bean实例,args:显式参数(必须为非单例模式)
Object getBean(String name, Object... args) throws BeansException;
//根据bean的名字获得对象,并转换为Class类型
*<T> T getBean(String name, Class<T> requiredType);
//根据bean的类型获得对象(必须是拥有唯一实现类)
*<T> T getBean(Class<T> requiredType) throws BeansException;
//根据bean的类型获得对象,args:显式参数
<T> T getBean(Class<T> requiredType, Object... args) throws BeansException;
//这里提供对bean的检索,看看是否在IOC容器有这个名字的bean
*boolean containsBean(String name);
//判断这个bean是不是单例
*boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
//同时判断这个bean是不是多例
*boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
//这里得到bean实例的Class类型
*Class<?> getType(String name) throws NoSuchBeanDefinitionException;
//这里得到bean的别名,如果根据别名检索,那么其原名也会被检索出来
*String[] getAliases(String name);
2、ApplicationContext接口
1)作用
应用上下文,继承BeanFactory接口,它是Spring的更高级的容器,提供了更多的有用的功能;
1) 国际化(MessageSource)
2) 访问资源,如URL和文件(ResourceLoader)
3) 载入多个(有继承关系)上下文 ,使得每一个上下文都专注于一个特定的层次,比如应用的web层
4) 消息发送、响应机制(ApplicationEventPublisher)
5) AOP(拦截器)
2)实现类
ClassPathXmlApplicationContext
从类的根路径下加载配置文件 【推荐使用这种】
FileSystemXmlApplicationContext
从硬盘路径下加载配置文件
AnnotationConfigApplicationContext
基于Java的配置类加载Spring的应用上下文配置
@Test
public void createAccountTest(){
//加载配置文件
ApplicationContext applicationContext =
new ClassPathXmlApplicationContext("bean.xml");
//获得bean
AccountDao accountDao = (AccountDao) applicationContext.getBean("accountDao");
AccountServic accountServic = (AccountServic) applicationContext.getBean("accountServic");
//set方法指定accountDao
accountServic.setAccountDao(accountDao);
//创建账户
accountServic.createAccount();
}
3、接口容器的加载顺序
代码演示
##思考
BeanFactory、ApplicationContext都是容器,那么他们的加载顺序有什么不同?
##目的
了解BeanFactory和ApplicationContext的加载顺序
##实现
步骤:
1、观察ApplicationContext的加载方式
2、观察BeanFactory的加载方式
3、比较一下加载顺序
改造AccountDaoImpl
在AccountDaoImpl中增加构造函数
public AccountDaoImpl() {
System.out.println("AccountDaoImpl的实例已经创建");
}
改造ClientController
/**
* @Description:测试
*/
public class ClientController {
@Test
public void saveAccount() {
/**
* Spring-IOC容器:ApplicationContext
* 构建方式:通过ClassPathXmlApplicationContext加载配置文件
* 使用bean:getBean
*/
System.out.println("======ApplicationContext开始创建容器=====");
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml");
System.out.println("======ApplicationContext创建容器完成=====");
applicationContext.getBean("accountDao");
System.out.println("======分割线==========");
System.out.println("======BeanFactory开始创建容器=====");
Resource resource = new ClassPathResource("bean.xml");
BeanFactory beanFactory = new XmlBeanFactory(resource);
System.out.println("======BeanFactory创建容器完成=====");
beanFactory.getBean("accountDao");
}
}
【3.4】加载顺序
小结
1.BeanFactory是顶层接口
2.ApplicationContext是子接口
3.它们最大的区别是创建对象的时间不一样(单例的):
【BeanFactory】采用的是延迟加载的思想。即什么时候使用对象,什么时候创建
【ApplicationContext】采用立即创建的思想。即一加载配置文件,立即就创建
五 bean标签详解【重点】
1、bean标签作用
bean作用:用于配置对象让spring 来创建的。
【细节】
默认情况下调用类的无参构造函数。
2、bean标签基本属性
属性 | 说明 |
---|---|
id | bean的唯一标识名称 |
class | 实现类的全限定名称 |
name | bean的名称 * 多个别名使用 ”,” 分割 * bean与bean的别名不可以重复 |
入门案例中我们已经基本使用过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
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="accountDao" name="accountDao2,accountDao3" class="com.example.spring.dao.impl.AccountDaoImpl"></bean>
<bean id="accountService" class="com.example.spring.service.impl.AccountServiceImpl"></bean>
</beans>
3、bean标签作用范围
属性 | 说明 |
---|---|
scope | 指定对象的作用范围。 * singleton 【默认】: 单例,所有的请求都用一个对象来处理 * prototype : 多例,每个请求用一个新的对象来处理 * request : WEB 项目中,将对象存入到 request 域中. * session : WEB 项目中,将对象存入到 session 域中. * global session : WEB 项目中,应用在集群环境.如果没有集群环境那么相当于session |
global session图解
代码演示
## 【1】思考
单例、多例他们分别在什么场景中使用?他们有什么区别?
spring默认单例,不需要修改,不要随意定义成员变量。
多例:资源共用
## 【2】目标
1、掌握scope的单例、多例的配置
2、掌握单例和多例的区别
## 步骤:
1、改造ClientController多次获得对象
2、装配bean到spring的IOC容器中,修改bean标签中scope的作用域
3、观察不同作用域下获得的对象内存地址是否一致
改造ClientController
/**
* @Description:测试
*/
public class ClientController {
@Test
public void saveAccount() {
/**
* Spring-IOC容器:ApplicationContext
* 构建方式:通过ClassPathXmlApplicationContext加载配置文件
* 使用bean:getBean
*/
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml");
AccountDao accountDaoA = (AccountDao) applicationContext.getBean("accountDao");
AccountDao accountDaoB = (AccountDao) applicationContext.getBean("accountDao");
System.out.println("accountDaoA的内存地址:"+accountDaoA.hashCode());
System.out.println("accountDaoB的内存地址:"+accountDaoB.hashCode());
}
}
Bean【默认:singleton】
使用bean标签在bean.xml中装配accountDao的scope=“singleton”
<?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">
<!--创建AccountDaoImpl-->
<bean id="accountDao" class="com.example.spring.dao.impl.AccountDaoImpl" scope="singleton"></bean>
<!--创建AccountServicImpl-->
<bean id="accountServic" class="com.example.spring.service.impl.AccountServicImpl"></bean>
</beans>
singleton运行结果
bean【多例:prototype】
使用bean标签在bean.xml中装配accountDao的scope=“prototype”
<?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">
<bean id="accountDao" class="com.example.spring.dao.impl.AccountDaoImpl" scope="prototype"></bean>
<!--创建AccountServicImpl-->
<bean id="accountServic" class="com.example.spring.service.impl.AccountServicImpl"></bean>
</beans>
prototype运行结果
bean作用域小结
# 1、单例和多里创建方式、内存地址
【singleton单例】:所有请求只创建一个对象,内存地址相同
【prototype多例】:每次请求都创建新的对象,内存地址不同
# 2、为什么使用单例?
节省内存、CPU的开销,加快对象访问速度
# 3、为什么使用多例?
如果你给controller中定义很多的属性,那么单例肯定会出现竞争访问,
不要在controller层中定义成员变量(dao、service注入的bean)
当web层的对象是有状态的时候 使用多例,防止并发情况下的互相干扰
# 4、单例、多例的场景
单例===》spring中的Dao,Service,controller都是单例的
多例====》struts2的Action是多实例
4、bean标签生命周期
# sevlet的生命周期
1.被创建:执行init方法,只执行一次
--默认情况下,第一次被访问时,Servlet被创建,然后执行init方法;
--可以配置执行Servlet的创建时机;
2.提供服务:执行service的doGet、doPost方法,执行多次
3.被销毁:当Servlet服务器正常关闭时,执行destroy方法,只执行一次
spring-IOC中不同作用域中bean的生命周期
作用范围 | 生命周期 | |
---|---|---|
单例scope=“singleton” | 所有请求只创建一次对象 | 出生:应用加载,创建容器,对象就被创建 活着:只要容器在,对象一直活着。 死亡:应用卸载,销毁容器,对象就被销毁 |
多例scope=“prototype” | 每次请求都创建对象 | 出生:应用加载,创建容器,对象使用创建 活着:只要容器在,对象一直活着。 死亡:对象长时间不用,被垃圾回收器回收 |
生命周期方法相关标签属性
init-method #指定类中的初始化方法名称
destroy-method #指定类中销毁方法名称
代码演示
步骤:
1、创建LifecycBeanServic类
2、装配LifecycBeanServic
3、创建测试类
4、观察默认单例下生命周期
5、观察多例下生命周期
LifecycleService类
/**
* @Description:生命周期测试服务
*/
public class LifecycleService {
public LifecycleService() {
System.out.println("LifecycleService构造");
}
public void init(){
System.out.println("LifecycleService初始化");
}
public void doJob(){
System.out.println("LifecycleService工作中");
}
public void destroy(){
System.out.println("LifecycleService销毁");
}
}
单例模式下生命周期
配置bean.xml,装配bean并且设置问单例:
<?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">
<bean id="lifecycBeanServic" class="com.example.spring.service.LifecycBeanServic"
scope="singleton" init-method="init" destroy-method="destory"></bean>
</beans>
创建ClientController
/**
* @Description:客户端
*/
public class ClientContrller {
/**
* ApplicationContext:spring-IOC容器
* ClassPathXmlApplicationContext:容器实现类,加载配置文件
* applicationContext.getBean:获得容器中的bean对象
*/
@Test
public void createAccount(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml");
System.out.println("applicationContext初始化完成");
LifecycleService lifecycleService = applicationContext.getBean("lifecycleService", LifecycleService.class);
lifecycleService.doJob();
System.out.println("applicationContext容器关闭");
((ClassPathXmlApplicationContext) applicationContext).close();
}
}
多例模式下生命周期
将配置文件中的单例修改为多例
<?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">
<bean id="lifecycBeanServic" class="com.example.spring.service.LifecycBeanServic"
scope="prototype" init-method="init" destroy-method="destory"></bean>
</beans>
再次执行方法发现,LifecycleBean被延迟加载了,
并且只执行了初始化方法-init,没有执行销毁方法destory。
bean生命周期小结
# 单例对象:scope="singleton"
一个应用只有一个对象的实例。它的作用范围就是整个应用。
生命周期:
对象出生:当应用加载,创建容器时,对象就被创建了。
对象活着:只要容器在,对象一直活着。
对象死亡:当应用卸载,销毁容器时,对象就被销毁了。
# 多例对象:scope="prototype"
每次访问对象时,都会重新创建对象实例。
生命周期:
对象出生:当使用对象时,创建新的对象实例(getBean)。
对象活着:只要对象在使用中,就一直活着。
对象死亡:当对象长时间不用时,被垃圾回收器回收。
# 生命周期方法:
init-method:指定类中的初始化方法名称
destroy-method:指定类中销毁方法名称
5、bean的实例化方式
bean的实例化方式有以下3种:
- bean缺省构造函数创建
- 静态factory方法创建
- 实例化factory方法创建(通过非常发非静态方法创建)
1)缺省构造函数方式
配置方式
<!--空的构造方法实例化-->
<bean id="account" class="com.example.spring.pojo.Account"></bean>
注意事项
缺省构造函数实例化Bean的方式是Spring中默认的实例化方式;
被实例化的Bean中必须有无参构造;
2)静态工厂方法方式
步骤一:创建静态工厂
/**
* @Description:静态工厂
*/
public class StaticFactory {
public static Account createAccount(){
System.out.println("静态工厂构建!");
return new Account();
}
}
步骤二:配置静态工厂
<!--静态工厂实例化-->
<bean id="accountStatic" class="com.example.spring.factory.StaticFactory" factory-method="createAccount"></bean>
3)实例工厂方法方式
步骤一:创建实例工厂
/**
* @Description:实例化工厂
*/
public class InstanceFactory {
public Account createAccount(){
System.out.println("实例工厂构建!");
return new Account();
}
public User createUser(){
System.out.println("实例工厂构建!");
return new User();
}
}
步骤二:配置方式
<!--实例化工厂实例化-->
<bean id="instanceFactory" class="com.example.spring.factory.InstanceFactory"></bean>
<bean id="accountInstance" factory-bean="instanceFactory" factory-method="createAccount"></bean>
bean实例化小结
#【缺省构造函数方式】
说明:
在默认情况下会根据默认缺省构造函数来创建类对象。如果bean中没有默认无参构造函数,将会创建失败。
场景:
当各个bean的业务逻辑相互比较独立时,或者与外界关联较少时可以使用
#【静态工厂方法方式】
说明:
使用工厂中的静态方法创建对象,并装配到 spring的IOC 容器中。
id 属性:指定 bean 的 id,用于从容器中获取
class 属性:指定静态工厂的全限定类名
factory-method 属性:指定生产对象的静态方法
场景:
统一管理各个bean的创建
各个bean在创建之前需要相同的初始化处理,则可用静态factory方法进行统一的处理
#【实例工厂方法方式】
说明:
使用工厂中的实例方法创建对象,并装配到容器中。
1、先把实例工厂做为一个bean装配到 spring容器中。
2、然后再引用工厂bean 来调用里面的非静态方法来获取bean并装配到spring的IOC容器中。
factory-bean 属性:用于指定实例工厂 bean 的 id。
factory-method 属性:用于指定实例工厂中创建对象的方法
场景:
1.实例factory方法也作为业务bean控制,可以用于集成其他框架的bean创建管理方法,
2.能够使bean和factory的角色互换
6、bean标签配置小结
#1、bean标签的作用:把自己的类的对象的创建交给Spring管理
#2、基本配置:
id:IOC工厂中bean实例的唯一标识
class:实现类的全限定路径
name:别名
#3、bean的作用域:
单例:默认,IOC工厂创建后,立即创建bean的实例对象(bean只会被实例化一次)
多例:scope="prototype" 每次从工厂中获取bean的时候,都会创建一个新的对象返回
#4、bean的生命周期:
单例:
创建:IOC工厂创建后,立即创建bean的实例对象
初始化:对象创建完成之后立刻调用
工作...................
销毁:IOC工厂卸载,单例bean销毁
多例:
出生:应用加载,创建容器,对象使用创建<br/>
活着:只要容器在,对象一直活着。<br/>
死亡:对象长时间不用,被垃圾回收器回收
#5、bean实例化的3种方式:获取对象
bean缺省构造函数创建
静态factory方法创建
实例化factory方法创建
六 、spring之依赖注入DI【重点】
1、DI是什么
DI依赖注入:
Dependency Injection(简称DI注入)。
它是spring框架核心 ioc容器,
bean属性值赋值的具体方案
在上面,我们在程序编写时,通过控制反转,把对象的创建交给了 spring。
但是这种方式仅仅是降低了代码中的依赖关系,并不会完全消除依赖。
例如:我们的业务层仍会调用持久层的方法。
如图所示:
而所谓的依赖注入,可以先简单的理解为由spring框架来帮助我们以解耦的方式将dao传递到service中,
以解耦的方式给属性进行赋值,简称DI注入。
2、DI和IOC区别
-
IoC与DI是同一件事站在不同角度看待问题
在应用程序的角度看程序需要被动等待Spring提供资源(注入资源)是DI;
但是在Spring容器的角度看是,是将资源的创建权利做了翻转,且由容器提供数据,是IOC;
-
半杯水
半杯水:乐观的人会庆幸还有半杯水,而悲观的人是恼怒还有半杯水;
3、DI的方式和数据类型
Spring中的依赖注入:
注入的方式有三种:
第一种:使用构造方法注入
要求:必须有对应参数列表的构造函数
第二种:使用set方法注入(XML开发主流)
要求:提供被注入对象的set方法(不需要get方法)
第三种:使用注解注入(第二天会学)
注入的数据类型有三类:
第一类:基本类型和String
第二类:其他bean类型
要求:其他bean指的是在spring的配置文件中定义过的bean,或者是用注解注释过的类。
第三类:复杂类型(集合类型)
Array: 数组
List:集合
Map:集合
Properties:属性集
构造方式:
默认:使用无参数构造方法,创建对象
set方式:
property 指定属性
name:按属性名
ref:指定注入bean的Id
构造函数:
constructor-arg:构造函数
name:按属性名
index:按下标注
type:按类型
1)set方法注入
格式
使用类中属性的set方法,给属性赋值。
注意,赋值的操作不是我们硬编码的,而是通过配置的方式,让spring框架来为我们注入。
要求:
1、bean中必须提供属性的set方法
2、bean标签中通过proprety标签注入属性
步骤:
1、为属性提供set方法
2、修改bean.xml的property注入
<property name="属性名" value="值"></property>
<property name="属性名(bean)" ref="引入id名"></property>
代码演示
修改AccountServicImpl
提供属性的set方法
/**
* @Description:账户服务实现类
*/
public class AccountServicImpl implements AccountServic {
AccountDao accountDao ;
@Override
public void createAccount() {
accountDao.createAccount();
}
/**
* @Description 提供set方法
*/
public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}
}
修改bean.xml
<!--
bean:实例化对象
id:bean的唯一标示
class:实现类的全路径(反射使用)
细节:默认使用无参数构造函数实例化
-->
<bean id="accountDao" class="com.example.spring.dao.impl.AccountDaoImpl">
</bean>
<bean id="accountService" class="com.example.spring.service.impl.AccountServiceImpl">
<property name="accountDao" ref="accountDao"></property>
</bean>
ClientController测试
/**
* @Description:调用层
*/
public class ClientController {
@Test
public void createAccountTest(){
//加载bean.xml
ApplicationContext applicationContext =
new ClassPathXmlApplicationContext("classpath:bean.xml");
//获取accountDao accountDao实例化的bean
AccountService accountService = (AccountService) applicationContext.getBean("accountService");
//执行
accountService.createAccount();
}
}
2)构造函数注入
格式
使用类中的构造函数,给成员变量赋值。
注意,赋值的操作不是我们硬编码的,而是通过配置的方式,让spring框架来为我们注入。
要求:
1、bean对象需要创建有参数的构造方法
2、在配置文件中通过constructor-arg标签注入属性
<constructor-arg name="属性名" value="值"></constructor-arg>
<constructor-arg name="属性名(bean)" ref="引入id"></constructor-arg>
代码演示
修改AccountServicImpl
添加构造函数
/**
* @Description:账户服务实现
*/
public class AccountServicImpl implements AccountServic {
AccountDao accountDao ;
/**
* @Description 构造函数
*/
public AccountServicImpl(AccountDao accountDao) {
this.accountDao = accountDao;
}
@Override
public void createAccount() {
accountDao.createAccount();
}
}
修改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
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="accountDao" class="com.heima.spring.dao.impl.AccountDaoImpl"></bean>
<!--创建accountServic使用构造函数-->
<bean id="accountServic" class="com.heima.spring.service.impl.AccountServicImpl">
<constructor-arg name="accountDao" ref="accountDao"></constructor-arg>
</bean>
</beans>
ClientController测试
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* @Description:调用层
*/
public class ClientController {
@Test
public void createAccountTest(){
//加载配置文件
ApplicationContext applicationContext =
new ClassPathXmlApplicationContext("classpath:bean.xml");
//获得bean
AccountServic accountServic = (AccountServic) applicationContext.getBean("accountServic");
//创建账户
accountServic.createAccount();
}
}
3、依赖注入的简单配置【了解】
简单名称空间注入只是set方法注入和构造方法注入的简化方式,其本质是相同的
P名称空间注入,就是set方法注入。其本质在于简化配置,
空间名:xmlns:p="http://www.springframework.org/schema/p
c名称空间注入,就是构造函数注入。其本质在于简化配置,
空间名: xmlns:c="http://www.springframework.org/schema/c"
1)P标签方式(set方法)
p名称空间注入,就是set方法注入。其本质在于简化配置,
bean.xml中添加空间名:
xmlns:p="http://www.springframework.org/schema/p"
修改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"
---------------------------------------------------
xmlns:p="http://www.springframework.org/schema/p"
---------------------------------------------------
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--
bean:实例化对象
id:bean的唯一标示
class:实现类的全路径(反射使用)
细节:默认使用无参数构造函数实例化
-->
<bean id="accountDao" class="com.heima.spring.dao.impl.AccountDaoImpl"> </bean>
<bean id="accountService" class="com.heima.spring.service.impl.AccountServiceImpl" p:accountDao-ref="accountDao"></bean>
</beans>
ClientController测试
2)C标签方式(构造函数)
c名称空间注入,就是构造函数注入。其本质在于简化配置,
bean.xml中添加空间名:
xmlns:c="http://www.springframework.org/schema/c"
修改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"
--------------------------------------------------------
xmlns:c="http://www.springframework.org/schema/c"
--------------------------------------------------------
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--
bean:实例化对象
id:bean的唯一标示
class:实现类的全路径(反射使用)
细节:默认使用无参数构造函数实例化
-->
<bean id="accountDao" class="com.heima.spring.dao.impl.AccountDaoImpl"></bean></bean>
<bean
id="accountService" class="com.heima.spring.service.impl.AccountServiceImpl"
c:accountDao-ref="accountDao"></bean>
</beans>
ClientController测试
4、复杂类型的注入
我们知道了自定对象,及基础对象的注入方式,那么数组、List、Set、Map、Properties是怎么注入的呢?
给类中的复杂的属性注入数据,比如集合或者数组,
我们这里介绍注入数组、List、Set、Map、Properties。
使用set方法注入集合属性:
array:一般用来设置数组
list:一般用来设置list集合
map:一般用来设置map集合
props:一般用来设置properties
代码演示
创建Account实体类
package com.example.spring.pojo;
import java.util.*;
/**
* @Description:账户实体类
*/
public class Account {
//账户编号
private String Id;
//账户所有者
private String accountName;
//账户余额
private Float money;
private String[] myStrs;
private List<String> myList;
private Set<String> mySet;
private Map<String, String> myMap;
private Properties myProps;
public Account() {
}
public String getId() {
return Id;
}
public void setId(String id) {
Id = id;
}
public String getAccountName() {
return accountName;
}
public void setAccountName(String accountName) {
this.accountName = accountName;
}
public Float getMoney() {
return money;
}
public void setMoney(Float money) {
this.money = money;
}
public String[] getMyStrs() {
return myStrs;
}
public void setMyStrs(String[] myStrs) {
this.myStrs = myStrs;
}
public List<String> getMyList() {
return myList;
}
public void setMyList(List<String> myList) {
this.myList = myList;
}
public Set<String> getMySet() {
return mySet;
}
public void setMySet(Set<String> mySet) {
this.mySet = mySet;
}
public Map<String, String> getMyMap() {
return myMap;
}
public void setMyMap(Map<String, String> myMap) {
this.myMap = myMap;
}
public Properties getMyProps() {
return myProps;
}
public void setMyProps(Properties myProps) {
this.myProps = myProps;
}
@Override
public String toString() {
return "Account{" +
"Id='" + Id + '\'' +
", accountName='" + accountName + '\'' +
", money=" + money +
", myStrs=" + Arrays.toString(myStrs) +
", myList=" + myList +
", mySet=" + mySet +
", myMap=" + myMap +
", myProps=" + myProps +
'}';
}
}
编写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
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="account" class="com.heima.spring.pojo.Account">
<!--set方法注入基本类型属性:-->
<property name="id" value="1111"></property>
<property name="accountName" value="小王"></property>
<property name="money" value="2000"></property>
<!--
注入集合属性:
使用set方法注入集合属性:
array:一般用来设置数组
list:一般用来设置list集合
map:一般用来设置map集合
props:一般用来设置properties
-->
<property name="myStrs">
<array>
<value>AAA</value>
<value>BBB</value>
<value>CCC</value>
</array>
</property>
<property name="myList">
<list>
<value>AAA</value>
<value>BBB</value>
<value>CCC</value>
</list>
</property>
<property name="mySet">
<set>
<value>AAA</value>
<value>BBB</value>
<value>CCC</value>
</set>
</property>
<property name="myMap">
<map>
<entry key="name1" value="AAA"></entry>
<entry key="name2" value="BBB"></entry>
<entry key="name3" value="CCC"></entry>
</map>
</property>
<property name="myProps">
<props>
<prop key="name1">AAA</prop>
<prop key="name2">BBB</prop>
<prop key="name3">CCC</prop>
</props>
</property>
</bean>
</beans>
controller测试
package com.example.spring.controller;
import com.example.spring.pojo.Account;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* @Description:调用层
*/
public class ClientController {
@Test
public void createAccountTest(){
//加载配置文件
ApplicationContext applicationContext =
new ClassPathXmlApplicationContext("classpath:bean.xml");
//获得bean
Account account = (Account) applicationContext.getBean("account");
//打印结果
System.out.println("account的对象信息"+account.toString());
}
}
总结
java中的耦合,如何解耦:
耦合: 程序代码之间的依赖关系
解耦合:
工厂 + 反射 + 配置文件
配置文件: 存放被需要创建的类的全限定名
工厂: 解析配置文件,根据配置文件中的配置创建bean对象
1.解析配置文件,获取配置文件中配置的类全限定名
2.根据配置的全限定名创建对象的bean对象
思考:
工厂可以根据配置文件创建bean对象,那么工厂创建的bean对象是单实例还是多实例的?
创建单实例:
将创建的bean对象存放到一个map集合中,我们管这个集合叫做bean对象容器;
创建多实例:
工厂创建的多实例对象属于每一个线程,不会往容器中存放;
解耦:
java中的耦合: 程序代码之间的依赖关系
解耦: 解开程序在编译期代码之间的依赖
对象 对象名称 = new 对象(); // 存在依赖
Class.forName("类的全限定名"); // 存在硬编码
工厂 + 配置文件 + 反射
=================================================
Spring框架:
轻量级框架: 学习成本低,执行效率高,Spring为我们的javaEE企业级应用提供了全方位的解决方案。
web: 控制层
SpringMVC
service: 业务层
service层可以使用Spring提供了AOP完成事务的控制
dao: 持久层
Spring提供了JDBCTemplate封装jdbc
SPring的两大核心:
IOC: 控制反转 ★
反转的是对象的创建权.
之前我们使用对象时,是主动出击创建对象(new 对象())
控制反转后,对象的创建权交个了Spring,由Spring帮我们创建对象,
当我们使用对象时,找Spring的IOC容器获取对象即可,IOC容器本质上就是一个Map集合。
AOP: 面向切面编程
方法增强,在不改变原代码的基础上对象方法进行增强。(无侵入式)
底层使用的是动态代理
SPring的IOC入门案例:
1.导入Spring的jar包 spring-context
2.编写配置文件
在配置文件中配置需要Spring帮我们创建的类
3.使用Spring的API,解析配置文件,获取ApplicationContext对象
调用应用上下文对象的API从IOC容器中获取bean对象
API:
ApplicationContext: 应用上下文对象,接口
ClassPathXmlApplicationContext★: 解析类路径下的配置文件
FileSystemXmlApplicationContext: 解析系统路径下的配置文件
AnnotationConfigApplicationContext: 解析类上的注解
立即加载的接口:
在解析完配置文件后,会立即创建bean对象,将bean存放到IOC容器中
BeanFactory: 顶层接口
默认使用延迟加载的形式创建对象
Spring的IOC-xml方式:
xml文件:
创建bean对象:
// 方式1: 使用类的无参构造
<bean id="唯一标识" class="类的全限定名"></bean>
// 方式2: 调用工厂的静态方法创建
<bean id="..." class="工厂的全限定名" factory-method="静态方法名">
// 方式3: 调用工厂的非静态方法
// 3.1 创建工厂对象
<bean id="factoryId" class="工厂类的全限定名"></bean>
// 3.2 调用非静态方法执行
<bean id="唯一标识" factory-bean="factoryId"
factory-method="非静态方法名"></bean>
bean对象的作用范围:
scope: 设置作用范围
singleton: 单实例对象(默认)
prototype: 多实例对象
<bean id="唯一标识" class="类的全限定名" scope=".."></bean>
bean对象的生命周期:
单实例:
创建: ioc容器创建,bean对象就创建(xml文件解析完毕后)
销毁: applicationContext对象关闭
多实例:
创建: 当调用getBean方法时创建
销毁: 等待GC回收
属性:
init-method: 设置初始化方法
destory-method: 设置销毁方法
<bean id="唯一标识" class="类的全限定名" scope=".."></bean>
DI: 依赖注入
注入方式:
方式1: 有参构造
方式2: set方法注入 ★
方式3: 注解 ★
注入的数据类型:
基本类型和String
bean对象
复杂类型:
数组
list
map
properties
Spring-IOC : 注解方式
半xml半注解:
在xml文件中开启组件扫描
相关的注解:
创建Bean对象的注解:
@Component
@Controller
@Service
@Repository