Spring框架的概述和入门案例
- spring框架的概述:【了解即可】
- spring是什么:spring是分层的JavaSE/EE应用的full-stack的轻量级开源框架,以IOC(控制反转)和AOP(面向切面编程),提供了表现层SpringMVC和持久层的springJDBC,及业务层事务管理等众多的企业级应用技术,还能整合开源世界众多著名的第三方框架和类库,逐渐成为使用最多的 Java EE 企业应用开源框架。
- spring的优势:
- 方便解耦,简化开发:通过的spring中的IoC核心容器,将对象之间的依赖关系交由Spring进行控制,避免硬编码造成的过度耦合,用户也不必再为单例模式类、属性文件解析等这些很底层的需求编写代码,可以更专注于上层的应用。
- AOP编程的支持:通过spring中的aop功能,方便的进行面向切面编程,使许多难以适用传统的oop思想实现的功能能够轻松的实现。
- 声明式事务的支持:可以从单调的事务管理的代码中解脱出来,通过声明式的方式对事务进行管理,提高开发的效率和质量。
- 方便集成其他的第三方框架:spring中降低了集成其他框架的难度,提供了对其他框架的支持。
- 降低了对JavaEEapi的使用难度:对常用的JavaEEAPI进行了简单的封装,如javaMail,JDBCTemplate,使用这些API的难度大大的降低。
- Spring框架的体系结构:
- Spring中的控制反转:
- 什么是程序的耦合和解耦:
- 程序之间的耦合性: 在软件工程中,程序之间的耦合就是对象之间的依赖性,对象之间耦合性越高,维护的成本就越高。因此,对象之间的设计应当使类和构件耦合之间最小(高内聚 和 低耦合)
- 解耦的两种思路:
- 创建对象的时候尽量不要使用new关键字,而是使用反射,通过读取配置文件的方式来获取要创建对象的全限定类名。例如:在使用jdbc的时候注册驱动使用的是反射的形式,而不是用DriverManager的register方法。从而降低程序之间的耦合性。
- 使用工厂模式来进行解耦:当服务器启动应用加载的时候,让一个类中的方法通过读取配置文件,将对象都创建出来并且存起来,在以后使用的时候,直接拿过来使用,而读取配置文件来创建对象的类就是工厂。如SqlSessionFactory 就是一个工厂类。
- Spring中的控制反转IoC:
- 控制反转IoC:在使用工厂类的时候创建多个对象,需要将对象存起来,且能将对象查询出来,这样就需要一个Map,spring中就是IOC核心容器,而使用new的方式来创建对象,是主动的方式;使用工厂模式获取对象时,跟工厂要,由工厂为我们查找或者创建对象。是被动的方式,这样就将对象创建的权利交给了框架中的核心容器,这就是控制反转。【注意】:控制反转不是面向对象的术语,而是框架的重要特征。
- 控制反转的作用:降低程序之间的耦合性,注意的是是降低耦合 不是完全的消除程序之间的耦合性是不能完全的消除的,从而在实际的开发过程中实现:在编译期不依赖,而是在程序的运行期依赖。
- 使用Spring中的IoC解决程序之间的耦合:
-
准备工作:创建一个Maven工程,编写三层架构的接口和实现类。
-
进行Maven 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>cn.itheima</groupId> <artifactId>springIoc</artifactId> <version>1.0-SNAPSHOT</version> <dependencies> <!-- 引入 spring框架的坐标 使用的是5.0.2版本--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.0.2.RELEASE</version> </dependency> </dependencies> </project>
-
进行Bean对象的管理:在Maven工程中的resources目录下创建一个
Bean.xml
文件,将对象的创建交给Spring框架来处理,进行Bean对象的配置:(使用的是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"> <!--把对象的创建交给spring来管理--> <bean id="accountService" class="com.itheima.service.impl.IAccountServiceImpl"></bean> <bean id="accountDao" class="com.itheima.dao.impl.AccountDaoImpl"></bean> </beans>
-
使用容器来创建对象的getBean方法来获取对象,执行相应的方法。常用的容器有三种:
ClassPathXmlApplicationContext
,FileSystemXmlApplicationContext
,AnnotationConfigApplicationContext
都实现了ApplicationContext接口。- xml配置:
- ClassPathXmlApplicationContext: 它是从类的根路径下加载配置文件,推荐使用的方式
- FileSystemXmlApplicationContext: 它是从磁盘路径上加载配置文件,配置文件能在磁盘中的任意位置(绝对路径)
- 注解配置:
- AnnotationConfigApplicationContext: 读取注解创建容器
- xml配置:
-
- Spring中基于xml配置实现IoC的细节:
- Spring中的工厂类的结构图
- BeanFactory 和 ApplicationContext的区别和联系:
- 联系:BeanFactory是Spring容器中的顶级接口, ApplicationContext是它的子接口。
- 区别:BeanFactory 和 ApplicationContext创建对象的时间点不一样。ApplicationContext:只要一读取配置文件,默认情况下就会创建对象。BeanFactory:什么使用什么时候创建对象。
- Bean.xml文件中的细节详解:
bean
标签:- 作用:用于配置让spring来创建对象,默认的情况下使用的是无参的构造函数来创建对象,如果没有无参的构造函数不能成功的创建对象。
- bean标签中常用的属性:
id
属性:对象在容器中的唯一标识,能够用来获取对象。class
属性 :指定的是要创建对象的全限定类名,默认的情况下使用的是无参的构造函数。scope
属性: 指定对象的作用范围,有五种取值(常用的是前两种):- singleton :默认值,单例的.
- prototype :多例的.
- request :WEB 项目中,Spring 创建一个 Bean 的对象,将对象存入到 request 域中.
- session :WEB 项目中,Spring 创建一个 Bean 的对象,将对象存入到 session 域中.
- global session :WEB 项目中,应用在 Portlet 环境(集群环境).如果没有 Portlet 环境那么globalSession 相当于 session.
init-method
:指定类中初始化方法名称。destroy-method
:指定类中销毁方法名称。
- bean对象的生命周期和作用范围:(Spring 中Bea对象的生命周期比较的复杂)
- 单例对象: scope=“singleton”
- 单例对象创建时机:使用的是立即加载
- 作用范围: 每个应用只有一个该对象的实例,它的作用范围就是整个应用
- 生命周期: 单例对象的创建与销毁 和 容器的创建与销毁时机一致
- 对象出生: 当应用加载,创建容器时,对象就被创建
- 对象活着: 只要容器存在,对象一直活着
- 对象死亡: 当应用卸载,销毁容器时,对象就被销毁
- 总结:单例对象的生命周期和容器的生命周期是一致的
- 多例对象: scope=“prototype”
- 多例对象的创建时机:使用的是延时加载
- 作用范围: 每次访问对象时,都会重新创建对象实例.
- 生命周期: 多例对象的创建与销毁时机不受容器控制
- 对象出生: 当使用对象时,创建新的对象实例
- 对象活着: 只要对象在使用中,就一直活着
- 对象死亡: 当对象长时间不用时,被 java 的垃圾回收器回收了
- 单例对象: scope=“singleton”
- Bean对象实例化的三种方式:
- 第一种方式:使用默认无参构造函数:如果 bean 中没有默认无参构造函数,将会创建失败 (在Spring的配置文件中使用bean标签配置id和class属性,且没有其他的属性)
<bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl"/>
- 第二种方式:使用Spring中的静态工厂的方法来创建对象:(使用的是某个类中的静态方法来创建对象,并将对象存入spring和容器中)
<!--factory-method 属性:指定生产对象的静态方法--> <bean id="accountService" class="com.itheima.factory.staticFactory" factory-method="getAccountService"></bean>
- 第三种方式:使用spring来管理实例工厂-使用实例工厂中的普通方法来创建对象。(先是将工厂的创建交给Spring来管理,然后使用工厂的bean来调用里面的方法,从而来创建对象)
<!--factory-bean 属性:用于指定实例工厂 bean 的 id。factory-method 属性:用于指定实例工厂中创建对象的方法。--> <bean id="instancFactory" class="com.itheima.factory.InstanceFactory"></bean> <bean id="accountService" factory-bean="instancFactory" factory-method="createAccountService"></bean>
- 第一种方式:使用默认无参构造函数:如果 bean 中没有默认无参构造函数,将会创建失败 (在Spring的配置文件中使用bean标签配置id和class属性,且没有其他的属性)
- Spring中的工厂类的结构图
- 什么是程序的耦合和解耦:
- Spring中的依赖注入:
- 什么是以依赖注入:依赖注入(Dependency Injection) Spring中IoC的作用是降低程序之间的耦合,那么依赖注入就是IoC的具体实现方式。依赖关系的管理是Spring框架来进行维护的,依赖关系的具体的维护方式就是依赖注入。
- 能够进行依赖注入的数据类型:三类
- 基本的数据类型 和 String类型
- 其他的bean类型:(在配置文件中或者是注解中配置过的bean 或者说是在spring容器中体现的类型)
- 复杂类型 或者说是 集合类型(前三种能互用 后两种能互用)
<property name="myStrings"> <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="mySet"> <set> <value>AAA</value> <value>BBB</value> <value>CCC</value> </set> </property> <property name="myMap"> <map> <!--两种写法 第一种的方式较为简单--> <entry key="testA" value="AAA"></entry> <entry key="testB"> <value>BBB</value> </entry> </map> </property> <property name="properties"> <props> <prop key="testA">AAA</prop> <prop key="testB">AAA</prop> </props> </property>
- 依赖注入的方式:三种
- 第一种使用构造器注入: 使用的标签是
constructor-arg
- 标签出现的位置是:bean标签的内部
- constructor-arg标签的属性: 五种
- index:用于指定要注入的数据给构造函数中,指定索引位置的参数赋值,索引的位置是从0开始的。(能独立的使用但是 需要记住所有的参数的顺序和类型)
- name:用于指定给构造函数中指定名称的参数赋值 常用名称 主要是直接
- type: 指定要注入的数据的类型 该数据类型也是构造函数中某个或者是某参数的类型 但是如果参数中有多个数据类型一致的话不行
以上的三个用于指定给构造函数那个参数赋值 - ref: 用于指定其他的bean类型 它指的就是在spring的ioc核心容器中出现过的bean对象
- value: 用于提供基本数据类型和String类型的数据
- 构造器注入的优缺点:
-
优点:在获取bean对象时,注入数据是必要的操作,否则对象无法创建成功。 有些对象来创建时,有些属性是必须传入的,这样的方式就非常的适用。
-
缺点:改变了bean对象的实例化方式,在我们创建对象的时候 如果用不要这些数据 也必须提供。(这样的方式不常用)
<bean id="accountService" class="com.itheima.service.impl.IAccountServiceImpl"> <constructor-arg name="name" value="泰斯特"></constructor-arg> <constructor-arg name="age" value="18"></constructor-arg> <constructor-arg name="birthday" ref="now"></constructor-arg> </bean> <!--配置bean对象 配置一个日期对象使用constructor-arg标签中的ref属性来进行关联配置了全限定类名 spring就会使用反射 将对象进行创建 然后将对象存入spring核心容器中,使用id将对象拿出来--> <bean id="now" class="java.util.Date"></bean>
-
- 第二种使用set方法注入:使用的标签是
property
- 标签出现的位置:同样是在bean标签的内部
- property标签的属性:三种
- name:用于指定注入时调用的set方法的名称 找到的是属性的值 不是成员变量的值
- ref: 用于指定其他的bean类型 它指的就是在spring的ioc核心容器中出现过的bean对象
- value: 用于提供基本数据类型和String类型的数据
- set方法注入的优缺点:
- 优点:创建对象没有明确的限制,可以使用默认的构造函数
- 缺点: 如果某个成员必须有值,使用set方式无法保证一定注入。获取对象时set方法可能没有执行。
<bean id="accountService2" class="com.itheima.service.impl.IAccountServiceImpl2" > <property name="name" value="test"></property> <property name="birthday" ref="now1"></property> <property name="age" value="18"></property> </bean> <bean id="now1" class="java.util.Date"></bean>
- 第三种方法:使用注解注入【需要注意的一点是使用注解配置和使用XML文件进行配置实现的功能是一致的,都是为了降低程序之间的耦合性,只是配置的形式不同。且不同的公司对于注解形式和xml的形式的偏好程度不同,两种方式都要会使用。】
- 导入外部文件使用的标签:
<context:property-placeholder location="classpath:jdbc.properties"/> <!--或者是--> <bean id="propertyPlaceholderConfigurer" class="org.springframework,beans.factory.config.PropertyPlaceholderConfigurer"> <property name="locations"> <list> <value>jdbc.properties<value/> </list> </property> </bean>
- 第一种使用构造器注入: 使用的标签是
- 基于注解的IOC的详解:
- 环境的搭建:
- 导入相应的jar包,在bean.xml文件中,配置spring创建容器时扫描的包,注意的是这时使用的约束和使用xml进行配置的不同,需要一个名称为context名称空间和约束。
context:component-scan
标签 会扫描指定包下和子包的注解<?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:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- 告知spring在创建容器的时候要扫描的包,配置所需要的标签不是在beans的约束中,而是一个名称为 context名称空间和约束。context:component-scan 会扫描指定包下和子包的注解 --> <context:component-scan base-package="com.itheima"></context:component-scan> </beans>
- 导入相应的jar包,在bean.xml文件中,配置spring创建容器时扫描的包,注意的是这时使用的约束和使用xml进行配置的不同,需要一个名称为context名称空间和约束。
- 注解IOC常用的注解:
- 分类:四种
- 用于创建对象的:作用就是和在xml文件中编写一个bean标签实现的功能是一致的,但是只是添加了注解不能正常的运行 需要告知要扫描的包,在bean.xml中进行配置
- @Component:
- 作用:就是通过反射来创建对象,然后将对象存入Spring的IoC容器中。
- 属性:
String value() default "";
用于指定bean对象的id,不写value的值,默认的就是当前类名,且首字母小写,但是类名的前两个字母都是大写,返回的Bean名称也是大写,即类名是IUserDao,bean名也是IUserDao。
- @Repository @Service @Controller :
- 作用:这三个注解的作用和@Component注解的作用是一致的,是spring框架为我们提供的明确使用的三层使用的注解,使三层对象更加的清晰
- 作用的位置:
- @Repository:一般使用在持久层(dao层)
- @Service:一般使用在业务层(service层)
- @Controller: 一般使用于表现层(controller层)
- 属性:
String value() default "";
属性和@Component是一样的
- @Component:
- 用于数据注入的:作用就是和在xml文件中编写一个property标签实现的功能是一致的
- @Autowired
- 作用:就是自动的按照类型注入,将自动在代码上下文中找到和其匹配(默认是类型匹配)的Bean,并自动注入到相应的地方去。
- 使用的位置:
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
- 和注解配置的不同: 进行注入的时候set方法不是必须的
- 如果ioc容器中没有任何的bean类型和要注入的变量类型匹配, 就会报错。
- @Qualifier
- 作用:按照类注入的基础上再按照名称注入,它在给类成员注入的时候不能单独的使用。 但是在给方法参数使用的使用可以单独的使用。
- 使用的位置:
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE})
- 属性:value 用于指定要注入的bean的id 在给类成员注入的时候需要依赖于Autowired使用
- @Resource(在容器中有多个类型相同的bean时,需@Autowired和@Qualifier组合使用才行,为了简化使用@Resource注解)
- 作用: 直接按照bean的id进行注入, 且可以独立使用
- 属性: name属性 注意的是不是value 用于指定bean的id
- 注意:不是Spring框架中提供的注解,而是
javax.annotation.Resource;
以上的三种注解只能注入指定的bean类型的数据,而基本类型和String类型是不能使用上述注解来实现集合类型和导入的jar包中的类型的注入目前还是只能通过xml来实现(以后会讲纯注解的方式)
- @Value
- 作用:用于注入基本的数据类型和String类型,一般是将配置文件中的数据进行注入
- 属性:
String value();
用于执行数据的值。 它能使用spel 也就是spring中的el表达式。SpEl的写法: 就是${表达式}或者是#{表达式}
- @Autowired
- 用于改变作用范围的 :作用就是在一个bean标签使用一个scope标签实现的功能是一致的
- @Scope
- 作用:用于指定bean的作用范围
- 属性:看着像是两个其实就只有一个属性
@AliasFor("scopeName") String value() default ""; @AliasFor("value") String scopeName() default "";
- value指定范围的取值 常用的取值有:singleton prototype 不写默认的情况下是单例的
- 作用的位置:
@Target({ElementType.TYPE, ElementType.METHOD})
- @Scope
- 和生命周期相关的:作用就是在一个bean标签使用一个init-method 和使用一个destroy-method标签是一致的。
- @PreDestroy
- 作用:用于指定销毁方法
- @PostConsturct
- 作用:用于指定初始化方法
- @PreDestroy
- 用于创建对象的:作用就是和在xml文件中编写一个bean标签实现的功能是一致的,但是只是添加了注解不能正常的运行 需要告知要扫描的包,在bean.xml中进行配置
- 分类:四种
- 纯注解方式实现:
- 注解方式存在的问题:使用注解的形式还是离不开bean.xml配置文件,实现纯注解的方式就是,将bean.xml文件中的内容也通过注解实现。如开启注解扫描、配置数据源的信息等。
- 注意:选择哪种配置的原则是简化开发和配置方便,而非追求某种技术。不要因小失大(使用框架的目的是为了简化开发 不是炫技)
- 纯注解方式需要的注解:
- @Configuration:
- 作用:指定的是当前类是一个spring的配置类,在创建容器时会从该类上加载注解。获取容器时需要使用AnnotationApplicationContext(有@Configuration 注解的类.class) 而不是使用ClassPathXmlApplicationContext实现类进行容器的创建。
- 属性: value 指定配置类的字节码
- 作用的位置:类上
- @ComponentScan:
- 作用:用于指定 spring 在初始化容器时要扫描的包。作用和在 spring 的 xml 配置文件中的:
<context:component-scan base-package="com.itheima"/>
是一样的。 - 属性:basePackages 别名是 value:用于指定要扫描的包。和该注解中的 value 属性作用一样。
- 作用的位置:类上
- 作用:用于指定 spring 在初始化容器时要扫描的包。作用和在 spring 的 xml 配置文件中的:
- @Bean
- 作用:表明使用此方法创建一个对象,并且放入 spring 容器。
- 属性:name:给当前@Bean 注解方法创建的对象指定一个名称(即 bean 的 id)
- 作用的位置:方法上
- @PropertySource
- 作用: 用于加载.properties 文件中的配置。例如我们配置数据源时,可以把连接数据库的信息写到properties 配置文件中,就可以使用此注解指定 properties 配置文件的位置。
- 属性:value[]:用于指定 properties 文件位置。如果是在类路径下,需要写上 classpath:
- 作用的位置:类上
- @Import
- 作用:用于导入其他配置类,在引入其他配置类时,可以不用再写@Configuration 注解。当然,写上也没问题。
- 属性:value[]:用于指定其他配置类的字节码。
- 作用的位置:类上
- @Configuration:
- 环境的搭建:
- Spring 整合 Junit
- 注意:当我们使用spring 5.x版本的时候,要求junit的jar必须是4.12及以上
- 步骤:
- 导入junit 的必备 jar 包 注意的是需要spring aop的支持
- 使用@RunWith 注解替换原有运行器
@RunWith(SpringJUnit4ClassRunner.class) public class XxxTest { }
- 使用@ContextConfiguration 指定 spring 配置文件的位置
- 属性:
- locations 属性:用于指定配置文件的位置。如果是类路径下,需要classpath:表明
- classes 属性:用于指定注解的类。当不使用 xml 配置时,需要用此属性指定注解类的位置。
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations= {"classpath:bean.xml"}) public class XxxTest { }
- 属性:
- 使用@Autowired 给测试类中的变量注入数据
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations= {"classpath:bean.xml"}) public class XxxTest { @Autowired private IAccountService as; }