Spring是什么:
Spring是分层的javaEE轻量级开源框架,以IOC(控制反转)和AOP(面向切面编程)为内核的框架。
Spring的优势:
方便解耦,简化开发。
AOP编程的支持。
声明事务的支持。
方便程序测试。
方便集成各种优秀框架,
降低javaEEAPI的使用难度。
IOC的概念和作用:
IOC:控制反转,降低程序之间的耦合,解除代码中的依赖关系。是一个map结构。
之前我们获取对象采用的是new,是主动的。用配置文件以后获取对象是从工厂要,由工厂查找或者创建对象,是被动的,这种被动接收方式获取对象的思想就是控制反转,是spring框架核心之一。
程序的耦合:
耦合:程序之间的依赖关系,包括类之间的依赖,方法间的依赖。
解耦:降低程序之间的依赖关系。
在实际开发中要做到:编译期不依赖,运行时才依赖。
解耦的思路:
1 使用反射来创建对象,而避免使用new关键字。
2 通过读取配置文件来获取要创建的对象权限权限定类名。
Bean:在计算机英语中是有可反复使用组件的含义。
JavaBean:用java语言编写的可反复使用的组件。它就是创建我们service和Dao对象的。
方式:
1 需要一个配置文件 来配置我们的service和Dao。
配置内容:唯一标识=权限定类名(key=value)
2 通过配置文件中的配置内容来反射创建对象。
配置文件可以是xml格式也可以是properties,(在main---resources目录下创建XXX.properties或者XXX.xml ,XXX可以是叫任意,此处我叫它bean)
spring的搭建
1 建立maven项目,在pom.xml中写导入坐标下如下代码
org.springframework
spring-context
5.0.2.RELEASE
2 在src----main----resources下创建bean.xml(不一定叫bean 只要不是中文叫什么都行)在里面添加约束。
3 把对象的创建交给Spring来管理
4 在表现层获取spring的核心容器,并根据id获取对象。
public static void main(String[] args){
//1 获取核心容器
ApplicationContext ac = new ClassPathXmlApplicationContext("beann.xml");
//2根据id获取bean对象
IAccountService as =(IAccountService)ac.getBean("accountService");
IAccountDao adao =ac.getBean("accountDao",IAccountDao.class);
System.out.println(as);
System.out.println(adao);
}
//打印消息为:com.itheima.serivce.impl.AccoutnServiceImpl@5e5792a0
// com.itheima.dao.impl.AccountDaoImpl@26653222
ApplicationContext的三个常用实现类:
ClassPathXMLApplicationContext(常用):它可以加载类路径下的配置文件 要求配置文件必须在类路径下。不在的话加载不了,也就是说加载不了就创建不了容器。
FileSystemXmlApplicationContext:它可以加载磁盘任意路径下的配置文件(必须有访问权限)
AnnotationConfigApplicationContext:读取注解创建容器。
核心容器的两个接口引发的问题:
ApplicationContext:(用的比较多)(单例模式适用)它在构建核心容器时,创建对象采取的策略是采用立即加载方式 也就是说只要读取完配置文件马上创建配置文件中的配置对象。
BeanFactory:(多列模式适用)它在构建核心容器的时候 创建对象采取的策略是延迟加载方式,也就是说id什么时候获取对象了 才什么时候真正的创建对象。
spring对bean的管理细节
1 创建bean的三种方式
2 bean对象的作用范围
3 bean对象的声明周期
1 创建bean的三种方式
第一种:使用默认构造函数创建。在spring的配置文件中使用bean标签,配合id和class属性之后,没有其他标签时,采取的就是默认构造函数创建bean对象,此时如果类中没有默认构造函数,则对象无法创建。
第二种:使用普通工厂中的方法创建对象(使用某个类中的方法创建对象并存入spring容器)
模拟一个实例工厂,创建业务层实现类 此工厂创建对象,必须现有工厂实例对象,再调用方法
public class InstanceFactory {
public IAccountService createAccountService(){
return new AccountServiceImpl();
}
}
第三种:使用工厂中的静态方法创建对象(使用某个类中静态方法创建,并存入spring容器)
/**
* 模拟一个静态工厂,创建业务层实现类
*/
public class StaticFactory {
public static IAccountService createAccountService(){
return new AccountServiceImpl();
}
}
2 bean对象的作用范围
bean标签的scope属性,作用是指定bean的作用范围。
取值:(标粗常用)
singleton:单例(默认值)
prototype:多例
request:作用于web应用的请求范围
session:作用于web应用的会话范围
global-session:作用于集群环境会话范围(全局会话范围),当不是集群环境时 它就是session。
3 bean对象的声明周期
单例对象:scope="singleton"
一个应用只有一个对象的实例。
它的作用范围就是整个引用。
生命周期:
对象出生:当应用加载,创建容器时,对象就被创建了。
对象活着:只要容器在,对象一直活着。
对象死亡:当应用卸载,销毁容器时,对象就被销毁了。
多例对象:scope="prototype"
每次访问对象时,都会重新创建对象实例。
生命周期:
对象出生:当使用对象时,创建新的对象实例。
对象活着:只要对象在使用中,就一直活着。
对象死亡:当对象长时间不用时,被 java 的垃圾回收器回收了。
spring的依赖注入
依赖注入:Dependency Injection。它是 spring 框架核心 ioc 的具体实现。 我们的程序在编写时,通过控制反转,把对象的创建交给了 spring,但是代码中不可能出现没有依赖的情况。 ioc 解耦只是降低他们的依赖关系,但不会消除。例如:我们的业务层仍会调用持久层的方法。 那这种业务层和持久层的依赖关系,在使用 spring 之后,就让 spring 来维护了。 简单的说,就是坐等框架把持久层对象传入业务层,而不用我们自己去获取。
依赖注入的方式有三种:
1使用构造函数提供
2 使用set方法提供
3 使用注解提供
构造函数注入 (此种方法不适合经常变化的数据)
顾名思义,就是使用类中的构造函数,给成员变量赋值。
优势:在获取bean对象时,注入数据是必须的操作,否则对象无法创建成功。
弊端:改变了bean对象的实例化方式,使我们在创建对象时,如果我们用不到这些数据也必须提供。
注意,赋值的操作不是我们自己做的,而是通过配置的方式,让 spring 框架来为我们注入。
具体代码如下
public class AccountServiceImpl implements IAccountService {
private String name;
private Integer age;
private Date birthday;
public AccountServiceImpl(String name, Integer age, Date birthday) {
this.name = name;
this.age = age;
this.birthday = birthday;
}
@Override
public void saveAccount() {
System.out.println(name+","+age+","+birthday);
}
}
使用构造函数的方式,给 service 中的属性传值
要求: 类中需要提供一个对应参数列表的构造函数。
涉及的标签:
属性:
index
:指定参数在构造函数参数列表的索引位置
type
:指定参数在构造函数中的数据类型
name
:指定参数在构造函数中的名称 用这个找给谁赋值 (常用)
上面三个都是找给谁赋值,下面两个指的是赋什么值的
value
:它能赋的值是基本数据类型和 String 类型
ref
:它能赋的值是其他 bean 类型,也就是说,必须得是在配置文件中配置过的 bean
set 方法注入 (常用)
顾名思义,就是在类中提供需要注入成员的 set 方法。
优势:创建对象时 没有明确限制,可以使用默认构造函数。
弊端:如果有某个成员必须有值,则获取对象时set方法没有执行。
具体代码如下:
public class AccountServiceImpl implements IAccountService {
private String name;
private Integer age;
private Date birthday;
public void setName(String name) {
this.name = name;
}
public void setAge(Integer age) {
this.age = age;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
@Override
public void saveAccount() {
System.out.println(name+","+age+","+birthday);
}
}
通过配置文件给 bean 中的属性传值:
使用 set 方法的方式
涉及的标签:
属性:
name:找的是类中 set 方法的名称
ref:给属性赋值是其他 bean 类型的
value:给属性赋值是基本数据类型和 string 类型的 实际开发中,此种方式用的较多。
注入集合属性
就是给类中的集合成员传值,它用的也是set方法注入的方式,只不过变量的数据类型都是集合。 我们这里介绍注入数组,List,Set,Map,Properties。具体代码如下:
public class AccountServiceImpl implements IAccountService {
private String[] myStrs;
private List myList;
private Set mySet;
private Map myMap;
private Properties myProps;
public void setMyStrs(String[] myStrs) {
this.myStrs = myStrs;
}
public void setMyList(List myList) {
this.myList = myList;
}
public void setMySet(Set mySet) {
this.mySet = mySet;
}
public void setMyMap(Map myMap) {
this.myMap = myMap;
}
public void setMyProps(Properties myProps) {
this.myProps = myProps;
}
@Override
public void saveAccount() {
System.out.println(Arrays.toString(myStrs));
System.out.println(myList);
System.out.println(mySet);
System.out.println(myMap);
System.out.println(myProps);
}
}
注入集合数据 List 结构的: array,list,set
Map 结构的 map,entry,props,prop
AAA
BBB
CCC
AAA
BBB
CCC
AAA
BBB
CCC
aaa
bbb