#Spring概述
Spring是分层的、JavaSE/EE一站式(full-stack)、轻量级开源框架。以IoC(Inverse Of Control:反转控制)和AOP(Aspect Oriented Programming:面向切面编程)为内核,提供了表现层Spring MVC和持久层Spring JDBC以及业务层事务管理等众多的企业级应用技术,还能整合开源世界众多著名的第三方框架和类库,逐渐成为使用最多的Java EE企业应用开源框架。
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 andDevelopment(2002)
阐述了J2EE使用EJB开发设计的优点及解决方案
Expert One-to-One J2EE Developmentwithout EJB(2004)
阐述了J2EE开发不使用EJB的解决方式(Spring雏形)
Spring的优势
spring是为了解决javaEE实际问题
1.方便解耦,简化开发
通过Spring提供的IoC容器,可以将对象间的依赖关系交由Spring进行控制,避免硬编码所造成的过度程序耦合。用户也不必再为单例模式类、属性文件解析等这些很底层的需求编写代码,可以更专注于上层的应用。
2.AOP编程的支持
通过Spring的AOP功能,方便进行面向切面的编程,许多不容易用传统OOP(面向对象)实现的功能可以通过AOP轻松应付。
3. 声明式事务的支持
可以将我们从单调烦闷的事务管理代码中解脱出来,通过声明式方式灵活的进行事务的管理,提高开发效率和质量。
4. 方便程序的测试
可以用非容器依赖的编程方式进行几乎所有的测试工作,测试不再是昂贵的操作,而是随手可做的事情。
5. 方便集成各种优秀框架
Spring可以降低各种框架的使用难度,提供了对各种优秀框架Struts、Hibernate、Hessian(远程通讯,类似于webService)、Quartz(定时任务)等的直接支持。
6. 降低JavaEE API的使用难度
Spring对JavaEE API(如JDBC、JavaMail、远程调用等)进行了薄薄的封装层,使这些API的使用难度大为降低。
Spring的体系结构
核心容器(Core Container) 包括Core、Beans、Context、EL模块。
1:Core和Beans模块提供了Spring最基础的功能,提供IoC和依赖注入特性。这里的基础概念是BeanFactory,它提供对Factory模式的经典实现来消除对程序性单例模式的需要,并真正地允许你从程序逻辑中分离出依赖关系和配置。
2:Context模块基于Core和Beans来构建,它提供了用一种框架风格的方式来访问对象,有些像JNDI注册表。Context封装包继承了beans包的功能,还增加了国际化(I18N),事件传播,资源装载,以及透明创建上下文,例如通过servlet容器,以及对大量JavaEE特性的支持,如EJB、JMX。核心接口是ApplicationContext。
3:Expression Language,表达式语言模块,提供了在运行期间查询和操作对象图的强大能力。支持访问和修改属性值,方法调用,支持访问及修改数组、容器和索引器,命名变量,支持算数和逻辑运算,支持从Spring 容器获取Bean,它也支持列表投影、选择和一般的列表聚合等。
数据访问/集成部分(Data Access/Integration)
1:JDBC模块,提供对JDBC的抽象,它可消除冗长的JDBC编码和解析数据库厂商特有的错误代码。
2:ORM模块,提供了常用的”对象/关系”映射APIs的集成层。 其中包括JPA、JDO、Hibernate 和 iBatis 。利用ORM封装包,可以混合使用所有Spring提供的特性进行”对象/关系”映射,如简单声明性 事务管理 。
3:OXM模块,提供一个支持Object和XML进行映射的抽象层,其中包括JAXB、Castor、XMLBeans、JiBX和XStream。
4:JMS模块,提供一套”消息生产者、消费者”模板用于更加简单的使用JMS,JMS用于用于在两个应用程序之间,或分布式系统中发送消息,进行异步通信。
5:Transaction模块,支持程序通过简单声明性 事务管理,只要是Spring管理对象都能得到Spring管理事务的好处,即使是POJO,也可以为他们提供事务。
Web
1:Web模块,提供了基础的web功能。例如多文件上传、集成IoC容器、远程过程访问、以及Web Service支持,并提供一个RestTemplate类来提供方便的Restful services访问
2:Web-Servlet模块,提供了Web应用的Model-View-Controller(MVC)实现。Spring MVC框架提供了基于注解的请求资源注入、更简单的数据绑定、数据验证等及一套非常易用的JSP标签,完全无缝与Spring其他技术协作。
3:Web-Struts模块, 提供了对Struts集成的支持,这个功能在Spring3.0里面已经不推荐了,建议你迁移应用到使用Struts2.0或Spring的MVC。
4:Web-Portlet模块,提供了在Portlet环境下的MVC实现
AOP
1:AOP模块,提供了符合AOP 联盟规范的面向方面的编程实现,让你可以定义如方法拦截器和切入点,从逻辑上讲,可以减弱代码的功能耦合,清晰的被分离开。而且,利用源码级的元数据功能,还可以将各种行为信息合并到你的代码中 。
2:Aspects模块,提供了对AspectJ的集成。
3:Instrumentation模块, 提供一些类级的工具支持和ClassLoader级的实现,可以在一些特定的应用服务器中使用。
Test
1:Test模块,提供对使用JUnit和TestNG来测试Spring组件的支持,它提供一致的ApplicationContexts并缓存这些上下文,它还能提供一些mock对象,使得你可以独立的测试代码。
Spring核心
IoC(Inverse ofControl 控制反转): 将对象创建权利交给Spring工厂进行管理。
IoC底层实现:工厂(设计模式)+反射(机制) + 配置文件
AOP(Aspect OrientedProgramming 面向切面编程),基于动态代理的功能增强方式。
高内聚、低耦合
耦合性(Coupling),也叫耦合度,是对模块间关联程度的度量。
耦合是影响软件复杂程度和设计质量的一个重要因素,在设计上我们应采用以下原则:高内聚,低耦合。
内聚与耦合:
内聚标志一个模块内各个元素彼此结合的紧密程度,它是信息隐蔽和局部化概念的自然扩展。内聚是从功能角度来度量模块内的联系,一个好的内聚模块应当恰好做一件事。它描述的是模块内的功能联系。
耦合是软件结构中各模块之间相互连接的一种度量,耦合强弱取决于模块间接口的复杂程度、进入或访问一个模块的点以及通过接口的数据。 程序讲究的是低耦合,高内聚。就是同一个模块内的各个元素之间要高度紧密,但是各个模块之间的相互依存度却要不那么紧密。
内聚和耦合是密切相关的,同其他模块存在高耦合的模块意味着低内聚,而高内聚的模块意味着该模块同其他模块之间是低耦合。在进行软件设计时,应力争做到高内聚,低耦合。
解释:
程序的耦合
耦合:程序间的依赖关系
包括:
类之间的依赖
方法间的依赖
解耦: 降低程序间的依赖关系
实际开发中:
应该做到:编译期不依赖,运行时才依赖。
解耦的思路:
第一步:使用反射来创建对象,而避免使用 new 关键字。
第二步:通过读取配置文件来获取要创建的对象全限定类名
Spring中工厂的类结构
BeanFactory和 ApplicationContext 的区别
BeanFactory 才是 Spring 容器中的顶层接口。
ApplicationContext 是它的子接口。
BeanFactory 和 ApplicationContext 的区别: 创建对象的时间点不一样。
ApplicationContext:只要一读取配置文件,默认情况下就会创建对象。
BeanFactory:什么使用什么时候创建对象。
Beanfactory的用法:
1 | BeanFactory ac = new XmlBeanFactory(new ClassPathResource("applicationContext.xml")); |
ApplicationContext 接口的实现类
ClassPathXmlApplicationContext:
它是从类的根路径下加载配置文件 推荐使用这种
FileSystemXmlApplicationContext:
它是从磁盘路径上加载配置文件,配置文件可以在磁盘的任意位置。
AnnotationConfigApplicationContext:
当我们使用注解配置容器对象时,需要使用此类来创建 spring 容器。它用来读取注解。
#Bean的相关的配置
用于配置对象,让spring创建管理。默认使用无参的构造方法,如果没有无参构造方法则会创建失败。
1.Bean标签的属性:
id:指定对象的唯一标识名称,里面不能出现特殊字符
name:没有使用约束中的唯一约束(理论上可以出现重复,但是实际开发中不能出现)里面可以出现特殊字符。
class:指定类的全限定名称(包名+类名)
2.Bean的作用范围的配置
scope:指定bean的作用范围
singleton:单例(默认值 Spring会采用单例模式创建这个对象)
prototype:多列 (Struts2和Spring整合一定会用到)
单例对象:scope="singleton"
一个应用只有一个对象的实例。它的作用范围就是整个应用。
生命周期:
对象出生:当应用加载,创建容器时,对象就被创建了。
对象活着:只要容器在,对象一直活着。
对象死亡:当应用卸载,销毁容器时,对象就被销毁了。
多例对象:scope="prototype"
每次访问对象时,都会重新创建对象实例。
生命周期:
对象出生:当使用对象时,创建新的对象实例(getBean)。
对象活着:只要对象在使用中,就一直活着。
对象死亡:当对象长时间不用时,被java的垃圾回收器回收了。
生命周期方法:
init-method:指定类中的初始化方法名称(生命周期相关)。
destroy-method:指定类中销毁方法名称(生命周期相关)。
request:web项目中,spring将创建的对象,存入request域中session
globalsession:web项目中,如果是服务器集群环境,应用在整个集群中;如果没有服务器集群,相当于session
3.Bean生命周期
init-method:指定类中的初始化方法名称,一般用于执行资源的初始化
destory-method:指定类的初始化方法名称,一般用于执行资源的释放
4.Bean的实例化方式
1.无参构造方式
2.静态工厂实例化的方式
3.实例工厂
#spring的属性注入
1.构造方法的属性注入
1 | <!-- 将service 实现类装配到容器中 --> |
2.set方法的属性注入
1 | <bean id="bean1" class="com.qiezi.xmlpeizhi.Bean1"> |
3.p名称空间的属性注入(spring2.5以后)
首先引入p名称空间完成属性的注入
1 | xmlns:p = "http://www.springframework.org/schema/p" |
1.普通属性 p:属性名 = “值”
2.对象属性 p:属性名-ref = “值”
1 | <bean id="bean1" class="com.qiezi.xmlpeizhi.Bean1" p:name="凯迪拉克" p:prince="20"></bean> |
4.SplEL的属性注入(spring3.0以后)
Spring Expression Language,Spring的表达式语言。
{SpEl}
1 | <bean id="carInfo" class="com.qiezi.xmlpeizhi.CarInfo"/> |
5.集合类型属性注入
1 | <bean id="collection" class="com.qiezi.collectionBean.demo01"> |
#分模块开发的配置
1.在加载配置文件的时候,加载多个
1 | ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml1","applicationContext.xml2"); |
2.在一个配置文件中引入多个配置文件
1 | <import resource="applicationContext2.xml"/> |
#spring的IOC注解
1 | <!-- 配置资源文件 --> |
1.spring4还需要引入aop的包
2.导入包logging-1.1.1jar, log4j-1.2.15.jar, aop-4.2.4, beans, context, core, expression
3.创建配置文件并引入约束
4.配置组件扫描(那些包下的类使用IOC注解)
1.在类上添加注解
@Component(“”) 组件
作用:
在类上使用该注解,把资源让spring来管理。相当于在xml中配置一个bean。
属性:
value:指定bean的id。如果不指定value属性,默认bean的id是当前类的类名。首字母小写。
@Component 注解:相当于配置了
标签 value= "accountService":相当于配置了bean标签的id属性,单独配置value时,可以省略value属性名称。
1.修饰一个类,将我们这个类交给spring管理
2.这个注解有三个衍生注解(功能类似) 修饰类
@Controller web层
@Service service层
@Repository dao层
2.设置属性的值
注解方式:可以没有set方法
1.有set方法需要将属性注入的注解添加到set方法
2.属性如果没有set方法,需要将属性注入到注解添加到属性上
设置普通属性的 值
@Value(“”) :设置普通属性的 值
设置对象属性的 值
@Autowired 注解的方式按照类型的方式设置 , xml是按照名称的方式进行设置
可以用@Autowired和@Qualified(value=”userDao”) 一起使用 强制按照名称的方式进行配置
上面两种的注解 可以使用一个替代类型是一套spring实现的一套接口规范
自动按照类型注入。当使用注解注入属性时,set方法可以省略。它只能注入其他bean类型。当有多个类型匹配时,使用要注入的对象的变量名称作为bean的id,在spring容器查找,找到了也可以注入成功。找不到就报错。
自动安装类型注入:比如说注入IAccount 自动去spring容器中寻找其子类比如说IAccountImpl在spring中,则将其注入到IAccount中 ,当有多个类型匹配时,使用要注入对象的变量名称作为bean的id在spring中找到并匹配,还可以配合@Qualifier(value = “xxx”)指定某一个id的bean进行注入。当都不喜欢用这两个的时候,可以直接使用@Resource(name = “xxxx”) 指定某一id的bean进行**注入**。
它只能注入其他bean类型:是受spring管理的bean
@Qualifier
作用:
在自动按照类型注入的基础之上,再按照Bean的id注入。它在给字段注入时不能独立使用,必须和@Autowire一起使用;但是给方法参数注入时,可以独立使用。
属性:
value:指定bean的id。
@Resource 按照名称注入 来对 对象设置属性
1 | 作用: |
@Value
作用:
注入基本数据类型和String类型数据的
属性:
value:用于指定值
1 | // value 可以读取资源文件中的数据,但是必须现在applicationContext.xml中声明 |
3.Bean的其他注解
1.声明周期相关的注解
@PostConstruct:初始化方法
@PreDestroy :销毁方法
2.Bean的作用范围的注解
@Scope :作用范围
1 | 位于类上 |
使用:@Scope(“prototype”)
singleton | 默认单例 |
---|---|
prototype | 多例 |
request | |
session | |
globalsession |
3.xml和注解的比较
xml可以使用任何场景 结构清晰,维护方便
注解:有些地方不能用 比如说类不是自己写的,但是开发方便
4.可以使用xml管理Bean,注解完成属性注入
5.注意事项:
扫描是为了扫描类上的注解
在没有扫描的情况下,使用属性注入的注解 @Resource @Value @Autowired @Qulifier
@Configuration
1 | 作用: |
@ComponentScan
1 | 作用: |
@Bean
1 | 作用: |
@PropertySource
1 | 作用: |
@Import
1 | 作用: |
通过注解获取容器
1 |
|
4.spring整合Junit
1.导入坐标
1 | <dependency> |
2.在测试类上添加如下注解
@RunWith(SpringJUnit4ClassRunner.class)
1 | @RunWith(SpringJUnit4ClassRunner.class) |
@ContextConfiguration(locations = {“classpath:applicationContext.xml”})
这是在有配置文件的情况下
如果没有配置文件,纯注解的情况下则使用
@ContextConfiguration(classes = {SpringConfiguration.class})
作用:
加载配置类或者xml配置文件
属性:
value[]:用来指定xml配置文件的路径
class[]: 用来指定配置类
5.注解总结
5.1用于装配Bean的注解
@Component(value = “xxx”)
一般用于将三层中的bean装配到容器中,value可以省略,value的属性值作为bean的id
@Controller(value = “xxx”)
一般用于将web层装配到容器中,使用方法和@Component(value = “xxx”)一模一样
@Service(value = “xxx”)
一般用于将service层装配到容器中,使用方法和@Component(value = “xxx”)一模一样
@Repository(value = “xxx”)
一般用于将dao层装配到容器中,使用方法和@Component(value = “xxx”)一模一样
5.2用于属性注入的注解
@Autowired
只能安装bean类型注入,如果有多个类型匹配,默认将属性名称作为id去容器中查找
@Qualifier
一般和@Autowired配合使用,用来注入指定id的bean,做方法的参数中可以独立使用
@Resource
用来注入指定id的bean类型,相当于@Autowired + @Qualifier
@Value
只能注入基本类型等数据,不能注入bean类型,可以使用#{}在资源文件中获取数据,前提是,外部资源文件被加载
5.3作用域的注解
@Scope
用于指定bean的作用域,一般是singleton和prototype
5.4与生命周期相关的注解
@PostConstruct
用于指定某一个方法为初始化方法
@PreDestory
用于指定某一方法为销毁方法
5.5其他配置类相关的
@Configuration
声明一个类为配置类,用于代替applicationContext.xml
@ComponentScan
用于开启注解扫描的包
@Import
用于导入其他类的
@Bean
用于将方法返回的bean类型的对象装配到容器中
5.6与Junit相关的
@RunWith
用于替换底层的运行器,初始化spring容器的
@ContextConfiguration
用于指定配置文件或者配置类的
#AOP
在软件行业中,AOP为Aspect Oriented Programming 面向切面编程,通过预编译的方式和运行时期动态代理实现程序功能的统一维护的一种技术。AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑之间的耦合度降低,提供程序的可用性,同时提高了开发效率
AOP实现原理
动态代理
特点:
什么时候开始功能增加了,什么时间就创建这个代理对象,然后对目标对象进行功能的增强,不可见,一开始并不存在,在使用目标对象的方法的过程中才 出现。
1.JDK动态代理(基于接口的动态代理) 只能对实现了接口的类产生代理。要求被代理类最少实现一个接口
2.Cglib动态代理(基于子类的动态代理) (类似于Javassist第三方代理技术):可以对没有实现接口的类产生代理对象。要求被代理对象不能用final修饰的类(最终类)
spring底层可以自动进行切换使用这两种
AOP相关术语
1 | class demo{ |
Joinpoint:连接点,可以被拦截到的点,增删改差都可以被增强,这些方法被称为连接点
Pointcut:切入点,真正被拦截到的点,,如果只对save方法的增强,save称为切入点
Advice:通知、增强 方法层面的增强
现在对save方法进行权限校验,权限校验的方法称为通知。
Introduction:引介 是类层面的增强
Target:被增强的对象 如果demo 被增强 则demo就是Target
Weaving:植入,通知应用(Advice)到目标(Target)过程
将权限校验的方法的代码应用到UserDao的save方法上的过程被称为植入
Proxy:代理对象
Aspect:切面,多个通知和多个切入点组合!!!
#springAOP入门
AspectJ的XMl方式
spring的AOP简介
AOP思想最早由AOP联盟组织提出的,spring使用这种思想的最好的框架
1.引入jar包
2.导入配置文件
3.编写类
4.
1 | // 引入spring和Junit4整合的jar |
AspectJ切入点表达式说明
1 | execution:匹配方法的执行(常用) |
常用标签
作用:用于声明开始aop配置
作用:用于配置切面
属性:id给切面提供一个唯一标识
ref:引用配置好的通知类bean的id
作用:用于配置切入点表达式
属性:expression:用于定义切入点表达式
id:用于给切入点表达式提供一个唯一标识
作用:用于配置前置通知
属性:
method:指定通知中方法的名称
pointcut:定义切入点表达式
pointcut-ref :指定切入点表达式的引用
作用:用于配置后置通知
属性:
method:指定通知中放的名称
pointcut:定义切入点表达式
pointcut-ref:指定切入点表达式的引用
作用:
用于配置异常通知
属性:
method:指定通知中方法的名称
pointcut:定义切入点表达式
pointcut-ref:指定切入点表达式的引用
作用:
用于配置最终通知
属性:
method:指定通知中方法的名称
pointcut:定义切入点表达式
pointcut-ref:指定切入点表达式的引用
作用:
用于配置环绕通知
属性:
method:指定通知中方法的名
pointcut:定义切入点表达式
pointcut-ref:指定切入点表达式的引用
说明:
它是spring框架为我们提供的一种可以在代码中手动控制增强代码什么时候执行的方式。
注意:
通常情况下,环绕通知都是独立使用的
注解配置AOP
1.在配置文件中开启注解扫描和注解AOP
1 | <!--开启注解扫描--> |
2.注解装配service实现类
3.通知上使用注解配置并声明该类是一个切面类
1 | "logger") ( |
4.使用注解配置前置通知类型
1 |
|
后置通知
1 |
|
异常通知
1 |
|
最终通知
1 |
|
环绕通知
1 |
|
配置切入点
1 |
|
ps:如果开启全注解配置
需要创建一个配置类,与之前类似,只是多加了个AOP注解扫描
1 | //声明这是个配置类 |
#事务控制
事务控制API介绍
1.PlatformTransactionManager
平台事务管理器,是spring真正管理事务的对象,是一个接口
实现类:
DataSourceTransactionManager:针对JDBC和Mybatis事务管理
HibernateTransactionManager:针对Hibernate事务管理
涉及到的两个接口:
TransactionDefinition:事务定义的对象
事务的隔离级别
事务的传播行为
事务是否只读
事务超时信息
TransactionStatus:事务状态信息的对象
是否有保存点
是否已经完成
等。。。
spring框架进行事务的管理,首先使用TransactionDefinition对事务进行定义,通过PlatformTransactionManager根据TransactionDefinition的定义信息进行事务的管理。在事务的管理过程中产生一系列的状态:保存到TransactionStatus中。
2.TransactionDefinition 事务的定义信息对象,里面有如下方法
获取事务对象名称 -String getName()
获取事务隔离级别 -int getlsolationLevel()
获取事务的超时时间 -int getTimeout()
获取事务是否只读 -boolean isReadOnly() 读写型事务:增删该开启事务;只读型事务:执行查询时,也会开启
事务的隔离级别
事务隔离反映事务提交并发访问时的处理态度
- ISOLATION_DEFAULT 默认级别,归属于下列某一种
- ISOLATION_READ_UNCOMMITTED 可以读取未提交数据
- ISOLATION_REPEATABLE_READ 是否读取其他事务提交修改后的数据,解决不可重复读问题(MySQL默认级别)
- ISOLATION_SERIALIZABLE 是否读取其他事务提交添加后的数据,解决幻读问题
事务的传播行为
传播行为解决的问题:一个业务层事务调用另一个业务层事务时,事务之间关系如何处理
事务传播行为PROPAGATION的取值:
REQUIRED支持当前事务,如果不存在,就新建一个(默认的传播行为)
应用:删除客户 删除订单 处于同一个事务,如果 删除订单失败,删除客户也要回滚
SUPPORTS 支持当前事务,如果不存在,就不使用事务
MANDATORY支持当前事务,如果不存在,抛出异常
REQUIRES_NEW:如果有事务存在,挂起当前事务,创建一个新的事务
应用:生成订单,发送通知邮件,通知会创建一个新的事务,如果邮件失败,不影响订单生成
NOT_SUPPORTED:以非事务方式运行,如果有事务存在,挂起当前事务
NEVER:以非事务方式运行,如果有事务存在,抛出异常
NESTED:如果当前事务存在,则嵌套事务执行
-依赖于JDBC3.0提供SavePoint技术
-删除客户 删除订单,在删除客户后,设置SavePOint执行删除订单,删除订单和删除客户在同一个事务,删除部分订单失败,事务回滚SavePoint,由用户控制是事务提交,还是回滚
小结:
REQUIRED:一个事务,要都成功,要么都失败
REQUIRES_NEW:两个不同事务,彼此直接没有关系,一个事务失败了不影响另一个事务
NESTED:一个事务,在A事务调用B过程中,B失败了,回滚事务到之前SavePoint,用户可以选择提交事务或者回滚事务
超时时间
默认值是-1,没有超时限制,如果有,以秒为单位进行设置。
-建议查询时设置为只读事务
-TransactionStatus接口描述了某个时间点上事务对象的状态信息,包含有6个具体的操作
刷新事务
- void flush()
获取是否存在储存点
- boolean hashSavepoint()
获取事务是否完成
- boolean isCompleted()
获取事务是否为新的事务
- boolean isNewTransaction()
获取事务是否回滚
- boolean isRollbackOnly()
设置事务回滚
- void setRollbackOnly()
基于XML的声明式事务控制(配置方式)
1.装配事务管理器
1 | <!-- 配置一个事务管理器 --> |
2.应用事务管理器
首先需要配置tx和aop的名称空间和约束
1 | <?xml version="1.0" encoding="UTF-8"?> |
配置事务
1 | <!--配置事务策略--> |
基于注解配置事务
1.开启注解事务管理
1 | <!--开启注解事务管理--> |
2.在需要开启事务的类上添加注解
1 |
|
基于配置类的方式
1。创建配置类
1 |
|
2.JdbcConfig
1 | "classpath:jdbc.properties"}) ({ |
3.TxConfig
1 |
|