Spring简介
Spring是一个开放源代码的设计层面框架,它解决的是业务逻辑层和其他各层的松耦合问题,因此它将面向接口的编程思想贯穿整个系统应用。Spring是于2003 年兴起的一个轻量级的Java 开发框架,由Rod Johnson创建。简单来说,Spring是一个分层的JavaSE/EE full-stack(一栈式) 轻量级开源框架。
- J2EE三层架构体系
-> 表现层
-> 业务层
-> 持久层
VIEW: Struts,Spring MVC
Service: 业务处理,功能逻辑,事物控制 IOC ,AOP
DAO: Mybatis,JBDC ,Hibernate
- 一站式
Spring提供了JavaEE各层的解决方案,
表现层:Spring MVC。
持久层:JdbcTemplate、ORM框架整合。
业务层:IOC、AOP、事务控制。
轻量级
Spring的出现取代了EJB的臃肿、低效、繁琐复杂、脱离现实。Spring体系架构
IOC
- IOC介绍
IOC其是一种设计思想,将创建对象的权利交给Spring,由IOC统一加载和管理,让Spring去管理对象生命周期,极大的解决了程序耦合性高的问题。
- IOC思想前瞻
IOC的思想最核心的地方在于,资源不由使用资源的双方管理,而由不使用资源的第三方管理,这可以带来很多好处。
第一,资源集中管理,实现资源的可配置和易管理。
第二,降低了使用资源双方的依赖程度,也就是我们说的耦合度。比如说甲方要达成某种目的不需要直接依赖乙方,它只需要达到的目的告诉第三方机构就可以了。
- Spring IOC容器
Spring IOC容器有两种BeanFactory和ApplicationContext,BeanFactory 是 Spring 框架的基础设施,面向 Spring 本身。ApplicationContext 面向使用 Spring 框架的开发者,几乎所有的应用场合我们都直接使用 ApplicationContext 而非底层的 BeanFactory。
- BeanFactory
BeanFactory 接口位于类结构树的顶端 ,IOC容器所设定的最基本功能规范。它最主要的方法就是 getBean(String beanName),该方法从容器中返回特定名称的 Bean。
BeanFactory的三个子接口:
* HierarchicalBeanFactory:提供父容器的访问功能
* ListableBeanFactory:提供了批量获取Bean的方法
* AutowireCapableBeanFactory:在BeanFactory基础上实现对已存在实例的管
解析
public interface BeanFactory {
/**
* 获取产生对象的FactoryBean
* 如:myObject是一个FactoryBean,使用&myObject得到的是FactoryBean
*/
String FACTORY_BEAN_PREFIX = "&";
/**
* 获取IoC容器中管理的bean
* @param name
* @return
* @throws BeansException
*/
Object getBean(String name) throws BeansException;
/**
* 判断容器是否含有指定名称的bean
* @param name
* @return
*/
boolean containsBean(String name);
/**
* 检查指定名称的bean是否是单例(可以在BeanDefinition中指定)
* @param name
* @return
* @throws NoSuchBeanDefinitionException
*/
boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
/**
* 检查指定名称的bean是否是prototype类型(可以在BeanDefinition中指定)
* @param name
* @return
* @throws NoSuchBeanDefinitionException
*/
boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
/**
* 检查指定名称的bean的Class类型是否是特定Class类型
* @param name
* @param targetType 用户指定
* @return
* @throws NoSuchBeanDefinitionException
*/
boolean isTypeMatch(String name, Class targetType) throws NoSuchBeanDefinitionException;
/**
* 查询指定名称bean的Class类型
* @param name
* @return
* @throws NoSuchBeanDefinitionException
*/
Class<?> getType(String name) throws NoSuchBeanDefinitionException;
/**
* 查询指定名称bean的所有别名(用户在BeanDefinition中指定的)
* @param name
* @return
*/
String[] getAliases(String name);
}
- ApplicationContext
ApplicationContext app = new ClassPathXmlApplicationContext(" .xml");
类名 对象名 =(类名)app.getBean(" ");
解析
从 ApplicationContext 的继承机构可以看到, ApplicationContext 继承了BeanFactory,也就是说,ApplicationContext 拥有BeanFactory的全部功能,ApplicationContext 是通过将容器的功能委派给DefaultListableBeanFactory来实现。除了继承BeanFactory,还有ResourceLoader、EnvironmentCapable、ApplicationEventPublisher、MessageSource等接口,也就说明ApplicationContext 除了容器的功能外,还囊括了资源的处理、环境、事件发布、国际化等。
- 示列
1:xml配置
<?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">
<!-- 若没写id,则默认为com.test.Man#0,#0为一个计数形式 -->
<bean id="man" class="com.test.Man"></bean>
</beans>
public class Test {
public static void main(String[] args) {
//加载项目中的spring配置文件到容器
//ApplicationContext context = new ClassPathXmlApplicationContext("resouces/applicationContext.xml");
//加载系统盘中的配置文件到容器
ApplicationContext context = new FileSystemXmlApplicationContext("E:/Spring/applicationContext.xml");
//从容器中获取对象实例
Man man = context.getBean(Man.class);
man.driveCar();
}
}
DI(依赖注入)
- DI概念前瞻
IOC重点是如何在系统运行中动态向某个对象提供它所需要的其他对象。这一点是通过DI(Dependency Injection,依赖注入)来实现的。比如对象A需要操作数据库,以前我们总是要在A中自己编写代码来获得一个Connection对象,有了 Spring我们就只需要告诉Spring,A中需要一个Connection,至于这个Connection怎么构造,何时构造,A不需要知道。在系统运行时,Spring会在适当的时候制造一个Connection,然后像打针一样,注射到A当中,这样就完成了对各个对象之间关系的控制。A需要依赖 Connection才能正常运行,而这个Connection是由 Spring注入到A中的,依赖注入的名字就这么来的。那么DI是如何实现的呢? Java 1.3之后一个重要特征是反射(reflection),它允许程序在运行的时候动态的生成对象、执行对象的方法、改变对象的属性,Spring就是通过反射来实现注入的。
- DI关键点!
理解DI的关键是:依赖,为什么需要依赖,谁注入谁,注入了什么,应用程序依赖于IOC容器,为什么需要依赖:应用程序需要IoC容器来提供对象需要的外部资源比如对数据库操作的对象,IOC容器注入这个,应用程序依赖这个对象,IOC和DI有什么关系呢?其实它们是同一个概念的不同角度描述,由于控制反转概念比较含糊(可能只是理解为容器控制对象这一个层面,很难让人想到谁来维护对象关系),所以2004年大师级人物Martin Fowler又给出了一个新的名字:依赖注入,相对IOC 而言,依赖注入明确描述了被注入对象依赖IoC容器配置依赖对象!
- Spring装配bean有三种方式
构造器注入
使用setter方法注入 [推荐]
接口注入
- 基于注解的方式
@Component:可以用于注册所有bean
@Repository:主要用于注册dao层的bean
@Controller: 主要用于注册控制层的bean
@Service: 主要用于注册服务层的bean
@Resource:java的注解,默认以byName的方式去匹配与属性名相同的bean的id,如果没有找到就会以byType的方式查找,如果byType查找到多个的话,使用@Qualifier注解(spring注解)指定某个具体名称的bean。
@Autowired:spring注解,默认也是以byName的方式去匹配与属性名相
同的bean的id,如果没有找到,就通过byType的方式去查找,如果查找到多个,用@Qualifier注解限定具体使用哪个。
@Autowired
private IUserDao userDao;
但是如果IUserDao有多个实现类则需要:
@Autowired
@Qualifier("指定具体实现")
private IUserDao userDao;
AOP
AOP概念点
在软件业,AOP为Aspect Oriented Programming的缩写,意为:[面向切面编程],通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,使函数式编程降低,提高程序的可重用性,同时提高了开发的效率。
- spring术语讲解
1、切面:拦截器类,其中会定义切点以及通知
2、通知:切面当中的方法,包括:
前置通知:在动态代理反射原先方法前调用的方法
后置通知:在动态代理反射完原有方法后调用的方法
返回通知:如果方法正常执行,在调用完后置通知后,就调用返回通知
异常通知:如果方法出现异常,在调用完后置通知后,就调用异常通知
环绕通知:可以决定是否调用目标方法,同时可以控制方法的返回
对象(这个通知具有一些细节,接下来会进一步说明)
3、引入:往代理对象中添加新的方法,但是新的方法不会被拦截
4、切点:即定义需要拦截的方法的特征,可以通过正则表达式匹配,也可以通过类的全限定名
5、连接点:需要拦截的方法
6、织入:生成代理对象并将切面内容嵌入流程中,将切面内容嵌入到流程中是什么意思呢?例如现在定义了前置通知,那么代理对象在调用被代理对象的方法之前就会调用前置通知
- 示列
@Aspect
public class UserInterceptor {
@Pointcut("execution( * org.srm.practice.service.*.*(..))")
public void user() {
}
@Before("user()")
public void sayHello() {
System.out.println("前置");
}
@After("user()")
public void sayGoodbey() {
System.out.println("后置");
}
@Around("user()")
public void sayAround(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("环绕通知..环绕前");
pjp.proceed();//执行方法
System.out.println("环绕通知..环绕后");
}
}
事物
Spring支持编程式事务管理和声明式事务管理两种方式。
- 编程式事务管理
编程式事务管理使用TransactionTemplate或者直接使用底层的PlatformTransactionManager。对于编程式事务管理,Spring推荐使用TransactionTemplate。
- 声明式事务管理建立在AOP之上的
声明式事务管理建立在AOP之上的。其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。声明式事务最大的优点就是不需要通过编程的方式管理事务,这样就不需要在业务逻辑代码中掺杂事务管理的代码,只需在配置文件中做相关的事务规则声明(或通过基于@Transactional注解的方式),便可以将事务规则应用到业务逻辑中
事务隔离级别
隔离级别是指若干个并发的事务之间的隔离程度。TransactionDefinition 接口中定义了五个表示隔离级别的常量:
TransactionDefinition.ISOLATION_DEFAULT:这是默认值,表示使用底层数据库的默认隔离级别。对大部分数据库而言,通常这值就是TransactionDefinition.ISOLATION_READ_COMMITTED。
TransactionDefinition.ISOLATION_READ_UNCOMMITTED:该隔离级别表示一个事务可以读取另一个事务修改但还没有提交的数据。该级别不能防止脏读,不可重复读和幻读,因此很少使用该隔离级别。比如PostgreSQL实际上并没有此级别。
TransactionDefinition.ISOLATION_READ_COMMITTED:该隔离级别表示一个事务只能读取另一个事务已经提交的数据。该级别可以防止脏读,这也是大多数情况下的推荐值。
TransactionDefinition.ISOLATION_REPEATABLE_READ:该隔离级别表示一个事务在整个过程中可以多次重复执行某个查询,并且每次返回的记录都相同。该级别可以防止脏读和不可重复读。
TransactionDefinition.ISOLATION_SERIALIZABLE:所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别。
事务传播行为
所谓事务的传播行为是指,如果在开始当前事务之前,一个事务上下文已经存在,此时有若干选项可以指定一个事务性方法的执行行为。在TransactionDefinition定义中包括了如下几个表示传播行为的常量:
TransactionDefinition.PROPAGATION_REQUIRED:如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。这是默认值。
TransactionDefinition.PROPAGATION_REQUIRES_NEW:创建一个新的事务,如果当前存在事务,则把当前事务挂起。
TransactionDefinition.PROPAGATION_SUPPORTS:如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
TransactionDefinition.PROPAGATION_NOT_SUPPORTED:以非事务方式运行,如果当前存在事务,则把当前事务挂起。
TransactionDefinition.PROPAGATION_NEVER:以非事务方式运行,如果当前存在事务,则抛出异常。
TransactionDefinition.PROPAGATION_MANDATORY:如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。
TransactionDefinition.PROPAGATION_NESTED:如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于TransactionDefinition.PROPAGATION_REQUIRED。
事务超时,所谓事务超时,就是指一个事务所允许执行的最长时间,如果超过该时间限制但事务还没有完成,则自动回滚事务。在 TransactionDefinition 中以 int 的值来表示超时时间,其单位是秒。默认设置为底层事务系统的超时值,如果底层数据库事务系统没有设置超时值,那么就是none,没有超时限制。