Spring学习总结

Spring学习总结

原文链接:Spring学习总结

Spring简介

Spring是一个开源的设计层面框架,它解决的是业务逻辑层和其他层的松耦合问题,因此它将面向接口的编程思想贯穿整个系统应用。Spring是于2003 年兴起的一个轻量级的Java 开发框架,由Rod Johnson创建。简单来说,Spring是一个分层的JavaSE/EE full-stack(一栈式) 轻量级开源框架。

J2EE三层架构体系

  • 表现层
    • view,典型代表:Strusts,Spring MVC
  • 业务层
    • Service,主要功能是业务处理、功能逻辑、事务控制 IOC、AOP
  • 持久层
    • dao,mybatis、hibernate、jdbc

轻量级

Spring的出现取代了EJB的臃肿、低效、繁琐复杂、脱离现实。

Spring体系结构

Spring学习总结_第1张图片

IOC

IOC介绍

IOC其是一种设计思想,将创建对象的权利交给Spring,由IOC统一加载和管理,让Spring去管理对象生命周期,极大的解决了程序耦合性高的问题。

IOC思想前瞻

IOC的核心思想在于,资源不由使用资源的双方管理,而由不使用资源的第三方管理,这可以带来很多好处:

  1. 资源集中管理,实现资源的可配置和易管理
  2. 降低了使用资源双方的依赖程度,也就是我们说的耦合度。比如说甲方要达成某种目的不需要直接依赖乙方,它只需要达到的目的告诉第三方机构就可以了。

举个栗子:

​ 比如甲方需要一双袜子,而乙方它卖一双袜子它要把袜子卖出去,并不需要自己去直接找到一个买家来完成袜子的卖出。它也只需要找第三方,告诉别人我要卖一双袜子。这样甲乙双方进行交易活动,都不需要自己直接去找卖家,相当于程序内部开放接口,卖家由第三方作为参数传入。甲乙互相不依赖,而且只有在进行交易活动的时候,甲才和乙产生联系。反之亦然。

​ 这样做什么好处么呢?甲乙可以在对方不真实存在的情况下独立存在,而且保证不交易时候无联系,想交易的时候可以很容易的产生联系。甲乙交易活动不需要双方见面,避免了双方的互不信任造成交易失败的问题。因为交易由第三方来负责联系,而且甲乙都认为第三方可靠。那么交易就能很可靠很灵活的产生和进行了,这就是IOC的核心思想甲乙双方将不在相互依懒

Spring IOC 容器

Spring IOC容器有两种BeanFactory和ApplicationContext,BeanFactory 是 Spring 框架的基础设施,面向 Spring 本身。ApplicationContext 面向使用 Spring 框架的开发者,几乎所有的应用场合我们都直接使用 ApplicationContext 而非底层的 BeanFactory。

BeanFactory

BeanFactory 接口位于类结构树的顶端 ,IOC容器所设定的最基本功能规范。

BeanFactory最主要的方法就是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(" ");

Spring学习总结_第2张图片
从 ApplicationContext 的继承机构可以看到,ApplicationContext 继承了BeanFactory,也就是说,ApplicationContext拥有BeanFactory的全部功能。ApplicationContext 是通过将容器的功能委派给DefaultListableBeanFactory来实现。除了继承BeanFactory,还有ResourceLoader、EnvironmentCapable、ApplicationEventPublisher、MessageSource等接口,也就说明ApplicationContext 除了容器的功能外,还囊括了资源的处理、环境、事件发布、国际化等。

示例

<?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(依赖注入)

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为Aspect Oriented Programming的缩写,意为:[面向切面编程],通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,使函数式编程降低,提高程序的可重用性,同时提高了开发的效率。
Spring学习总结_第3张图片

spring术语

  • 切面:拦截器类,其中会定义切点以及通知
  • 通知:切面中的方法,包括:
    • 前置通知:在动态代理反射原先方法前调用的方法
    • 后置通知:在动态代理反射完原有方法后调用的方法
    • 返回通知:如果方法正常执行,在调用完后置通知后,就调用返回通知
    • 异常通知:如果方法出现异常,在调用完后置通知后,就调用异常通知
    • 环绕通知:可以决定是否调用目标方法,同时可以控制方法的返回
    • 对象
  • 引入:往代理对象中添加新的方法,但是新的方法不会被拦截
  • 切点:即定义需要拦截的方法的特征,可以通过正则表达式匹配,也可以通过类的全限定名
  • 连接点:需要拦截的方法
  • 织入:生成代理对象并将切面内容嵌入流程中,将切面内容嵌入到流程中是什么意思呢?例如现在定义了前置通知,那么代理对象在调用被代理对象的方法之前就会调用前置通知

示例

@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之上的。其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。声明式事务最大的优点就是不需要通过编程的方式管理事务,这样就不需要在业务逻辑代码中掺杂事务管理的代码,只需在配置文件中做相关的事务规则声明(或通过基于@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,没有超时限制。

你可能感兴趣的:(java)