Spring框架是什么?
Spring是为企业Java最流行的应用程序开发框架。数以百万计的世界各地的开发人员使用Spring框架来创建高性能,易于测试的,可重用的代码。
Spring框架是一个开源的Java平台,它最初是由Rod Johnson编写并在2003年6月在Apache2.0许可下首次发布。
Spring是轻量级的,当涉及到大小和透明度。 spring框架的基本版本是大约2MB。
Spring框架的核心功能可以在任何Java应用程序中使用,但也有扩展的Java EE平台上构建Web应用程序。Spring框架的目标,以使J2EE开发更容易使用,并且通过使基于POJO的编程模型,促进良好的编程习惯。
使用Spring框架的好处:
以下是一些使用Spring框架的极大的好处列表:
Spring 使开发人员使用POJO来开发企业级应用程序。仅使用POJO的好处是不需要EJB容器产品,如应用服务器,但必须只使用一个强大的servlet容器,如Tomcat 或某些商业产品的选择。
Spring 被组织在一个模块化的方式。虽然包和类的数量是巨大的,你只有担心那些需要的,而其它的就忽略了。
Spring不重新发明轮子,而是真正利用了一些像一些ORM框架,日志框架,JEE,Quartz和JDK定时器,其他视图技术的现有技术。
编写测试Spring的应用程序很简单,因为环境相关的代码被移动到这个框架中。此外,通过使用JavaBean风格的POJO,它变得更容易使用依赖注入注入测试数据。
Spring web框架是一个设计良好的Web MVC框架,它提供了一个很好的替代Web框架,如Struts或其他过度设计或不太流行的Web框架。
Spring提供了一个方便的API平移技术特定的异常(通过JDBC,Hibernate,或者JDO抛出,例如)成一致,未经检查的异常。
轻量级的IoC容器往往是轻量级的,尤其是相对EJB容器,例如。这有利于开发和有限的内存和CPU资源的计算机上部署应用程序。
Spring提供了一致的事务管理接口,可向下扩展到(使用一个单一的数据库,例如)本地事务并扩展到全局事务(使用JTA,例如)。
依赖注入(DI):
Spring最有确定的技术是依赖注入控制反转(DI)。控制反转(IoC)是一个笼统的概念,它可以表现在许多不同的方式和依赖注入仅仅是控制反转的一个具体的例子。
当编写一个复杂的Java应用程序,应用程序类应该尽可能独立其他Java类来增加重复使用这些类,并独立于其他类别的测试它们,而这样做单元测试的可能性。依赖注入有助于粘合这些类在一起,同时保持他们的独立。
什么是依赖注入是什么呢?让我们来看看这两个词分开。这里的依赖性部分转化为两个类之间的关联。例如,A类是依赖B类,现在,让我们来看看第二部分,注入。这一切都意味着,B类将由IOC注入到A类得到。
依赖注入可以将参数传递给构造函数的方式或使用后建设setter方法发生。依赖注入是Spring框架的核心,所以会在一个单独的章节,一个不错的例子解释这个概念。
面向切面编程(AOP):
Spring的一个关键组件是面向切面编程(AOP)框架。跨越多个点的应用程序的功能被称为横切关注点和这些横切关注点是从应用程序的业务逻辑概念上区分开来。有方面的各种常见很好的例子包括日志记录,声明性事务,安全性和高速缓存等。
模块化的OOP关键单元是类,而在AOP中模块化的单元则是切面。DI帮助您从彼此分离的应用程序对象,AOP可以帮助你消除来自他们影响的对象横切关注点。
Spring框架AOP模块提供了面向方面编程实现,允许您定义方法拦截器和切入点,以干净脱钩,实现的功能,应该分开代码。我将在单独的一章讨论Spring AOP的概念。
步骤实例:
创建Helloword
第1步 - 创建Java项目:
第一步是使用EclipseIDE 创建一个简单的Java项目
第2步 - 添加必需的库 添加 Spring框架,并在我们的项目中通用的日志API库
第3步 - 创建源文件
我们创建HelloWorld.java 和 MainApp.java
这里是 HelloWorld.java 的文件的内容:
?
1 2 3 4 5 6 7 8 9 10 11 12 13 | package com.yiibai;
public class HelloWorld { private String message;
public void setMessage(String message){ this.message = message; }
public void getMessage(){ System.out.println("Your Message : " + message); } } |
下面是第二个文件 MainApp.java 的内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | package com.yiibai;
import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MainApp { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
HelloWorld obj = (HelloWorld) context.getBean("helloWorld");
obj.getMessage(); } } |
第4步 - 创建beans.xml配置文件:
1 2 3 4 5 6 7 8 9 10 11 12 | <?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-3.0.xsd">
<bean id="helloWorld" class="com.yiibai.HelloWorld"> <property name="message" value="Hello World!"/> </bean>
</beans> |
第5步 - 运行程序:
Spring AOP 编程实现
Java或Web项目都可以,这里需要是maven项目
1.2. 添加Spring AOP依赖pom.xml
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>4.3.9.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.9.RELEASE</version>
</dependency>
<!-- 1.8.5有问题 -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.8.9</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.9</version>
</dependency>
<dependency>
<groupId>Junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
1.3. 添加spring配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans default-lazy-init="true"
xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.3.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-4.3.xsd
http://www.springframework.org/schema/data/jpa
http://www.springframework.org/schema/data/jpa/spring-jpa-1.3.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.3.xsd">
<!-- 自动扫描该包 -->
<context:component-scan base-package="cn.tedu.aop"/>
<!-- 使aspectj注解生效,自动为目标对象生成代理对象 -->
<aop:aspectj-autoproxy/>
</beans>
@Service
publicclass XxxService {
publicint save(Object obj) {
System.out.println("save");
if(obj==null)thrownew NullPointerException();
return 1;
}
publicint update(Object obj) {
System.out.println("update");
if(obj==null)thrownew NullPointerException();
return 1;
}
}
1.5. 定义业务切面组件(基于注解)第一步
v Bean组件切入点(借助bean)
@Aspect
@Component
publicclass LoggingAspect {
@Before("bean(xxxService)")
publicvoid beforeMethod() {
System.out.println("beforeMethod");
}
@After("bean(xxxService)")
publicvoid afterMethod() {
System.out.println("afterMethod");
}
@AfterReturning(pointcut="bean(xxxService)",returning="result")
publicvoid afterReturningMethod(Object result) {
System.out.println("afterReturnMethod.result="+result);
}
@AfterThrowing("bean(xxxService)")
publicvoid afterThrowingMethod() {
System.out.println("afterThrowingMethod");
}
}
通知说明:
@Before: 切面方法在目标方法之前执行
@After: 切面方法在目标方法之后执行
@AfterReturning: 切面方法在目标方法正常结束之后执行
@AfterThrowing: 切面方法在目标方法异常之后执行
v 方法切入点(借助execution)第二部
@Aspect
@Component
publicclass TimingAspect {
@Before("execution(* cn.tedu..[h1] *Service.*(..)[h2] )")
publicvoid timeBeforeMethod(JoinPoint point) {
Stringmethod=point.getSignature().getName();
System.out.println("timeBeforeMethod:"+method);
}
/**方法切入点 (execution: 执行)*/
@After("execution(* cn.tedu..*Service.update(..))")
publicvoid timeAfterMethod(JoinPoint point) {
Stringmethod=point.getSignature().getName();
Objectarg=point.getArgs()[0];
System.out.println("timeAfterMethod:"+method+"("+arg+")");
}
}
2. Spring AOP事务管理
2.1. Spring 事务概述
事务是一个不可分割的逻辑工作单元,具备ACID特性,实际工作中可借助Spring进行事务管理,Spring提供了两种事务管理方式,编程式事务和声明式事务,本讲重点讲解实际项目中最常用的声明式事务管理,以简化事务的编码操作。
Ø Spring声明式事务管理底层基于AOP实现
2.2. Spring 声明式事务
Spring中声明式事务管理有两种方式,基于注解方式和基于xml方式。重点理解注解方式。
v Spring 基于注解方式实现声明式事务管理。
1) 在spring配置文件中启用事务注解
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource"ref="dataSource"/>
</bean>
<!--设置注解驱动的事务管理 -->
<tx:annotation-driven transaction-manager="txManager"/>
<tx:annotation-driven mode="aspectj"/>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource"ref="dataSource" />
</bean>
<bean class="org.springframework.transaction.aspectj.AnnotationTransactionAspect"factory-method="aspectOf">
<property name="transactionManager"ref="transactionManager" />
</bean[h3] >
2) 在类或方法中使用@Transaction注解应用事务。
² name 当在配置文件中有多个 TransactionManager , 可以用该属性指定选择哪个事务管理器。
² propagation 事务的传播行为,默认值为 REQUIRED。
² isolation 事务的隔离度,默认值采用 DEFAULT。
² timeout 事务的超时时间,默认值为-1。如果超过该时间限制但事务还没有完成,则自动回滚事务。
² read-only 指定事务是否为只读事务,默认值为 false;为了忽略那些不需要事务的方法,比如读取数据,可以设置 read-only 为 true。
² rollback-for 用于指定能够触发事务回滚的异常类型,如果有多个异常类型需要指定,各类型之间可以通过逗号分隔。
² no-rollback- for 抛出no-rollback-for 指定的异常类型,不回滚事务。
v Spring 基于XML配置方式实现声明式事务管理(了解)。
<tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <tx:method name="*" propagation="REQUIRED" isolation="READ_COMMITTED" timeout="-1" read-only="false" rollback-for="java.lang.Throwable" no-rollback-for=”NoTransactionException"/> </tx:attributes> </tx:advice> |
<aop:config> <aop:pointcut id="operation" expression="execution(* beans.service..*.*(..))"/> <aop:advisor advice-ref="txAdvice" pointcut="operation"/> </aop:config> |
2.3. Spring 事务的隔离级别
一共有4种, 一般采用@Transactional(isolation=Isolation.READ_COMMITTED) 级别, 是并发性能和安全性折中的选择. 是大多数软件项目采用的隔离级别.
隔离级别越高 效率就越低
在实际开发项目中 多个事务可能会并发执行 可能导致以下问题:
1. 脏读(A事务读取到了B事务没有提交的事务 B事务一旦回滚 A事务读取的就是脏事务) 如何避免?可以将事务的隔离级别设置为Isolation.READ_COMMITTED
2. 不可重复读取(原则上讲一个事物内部对某条数据的多次读取都是一致的 但当出现多次读取不一致 就称为不可重复读取) 可以将事务的隔离级别设置为isolation=Isolation.READ
3.
4. 幻影读(A事务读取B事务的两次有可能不一致 那是因为B事务添加了一条数据) 如何避免? 可以将事务的隔离级别设置为Isolation.SERIALIZABLE