Spring学习
Spring入门
spring简介
Spring是一个开源框架,Spring为简化企业级应用开发而生。 使用Spring可以使简单的 JavaBean实现以前只有EJB才能实现的功能。 Spring是一个IOC(DlI)和 AOP容器框架;
特点:
- 轻量级: Spring是非侵入性的–基于Spring开发的应用中的对象可以 不依赖于Spring 的API.
- 依赖注入(DI — dependency injection、Ioc)
- 面向切面编程(AOP — aspect oriented programming)
- 容器: Spring是一个容器,因为它包含并且管理应用对象的生命周期.
- 框架: Spring 实现了使用简单的组件配置组合成一个复杂的应用.在Spring中可以使用XML和Java 注解组合这些对象
- 一站式: 在IOC和 AOP的基础上可以整合各种企业应用的开源框架和优秀的第三方类库(实际上 Spring自身也提供了展现层的SpringMvc和持久层的Spring JDBC) .
Spring简单示例程序HelloWorld
程序的搭建:
- 引入Spring依赖包;
Maven库
选择5.3,18版本
配置文件:
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.18</version>
</dependency>
- 配置文件
配置依赖包:
在Maven项目的下的pom.xml中引入Spring的依赖
- 编写程序使用spring框架
构建一个HelloSpring实体类 包含Name.Addr
平常写法,不适用Spring的情况:
创建springconfig文件:
在resource下配置一个spring-1.xml配置文件,之后通过该配置文件创建我们需要的容器
package edu.etime.springdemo.demo1;
public class Test {
public static void main( String[] args) {
/*一般方法使用HeLLoSpring对象
1、new创建对象实例
2、调用get , set方法获取值或者赋值*/
HelloSpring helloSpring = new HelloSpring();
helloSpring.setName("张三");
helloSpring.setAddr("温江");
system.out.println(helloSpring.getName());
System.out.print1n(helloSpring.getAddr());
}
/*
使用spring容器:
1、创建spring容器
2、从容器中获取指定的bean
*/
//创建容器
ApplicationContext ctx = new ClassPathXm1ApplicationContext("spring-1.xm1");
//从容器中获取bean
HelloSpring hs = (HelloSpring) ctx.getBean("hellospring");
system.out.println(hs.getName()+"\t"+hs.getAddr());
}
IOC容器 & DI概述
概念
IOC(Inversion of Control):其思想是 反转资源获取的方向 .传统的资源查找方式要求组件向容器发起请求查找资源. 作为回应,容器适时的返回资源.而应用了IOC之后,则是 容器主动地将资源推送给它所管理的组件,组件所要做的仅是选择一种合适的方式来接受资源. 这种行为也被称为查找的被动形式
DI(Dependency Injection)—IOC的另一种表述方式:即组件以一些预先定义好的方式(例如: setter方法)接受来自如容器的资源注入.相对于IOC而言,这种表述更直接
IOC 与 DI 两者区别
IOC控制反转
DI依赖注入
bean的基本配置
基本配置
<bean id="hellospring" class="edu.etime.spring.HelloSpringTest">
<property name="name" value="Spring配置名"/>
<property name="addr" value="四川成都!"/>
</bean>
-
id 属性 :bean 的名称 ,在IOC容器中,bena的名称是唯一的.
hellospring
-
如果没有指定id属性,那么将会用class属性作为bean的名称
edu.etime.spring.HelloSpringTest
-
Class属性,类的全名称(包名 + 类名)
edu.etime.spring.HelloSpringTest
Spring容器
在Spring lOC容器读取 Bean配置创建Bean实例之前,必须对它进行实例化.只有在容器实例化后,才可以从lOC 容器里获取 Bean实例并使用.( 要获取 bean就必须要先实例化IOC容器,然后从容器中获取bean ) .
Spring 提供两种类型的IOC容器实现:
-
BeanFactory:IOC容器的基本实现;
-
ApplicationContext: 提供了更多的高级特性,是BeanFactory的子接口; (主要使用的实现容器方式)
ApplicationContext提供的实现类:
ClassPathXmlApplicationContext: 从类路径下加载配置文件。FileSystemXmIApplicationContext: 从文件系统中加载配置文件。
ConfigurableApplicationContext扩展于ApplicationContext,新增加两个主要方法: refresh() 和 close(), 让 ApplicationContext具有启动、刷新和关闭上下文的能力.
ApplicationContext在初始化上下文时就实例化所有单例的 Bean。(默认spirng._容器中的bean都是单例对象)。
WebApplicationContext是专门为wEB应用而准备的,它允许从相对于wEB根目录的路径中完成初始化工作.
ApplicationContext 与 ConfigurableApplicationContext的区别:
ConfigurableApplicationContext是ApplicationContext的子接口,增加了刷新和关闭方法,让IOC容器具备刷新和关闭功能.
从IOC容器中获取bean
两种方式获取Bean
- 通过Bean的id获取
- 通过Bean的Class类型获取(相同类型bean在ioc容器中不能存在多个)
//根据bean的id获取bean
HelloSpring hs = (HelloSpring) ctx.getBean("edu.etime.springdemo.demo1.HelloSpring")
//根据类型获取bean
//注意:相同类型的bean在IOC容器中不能存在多个
Hellospring hs1 = ctx.getBean(HelloSpring.class);
依赖注入方法
三种注入方式:
-
通过属性注入(通过setter方法注入)
-
通过构造方法注入
顺序不同的情况:
①通过index指定
②通过类型
③通过参数名字
- 通过工厂方法注入(静态工厂方法注入,实例工厂方法注入)
工厂方法注入一般来来说并不会去使用,大家可以自行搜索了解
工厂方法注入讲解示例
字面值
如果我们的值带有特殊字符:
那我们可以使用<![CDATA[<成都>]]>
这样的方式注入
引用其他bean (ref)
组成应用程序的bean经常需要相互写作以完成应用程序的功能.要使bean能够相互访问,就必须在bean配置文件中指定对bean的引用.
- 引入其他bean ref引用:
<l -- 引用其他的bean -->
<bean id="p1" class="edu.etime.springdemo.beans.Person">
<property name="name " value="张三"></property><! --通过属性来引用其他bean -->
<property name="car" ref="car4"></property>
</ bean>
<bean id="p2" class="edu.etime.springdemo.beans.Person">
<property name="name" value="张三"></property>
<! --通过属性来应用其他bean -->
<property name="car">
<ref bean="car3" /></property>
</ bean>
- 内部bean:
也可以在属性或构造器里包含 Bean的声明,这样的 Bean称为内部 Bean。当 Bean实例仅仅给一个特定的属性使用时,可以将其声明为内部 Bean。内部 Bean声明直接包含在或元素里,不需要设置任何id 或name 属性。 内部Bean不能使用在任何其他地方
<! --内部bean -->
<bean id="p3" class="edu.etime.springdemo. beans.Person">
<property name="name" value="张三" ></property>
<! --通过属性来应用其他bean -->
<property name="car">
<bean class="edu.etime. springdemo.beans.car">
<constructor-arg value=”大中国”
index="1 "></ constructor-arg>
<constructor-arg value=”红旗” index="o"></constructor-arg>
<constructor-arg value="40000" index="2"></constructor-arg>
</bean>
</property>
</bean>
注入NULL值
可以使用专用的<null />
元素标签为Bean的字符串或其他对象类型的属性注入null值
<property name="name ">
<null></null>
</property>
注入级联属性
<bean id="p2" class="edu.etime. springdemo.beans.Person">
<property name="name">
<null></null>
</property>
<! --通过属性来应用其他bean -->
<property name="car">
<ref bean="car3" />
</property>
<!--注入级联属性-->
<property name="car.price" value="40"></property>
</bean>
注意: Spring为级联属性赋值前必须先初始化对象,否则会出现异常.
<bean id="p3" class="edu.etime. springdemo.beans.Person">
<property name="name " value="张三"></property>
<! --通过属性来应用其他bean -->
<! -- <property name="car ">
<bean class="edu.etime. springdemo.beans.car">
<constructor-arg value="大中国" index="1"></constructor- arg>
<constructor- arg value="红旗"index="O"></constructor-arg>
<constructor- arg value="40000" index="2"></constructor-arg>
</bean>
</property> -->
<property name="car.price" value="44444"></property>
</bean>
如上所示:如果不先创建car这个属性,那么car.price就会出现异常
注入集合
注入List&Set
配置java.util.List类型的属性,需要指定标签,在标签里面包含一些元素,这些标签可以通过指定简单的常量值,通过指定对其他Bean的引用,通过指定内部Bean定义,通过指定空元素,甚至可以内嵌其他集合.
<bean id="th1" class= "edu.etime.springdemo.beans. TuHao">
<property name="name " value="上豪一号"></property>
<!--注入list集合-->
<property name="List">
<list>
<ref bean="car1"/>
<bean class="edu.etime.springdemo.beans.car">
<constructor-arg value="大中国" index="1"></constructor-arg>
<constructor-arg value="红旗" index="0"></constructor-arg>
<constructor-arg value="40000" index="2"></constructor-arg>
</bean>
</list>
</property>
</bean>
注入Map
<!--注入map -->
<bean id="th2" class="edu.etime.springdemo.beans.TuHao">
<property name= "name" value="上豪er号"></property>
<!-- 注入map集合-->
<property name= "map">
<map>
<entry key="car1" value-ref="car1"/>
<entry key="car2" value-ref="car2"/>
</map>
</property>
</bean>
Properties集合
使用定义 java.util.Properties,该标签使用多个作为子标签,每个标签必须定义key属性.
<! --注入properties -->
<bean id="datasource" class="edu.etime.springdemo. beans.Datasource">
<property name= "properties">
<props>
<prop key="driver">com.mysql.jdbc.Driver</prop>
<prop key="url ">mysql:jdbc//127.0.0.1: 3306/text</prop>
<prop key="username ">root</prop>
<prop key="password">123321234567</prop>
</props>
</property>
</bean>
Util& P标签
- util标签
eclipse引入
IDEA Maven 下的pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/maven-v4_0_0.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/spring-util.xsd">
util标签主要用于定义一些公用的集合,以供其他的bean来进行引用
<util:list id="list">
<ref bean="heLLo"/>
</util:list>
<util:map id="map">
</util:map>
<util:properties id="pro">
</util:properties>
- p标签
需要引入的命名空间
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/maven-v4_0_0.xsd
http://www.springframework.org/schema/p
http://www.springframework.org/schema/spring-p.xsd">
作用: 为了简化配置(主要就是简化属性注入的配置)
<bean id="car0" class="edu.etime.springdemo.beans.car"
p:brand="红旗飘飘" p:corp="China" p:price="9999999">
</bean>
自动装配
XML 配置里的Bean自动装配
Spring loc容器可以自动装配Bean.需要做的仅仅是在的 autowire 属性里指定自动装配的模式
byType (根据类型自动装配):若IoC容器中有多个与目标 Bean类型一致的 Bean.在这种情况下, Spring 将无法判定哪个Bean最合适该属性,所以不能执行自动装配.
byName (根据名称自动装配):必须将目标 Bean的名称和属性名设置的完全同.
constructor (通过构造器自动装配):当 Bean中存在多个构造器时,此种自动装配方式将会很复杂.不推荐使用
ByType根据类型自动装配
byType的Spring配置文件示例:
<bean id="car" class="edu.etime. springdemo2.beans.Car">
<property name="brand" value="红旗"></property>
<property name="corp" value="中国"></property><property name="price" value="599999"></property>
</bean>
<bean id="address" class="edu.etime.springdemo2.beans.Address ">
<property name="city" value="成都"></property>
<property name="street" value="玉林路"></property>
</bean>
<bean id="person" class="edu.etime.springdemo2.beans.Person"autowire="byType">
<property name= "name" value="张三"></property>
</bean>
实体类:
注意: 使用byType进行自动装配,需要I0C容器中的同类型的bean只能有一个。如果同类型的bean有多个,这是Spring将无法识别是哪一个bean。将无法自动状态。
ByName根据名称自动装配
byName的Spring配置文件示例:
<bean id= "car" class= "edu.etime.springdemo2.beans.Car">
<property name= "brand" value= "红旗"></property>
<property name= "corp" value= "中国"></property>
<property name= "price" value="599999"></property>
</bean>
<bean id= "address1" class= "edu.etime.springdemo2.beans.Address">
<property name= "city" value= "成都"></property>
<property name= "street”value= "玉林路"></property>
</bean>
<bean id= "address" class= "edu.etime.springdemo2.beans.Address ">
<property name= "city" value="北京"></property>
<property name= "street" value= "长安街"></property>
</bean>
<bean id= "person" class= "edu. etime.springdemo2.beans.Person"
autowire= "byName ">
<property name= "name”value= "张三"></property>
</bean>
byName: 根据在Person类中所定义的属性名称进行自动装配,这个时候,需要类中的属性名称和配置文件中的bean的id–致方可进行自动装配。如果名称不一致,不能进行装配,
那么该属性的值为Null
XML 配置里的Bean自动装配的缺点
在Bean配置文件里设置autowire属性进行自动装配将会装配Bean的所有属性.然
而,若只希望装配个别属性时,autowire属性就不够灵活了.
autowire属性 要么根据类型自动装配,要么根据名称自动装配,不能两者兼而有之.
一般情况下,在实际的项目中很少使用自动装配功能(配置文件中的自动装配),因为和
自动装配功能所带来的好处比起来,明确清晰的配置文档更有说服力一些
Bean之间的继承关系
知识点
-
Spring允许继承bean 的配置。
-
继承仅仅是指配置上的继承,并不意味着这两个bean之间存在继承关系。继承bean配置仅仅是为了复用其配置信息。
-
子Bean 也可以覆盖从父Bean继承过来的配置
-
父Bean可以作为配置模板,也可以作为Bean实例.若只想把父Bean作为模板,可以设置 的abstract属性为true, 这样Spring 将不会实例化这个Bean
-
并不是元素里的所有属性都会被继承.比如: autowire, abstract 等.
-
也可以忽略父Bean的class 属性,让子Bean指定自己的类,而共享相同的属性配置.但此时abstract 必须设为true
基础继承示例
<bean id= "address1" class= "edu.etime.springdemo2.beans.Address">
<property name= "city" value="成都"></property>
<property name= "street" value= "玉林路"></property>
</bean>
<bean id= "address2" class="edu.etime.springdemo2.beans.Address "
parent= "address1">
</bean>
子bean中覆盖父bean中的配置
<bean id= "address1" class="edu.etime.springdemo2.beans.Address">
<property name= "city" value= "成都" ></property>
<property name= "street" value="玉林路"></property>
</bean>
<bean id= "address2" class="edu.etime.springdemo2.beans.Address"
parent= "address1">
<property- name= "street" value= "林阴街"></property>
</bean>
abstract属性
<!--将address1设置abstract=true,这时,spring将不会实例化这个bean -->
<bean id= "address1" class= "edu.etime.springdemo2.beans.Address" abstract="true">
<property name= "city" value="成都"></property>
<property name= "street" value= "玉林路"></property>
</bean>
前置依赖depends-on
前置依赖 depends-on 不同与 ref 依赖。这两者都是表示对其他bean 的依赖,但是ref
常用的情况是这个bean作为当前bean的属性(依赖更直接)。
但是有时候依赖关系并不会这么明显,我们依赖的bean也许并不是我们当前bean 的
属性,比如当前bean GetConnection,我们需要初始化一些值,这些值的初始化是依赖于bean ConfigDataSource的,那么我们的bean GetConnection 肯定是依赖于ConfigDataSource的,但是ConfigDataSource并不是GetConnection的属性,这个时候用ref肯定是不合适的,就可以用depends-on
bean的作用域
在Spring中,可以在元素的scope属性里面设置 Bean的作用域
默认情况下,Spring只为每个在IOC容器里面声明的Bean创建一个唯一 一个实例,整个IOC容器范围内部都嫩共享该实例: 所有后续的getBean()调用和Bean引用都将返回这个唯一的Bean实例.该作用域被称为singleton, 它是所有Bean的默认作用域.
类别 | 说明 |
---|---|
singleton | 在SpringIOC容器中仅存在一个Bean实例,Bean以单实例的方式存在 |
prototype | 每次调用getBean()时都会返回一个新的实例 |
request | 每次HTTP请求都会创建一个新的Bean,该作用域仅适合于WebApplicationContext环境 |
session | 同一个HTTP Session共享一个Bean,不同的HTTPSession使用不同的Bean.该作用仅适合于WebApplicationContext环境 |
默认情况的配置文件:
<bean id= "address2" class="edu.etime.springdemo2.beans.Address"
parent= "address1" scope= "singleton">
<property name= "street" value= "林阴街"></property>
</bean>
singleton
- 在IOC容器中以单例的形式存在;
- Bean的实例在容器创建的时候就会创建;
prototype
- 每次请求返回不同的对象;
- bean 的创建,是在获取的时候再去创建bean 的实例;
使用外部配置文件
在配置文件里配置Bean时,有时需要在Bean的配置里混入系统部署的细节信息(例如:文件路径,数据源配置信息等).而这些部署细节实际上需要和Bean 配置相分离
Spring提供了一个 PropertyPlaceholderConfigurer 的BeanFactory 后置处理器,这个处理器允许用户将Bean配置的部分内容外移到属性文件中.可以在Bean配置文件里使用形式${var} 的变量,PropertyPlaceholderConfigurer 从属性文件里加载属性,并使用这些属性来替换变量.
ICO 容器中Bean 的生命周期方法
bean的生命周期:
bean的整个生命周期:
- 调用构造方法创建实例
- 设置属性
- postProcessBeforelnitialization (前置处理器)
- 调用init-method ---- bean已经准备好,可以进行使用了。
- postProcessAfterlnitialization (后置处理器)
- 容器关闭的时候调用: destory- method
生命周期说明
SpringI0C容器可以管理Bean的生命周期,Spring允许在Bean生命周期的特定点执
行定制的任务.
SpringIOC容器对Bean的生命周期进行管理的过程:
-
通过构造器或工厂方法创建Bean实例
-
为Bean 的属性设置值和对其他Bean的引用
-
调用Bean的初始化方法
-
Bean 可以使用了
-
当容器关闭时,调用Bean 的销毁方法
在Bean的声明里设置init-method 和destroy-method 属性,为Bean指定初始化和
销毁方法.
生命周期示例
Bean生命周期
两个主要的生命周期方法:
① init-method 初始化方法
② destory-method 销毁方法
Bean 的整个生命周期其
- 调用构造方法创建实例
- 设置属性
- 调用init-method ----- bean已经准备好了,可以进行使用了
- 容器关闭的时候调用: destory-method
后置处理器
Bean后置处理器允许在调用初始化方法前后对Bean进行额外的处理.
Bean 后置处理器对IOC容器里的所有Bean 实例逐一处理, 而非单-实例.其典型应用是:检查Bean属性的正确性或根据特定的标准更改Bean的属性.
对Bean后置处理器而言,需要实现BeanPostProcessor接口.在初始化方法被调用前后,Spring将把每个Bean 实例分别传递给.上述接口的以下两个方法:
postProcessBeforeInitialization
postProcessAfterInitialization
Spring的注解
在classpath中扫描组件
租价你扫面(component scanning) : spring能够从classpath下自动扫描,侦测和实例化具有特定注解的组件
特定组件包括:
@Component: 基本注解,标识了一个受Spring 管理的组件
@Repository: 标识持久层组件
@Service: 标识服务层(业务层)组件
@Controller: 标识表现层组件
上面4中注解的作用是一样的,都是在告诉spring,请把这个类放入到IOC容器中。而这几个注解的区别仅仅只是用于区别不同组件在程序中的作用。
对于扫描到的组件, Spring有默认的命名策略:使用非限定类名,第-一个字母小写.也可以在注解中通过value属性值标识组件的名称。(如果没有指定扫描到的组件的名称,那么默认使用类名作为组件的名称,第 一个字母小写)
自动扫描步骤:
- 在配置文件中开启自动扫描component-scan,并指定扫描的包
- 需要在要加入到IOC容器的类上面加上注解: @Component,@Controller,@Service,@Repository ----->创建容器的时候,扫描指定包下面的带有以上注解的类.
- 扫描到IOC容器中的Bean,id默认为非限定类名,首字母小写.例如:Car — car
- 关于id,还可以使用注解的value属性来指定其id,例如@Component(“car1”) || @Component(value = car1")
面试常问的问题:
区别:
- 本质上没有区别
扫描示例
- dao层和service层程序实例
自动装配
@Autowired
- 按照类型进行匹配;
- 如果在IOC容器中,有多个相同类型的bean,那么会采用byName的方式进行匹配。
- 如果在IOC容器中找不到匹配的bean,那么默认会抛异常。可以使用@Autowired(required =false)来设置bean是否是必须要注入。
@Autowired 通过byType方式进行自动装配 @Resource 通过byName方式进行自动装配,可以理解是xml的setter方式注入方式
-
组件装配
context:component-scan 元素还会自动注册AutowiredAnnotationBeanPostProcessor实例,该实例可以自动装配具有@Autowired 和@Resource 、@Inject 注解的属性。
说明:上面三个注解的作用几乎相同的。一般使用@autowired注解 -
autowired 注解
@Autowired注解自动装配具有兼容类型的单个Bean 属性。(首先使用类型进行匹配,如果类型的bean有多个,那么再采用名称进行匹配,如果名称匹配不上,那么就会抛出异常)
构造器,普通字段(即使是非public),一切具有参数的方法都可以应用@Autowired注解
默认情况下,所有使用@Autowired 注解的属性都需要被设置.当Spring 找不到匹配的Bean 装配属性时,会抛出异常,若某一属性允许不被设置,可以设置@Autowired 注解的required 属性为false
默认情况下,当I0C容器里存在多个类型兼容的Bean时,通过类型的自动装配将无法工作。如果ioc容器中包含多个兼容类型的bean,那么@AutoWired注解还会根据变量名与bean的名称进行自动装配。
@Autowired注解也可以应用在数组类型的属性.上,此时Spring将会把所有匹配的Bean进行自动装配
@Autowired注解也可以应用在集合属性上,此时Spring 读取该集合的类型信息,然后自动装配所有与之兼容的Bean.
@Autowired注解用在java.util.Map. 上时, 若该Map的键值为String, 那么Spring将自动装配与之Map值类型兼容的Bean,此时Bean的名称作为键值
- 最常用的自动装配示例