Spring学习笔记-day1
第一章Spring概述
1.1spring是什么
1.2spring的发展历程
1.3spring的优势
方便解耦,简化开发
AOP编程的支持
声明式事务的支持
方便程序的测试
方便集成各种优秀框架
降低JavaEE API的使用难度
spring源码时经典的学习范例
1.4spring的体系架构
第二章 Spring IOC
2.1模拟Spring IOC过程
解耦的思想:
第一步:通过读取配置文件来获取要创建的对象全限定名。
第二步:使用反射来创建对象,避免使用new关键字。
模拟业务场景中的三层架构
controller ——service——dao
首先使用new关键字来创建要依赖的对象:
dao层封装对资源的操作:
package com.jzt.dao;
public interface IHelloDao {
public void sayHello();
}
package com.jzt.dao.impl;
import com.jzt.dao.IHelloDao;
public class HelloDaoImpl implements IHelloDao {
public void sayHello() {
System.out.println("hello spring init!");
}
}
service层封装具体的业务,依赖dao层
package com.jzt.service;
public interface IHelloService {
public void sayHello();
}
package com.jzt.service.impl;
import com.jzt.dao.IHelloDao;
import com.jzt.dao.impl.HelloDaoImpl;
import com.jzt.service.IHelloService;
public class HelloServiceImpl implements IHelloService {
//依赖dao时,需要开发人员new具体的依赖类
private IHelloDao helloDao = new HelloDaoImpl();
public void sayHello() {
helloDao.sayHello();
}
}
利用test来模拟controller
package com.jzt.test;
import com.jzt.factory.HelloFactory;
import com.jzt.service.IHelloService;
import com.jzt.service.impl.HelloServiceImpl;
/**
* 模拟spring IOC的流程
*/
public class HelloTest {
public static void main(String[] args) {
//一般情况下,开发人员需要使用一个对象资源时,都是通过手动new的方式来获取这个资源的使用
IHelloService iHelloService = new HelloServiceImpl();
iHelloService.sayHello();
}
}
以上是我们开发人员在不使用spring框架时,需要自己手动创建依赖对象,然后调用依赖对象的方法进行操作。
下面我们模拟Spring IOC的过程:
1)创建配置bean的配置文件beans.properties:
helloService=com.jzt.service.impl.HelloServiceImpl
helloDao=com.jzt.dao.impl.HelloDaoImpl
2)使用工厂来创建需要依赖的bean对象:
package com.jzt.factory;
import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
public class HelloFactory {
private static Map<String, Object> beans;
private static Properties props;
static {
try {
//首先加载配置文件
props = new Properties();
InputStream in = HelloFactory.class.getClassLoader().getResourceAsStream("beans.properties");
props.load(in);
beans = new HashMap<String, Object>();
//加载配置文件中配置的bean的相关信息,这里主要是类的全限定名
Enumeration keys = props.keys();
while(keys.hasMoreElements()){
String key = keys.nextElement().toString();
String beanPath = props.getProperty(key);
//通过反射根据类的全路径名来获取对象的实例
Object bean = Class.forName(beanPath).newInstance();
//将获取到的对象实例放入容器中
beans.put(key, bean);
}
} catch (Exception e) {
System.out.println("初始化失败");
e.printStackTrace();
}
}
//提供一个公共的获取对象实例的方法
public static Object getInstance(String beanName){
return beans.get(beanName);
}
}
3)在使用时,通过调用工厂的getInstance()公共方法,来获取需要的bean
package com.jzt.test;
import com.jzt.factory.HelloFactory;
import com.jzt.service.IHelloService;
import com.jzt.service.impl.HelloServiceImpl;
/**
* 模拟spring IOC的流程
*/
public class HelloTest {
public static void main(String[] args) {
//一般情况下,开发人员需要使用一个对象资源时,都是通过手动new的方式来获取这个资源的使用
// IHelloService iHelloService = new HelloServiceImpl();
// iHelloService.sayHello();
//spring的ioc是通过工厂+反射的方式来将资源加载到spring容器中供开发人员使用
//下面我们通过工厂的方式来获取对象资源
IHelloService helloService = (IHelloService) HelloFactory.getInstance("helloService");
helloService.sayHello();
}
}
package com.jzt.service.impl;
import com.jzt.dao.IHelloDao;
import com.jzt.dao.impl.HelloDaoImpl;
import com.jzt.factory.HelloFactory;
import com.jzt.service.IHelloService;
public class HelloServiceImpl implements IHelloService {
// private IHelloDao helloDao = new HelloDaoImpl();
private IHelloDao helloDao = (IHelloDao) HelloFactory.getInstance("helloDao");
public void sayHello() {
helloDao.sayHello();
}
}
这样子,我们就可以不用自己手动的创建bean,把创建bean对象的工作交给factory工厂来做。而这种思想就是spring的IOC思想。
2.2Spring IOC的概述
控制反转(Inversion of Control,IOC):把创建对象的权利交给框架,是框架的重要特征。
作用:
削减计算机程序的耦合。(消除我们代码中的依赖关系)
2.3使用Spring IOC解决程序间的耦合
2.3.1准备Spring IOC的简单实现
也可以通过maven导入依赖:
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.2.RELEASE</version>
</dependency>
</dependencies>
简单使用:
1)生成beans.xml文件
<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-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<bean id="helloService" class="com.jzt.service.impl.HelloServiceImpl"/>
<bean id="helloDao" class="com.jzt.dao.impl.HelloDaoImpl"/>
</beans>
2)使用spring容器来获取需要的对象
package com.jzt.test;
import com.jzt.dao.impl.HelloDaoImpl;
import com.jzt.factory.HelloFactory;
import com.jzt.service.IHelloService;
import com.jzt.service.impl.HelloServiceImpl;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**8
* spring IOC
*/
public class HelloTest {
public static <HelloDao> void main(String[] args) {
//获取spring容器
ApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml");
IHelloService helloService = (IHelloService) ac.getBean("helloService");
HelloDao helloDao = (HelloDao) ac.getBean("helloDao", HelloDaoImpl.class);
System.out.println(helloService);
System.out.println(helloDao);
}
}
可以正常获取到bean对象了:
显然,通过spring框架能够很方便的获取到需要的依赖对象,省去了开发人员大量的创建new对象的过程。同时很大程度上解耦。
2.3.2ApplicationContext的三个常用实现类
- ClasspathXmlApplicationContext:可以加载类路径下的配置文件,要求配置文件必须放在类路径下(classpath)。 开发中更常用!
- FileSystemXmlApplicationContext:可以加载磁盘下任意路径下的配置文件(前提是要有文件操作权限)。
- AnnotationConfigApplicationContext:用于读取注解创建容器。。。
// ApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml");
ApplicationContext ac = new FileSystemXmlApplicationContext("C:\\Users\\sj\\Desktop\\beans.xml");
2.2.3核心容器的两个接口
- ApplicationContext:它在构建核心容器时,创建对象采用的策略是立即加载的方式。也就是说,只要一读取完配置文件马上就创建配置文件中配置的对象。(饿汉式)
- BeanFactory:他在构建核心容器时,创建对象采用的策略是延迟加载的方式。也就是说,什么时候获取对象,就什么时候才真正的创建对象。(懒汉式)
2.2.4创建bean对象的方式
创建bean的三种方式:
(1)使用默认构造方法创建
在spring配置文件中使用标签,配以id和class属性之后,且没有其他属性和标签时,采用的就是默认构造方法创建bean对象。
<!-- 第一种方式:使用默认构造方法
在spring配置文件中使用<bean>标签,配以id和class属性之后,且没有其他属性和标签时,采用的就是默认构造方法创建bean对象。
-->
<bean id="helloService" class="com.jzt.service.impl.HelloServiceImpl"/>
**此时如果该类中没有默认无参构造方法时,则对象将无法创建。
public class HelloServiceImpl implements IHelloService {
private String name;
//这里没有显式地创建默认构造方法,使用有参构造
public HelloServiceImpl(String name) {
this.name = name;
}
public void sayHello() {
}
}
(2)使用普通工厂中的方法创建bean对象(或者是使用某个类中的方法来创建对象,并存入spring容器中)
首先创建工厂类,以及生成bean的方法:
package com.jzt.factory;
import com.jzt.service.impl.HelloServiceImpl;
/**
* 模拟一个工厂,该类可能在jar保重,我们无法修改源码来创建默认构造方法
*/
public class InstanceFactory {
public HelloServiceImpl getInstance(){
return new HelloServiceImpl();
}
}
配置bean:
<!-- 第二种种方式:使用普通工厂中的方法创建bean对象(或者是使用某个类中的方法来创建对象,并存入spring容器中)
-->
<bean id="instanceFactory" class="com.jzt.factory.InstanceFactory"/>
<bean id="helloService" factory-bean="instanceFactory" factory-method="getInstance"/>
(3)使用静态工厂中的静态方法来创建bean对象(或者是使用某个类中的静态方法来创建对象,并存入spring容器中)
package com.jzt.factory;
import com.jzt.service.impl.HelloServiceImpl;
/**
* 模拟一个工厂,该类可能在jar保重,我们无法修改源码来创建默认构造方法
*/
public class InstanceFactory {
//使用普通方法
// public HelloServiceImpl getInstance(){
// return new HelloServiceImpl();
// }
//使用静态方法
public static HelloServiceImpl getInstance(){
return new HelloServiceImpl();
}
}
配置bean:
<!-- 第三种方式:使用静态工厂中的静态方法来创建bean对象(或者是使用某个类中的静态方法来创建对象,并存入spring容器中)
-->
<bean id="instanceFactory" class="com.jzt.factory.InstanceFactory" factory-method="getInstance"/>
2.2.5bean的作用范围
通过标签中的scope属性来设置bean对象的作用范围:
<!-- 通过<bean>标签中的scope属性来设置bean对象的作用范围-->
<bean id="helloService" class="com.jzt.service.impl.HelloServiceImpl" scope="prototype"/>
- singleton:单例,默认的;
- prototype:多例;
- request:作用于web应用的请求范围;
- session:作用于web应用的会话范围;
- global-session:作用于集群环境中的会话范围(全局会话范围),再不是集群化解下,他就是session。
2.2.6bean对象的生命周期
(1)单例对象:
- 出生:当容器创建时,对象出生;
- 活着:只要容器在,对象就存活;
- 销毁:容器销毁,对象消亡;
总结:单例对象的生命周期和容器相同;
(2)多例对象:
- 出生:当我们使用对象时,spring框架会为我们创建对象;
- 活着:对象只要被使用,就一直活着;
- 销毁:对象长时间不使用,没有其它对象引用时,由GC回收;
2.3spring的依赖注入
依赖注入:Dependency Injection
IOC的作用:降低程序间的耦合(依赖关系)
依赖关系的管理:以后都交给spring来管理;
在当前类中需要其他类对象,由spring为我们提供,我们只需要在配置文件中说明;
依赖关系的维护:就称之为依赖注入;
依赖注入:
- 能注入的数据:
- 基本类型和String
- 其他bean类型(在配置文件中或者注解中配置过的bean)
- 复杂类型和/集合类型
- 注入的三种方式:
- 使用构造方法注入;
- 使用set注入;
- 使用注解提供;
2.3.1使用构造函数注入
构造函数注入:
使用的标签:constractor-arg;
标签出现的位置:标签的内部;
标签中的属性:
- type:用于指定要注入的数据的数据类型,该数据类型也是构造函数某个活着某些参数 的类型;
- index:用于指定要注入的数据给构造函数中指定索引位置的参数赋值,索引的位置从0开始;
- name:用于指定给构造函数中指定名称的参数赋值;**(常用)**
- value:用于提供基本类型和String类型的数据;
- ref:用于指定其他的bean类型数据。它指的就是在spring的ioc核心容器中出现过的bean对象。
前三个用于指定给构造函数中哪个参数赋值=======
优点:
在获取bean对象时,注入数据是必须操作,否则无法创建对象;
弊端:
改变类bean对象的实例化方式,使我们在创建对象时,如果用不到这些数据,也必须提供。
给bean添加属性参数:
package com.jzt.service.impl;
import com.jzt.dao.IHelloDao;
import com.jzt.dao.impl.HelloDaoImpl;
import com.jzt.service.IHelloService;
import java.util.Date;
public class HelloServiceImpl implements IHelloService {
private String name;
private Integer age;
private Date date;
public HelloServiceImpl(String name, Integer age, Date date) {
this.name = name;
this.age = age;
this.date = date;
}
@Override
public String toString() {
return "HelloServiceImpl{" +
"name='" + name + '\'' +
", age=" + age +
", date=" + date +
'}';
}
public void sayHello() {
}
}
配置:
<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-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 通过构造函数注入属性值 -->
<bean id="helloService" class="com.jzt.service.impl.HelloServiceImpl">
<constructor-arg name="name" value="zhangsan"></constructor-arg>
<constructor-arg name="age" value="18"></constructor-arg>
<constructor-arg name="date" ref="now"></constructor-arg>
</bean>
<bean id="now" class="java.util.Date"></bean>
</beans>
2.3.2使用set方法注入
set方法注入:
使用的标签:property
标签出现的位置:标签的内部;
标签中的属性:
- name:用于指定调用时set方法名称;
- value:用于提供基本类型和String类型的数据;
- ref:用于指定其他的bean类型数据。它指的就是在spring的ioc核心容器中出现过的bean对象。
优点:
创建对象时没有明确的限制,可以使用默认构造函数;
弊端:
如果某个成员必须有值,则获取对象是某个set方法没有执行。
配置:
<bean id="now" class="java.util.Date"></bean>
<!-- 通过set方法注入 -->
<bean id="helloService2" class="com.jzt.service.impl.HelloServiceImpl">
<property name="name" value="testname"></property>
<property name="age" value="18"></property>
<property name="date" ref="now"></property>
</bean>
调用:
//获取spring容器
ApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml");
IHelloService helloService = (IHelloService) ac.getBean("helloService2");
System.out.println(helloService);
2.3.3通过注解注入(暂时略过,后面补充)
2.3.4复杂类型注入
复杂类型的注入/集合类型的注入:
- 用于给list(Array、List、Set)类型集合注入的标签:、、
- 用于给map(Map、Props)类型集合注入的标签:
含有复杂类型的对象:
package com.jzt.service.impl;
import com.jzt.service.IHelloService;
import java.util.*;
public class HelloServiceImpl2 implements IHelloService {
private String[] array;
private List list;
private Set set;
private Map map;
private Properties props;
public String[] getArray() {
return array;
}
public void setArray(String[] array) {
this.array = array;
}
public List getList() {
return list;
}
public void setList(List list) {
this.list = list;
}
public Set getSet() {
return set;
}
public void setSet(Set set) {
this.set = set;
}
public Map getMap() {
return map;
}
public void setMap(Map map) {
this.map = map;
}
public Properties getProps() {
return props;
}
public void setProps(Properties props) {
this.props = props;
}
@Override
public String toString() {
return "HelloServiceImpl2{" +
"array=" + Arrays.toString(array) +
", list=" + list +
", set=" + set +
", map=" + map +
", props=" + props +
'}';
}
public void sayHello() {
}
}
配置:
<!-- 复杂类型注入 -->
<bean id="helloService3" class="com.jzt.service.impl.HelloServiceImpl2">
<property name="array">
<array>
<value>AAA</value>
<value>BBB</value>
<value>CCC</value>
</array>
</property>
<property name="list">
<list>
<value>AAA</value>
<value>BBB</value>
<value>CCC</value>
</list>
</property>
<property name="set">
<set>
<value>AAA</value>
<value>BBB</value>
<value>CCC</value>
</set>
</property>
<property name="map">
<map>
<entry key="t1" value="AAA"></entry>
<entry key="t2" value="BBB"></entry>
<entry key="t3" value="CCC"></entry>
</map>
</property>
<property name="props">
<props>
<prop key="t1">AAA</prop>
<prop key="t2">BBB</prop>
<prop key="t3">CCC</prop>
</props>
</property>
</bean>
测试:
//获取spring容器
ApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml");
IHelloService helloService = (IHelloService) ac.getBean("helloService3");
System.out.println(helloService);
结果: