Spring核心知识备忘总结

Spring简介

Spring是一个轻量级的IoC和AOP容器框架。

Spring模块

主要由以下几个模块组成:
Spring Core:核心类库,提供IOC服务;
Spring Context:提供框架式的Bean访问方式,以及企业级功能(JNDI、定时任务等);
Spring AOP:AOP服务;
Spring DAO:对JDBC的抽象,简化了数据访问异常的处理;
Spring ORM:对现有的ORM框架的支持;
Spring Web:提供了基本的面向Web的综合特性,例如多方文件上传;
Spring MVC:提供面向Web应用的Model-View-Controller实现。

spring优点:

IOC和DI实现了高内聚低耦合
AOP提高了代码的复用率,也能使我们开发的时候更专注于核心业务
spring对其他主流框架提供了很好的集成支持


Spring工作原理:IOC(DI)和AOP

Spring IOC 容器:

 负责创建对象,装配对象,并且管理这些对象的整个生命周期。

IOC理解:

 IOC就是控制反转,以前我们创建对象是在代码里直接new, 耦合度高,IOC把对象的控制权反转给了spring容器,由容器根据配置文件和注解来创建对象和管理对象之间的依赖,降低了对象之间的耦合度,也有利于代码的复用。

DI理解:

 DI依赖注入,和IOC是同一个概念的不同角度的描述,就是在Spring创建对象时,动态的将依赖对象注入这个对象中,也就是自动地给创建对象的属性赋值。

AOP理解:

参考:Spring-AOP实战

AOP编程允许你把遍布于应用各层的功能分离出来形成可重用的功能组件。

 AOP就是面向切面,作为面向对象的一种补充,用于将那些与业务无关,但却对多个对象产生影响的公共行为和逻辑,抽取并封装为一个可重用的模块,这个模块被命名为“切面”(Aspect),减少系统中的重复代码,降低了模块间的耦合度,同时提高了系统的可维护性。可用于权限认证、日志、事务处理等公共功能。
 AOP实现的关键在于 代理模式,AOP代理主要分为静态代理和动态代理。静态代理的代表为AspectJ;动态代理则以Spring AOP为代表。

 1.AspectJ是静态代理的增强,所谓静态代理,就是AOP框架会在编译阶段生成AOP代理类,因此也称为编译时增强,他会在编译阶段将AspectJ(切面)织入到Java字节码中,运行的时候就是增强之后的AOP对象。

  2. Spring AOP使用的动态代理,所谓的动态代理就是说AOP框架不会去修改字节码,而是每次运行时在内存中临时为方法生成一个AOP对象,这个AOP对象包含了目标对象的全部方法,并且在特定的切点做了增强处理,并回调原对象的方法。
 Spring AOP中的动态代理主要有两种方式,JDK动态代理和CGLIB动态代理


Spring Bean的生命周期:

参考:https://www.cnblogs.com/zrtqsk/p/3735273.html

Servlet的生命周期:实例化,初始init,接收请求service,销毁destroy;
在这里插入图片描述
Spring上下文中的Bean生命周期与之类似,如下:
在这里插入图片描述
(1)实例化Bean:
对于BeanFactory容器,当客户向容器请求一个尚未初始化的bean时,或初始化bean的时候需要注入另一个尚未初始化的依赖时,容器就会调用createBean进行实例化。对于ApplicationContext容器,当容器启动结束后,通过获取BeanDefinition对象中的信息,实例化所有的bean。
(2)设置对象属性(依赖注入):
实例化后的对象被封装在BeanWrapper对象中,紧接着,Spring根据BeanDefinition中的信息 以及 通过BeanWrapper提供的设置属性的接口完成依赖注入。
(3)调用Aware接口方法:Aware接口也是为了让Bean能够感知到自身的一些属性。
接着,Spring会检测该对象是否实现了xxxAware接口,并将相关的xxxAware实例注入给Bean:
  ①如果这个Bean已经实现了BeanNameAware接口,会调用它实现的setBeanName(String beanId)方法,此处传递的就是Spring配置文件中Bean的id值;
  ②如果这个Bean已经实现了BeanFactoryAware接口,会调用它实现的setBeanFactory()方法,传递的是Spring工厂自身。
  ③如果这个Bean已经实现了ApplicationContextAware接口,会调用setApplicationContext(ApplicationContext)方法,传入Spring上下文;
(4)调用BeanPostProcessor预初始化方法
 如果想对Bean在初始化前进行一些自定义的处理,那么可以让Bean实现了BeanPostProcessor接口,那将会调用postProcessBeforeInitialization(Object obj, String s)方法。由于这个方法是在实例初始化前调用的,所以可以被应用于内存或缓存技术;
(5)调用nitializingBean: afterPropertiesSet方法
(6)调用Bean配置的init-method方法:
 如果配置了Bean的 init-method ,则自动调用配置的初始化方法。
(7)调用BeanPostProcessor后初始化方法:
 Bean实现了BeanPostProcessor接口,则会调用postProcessAfterInitialization方法。
(8)1~6步骤之后bean已经可以正常使用了
(7)DisposableBean:
 当Bean不再需要时,会经过清理阶段,如果Bean实现了DisposableBean这个接口,会调用其实现的destroy()方法;
(9))调用Bean配置的destroy-method方法
 最后,如果这个Bean的Spring配置中配置了destroy-method属性,会自动调用其配置的销毁方法。

以上是SpringBean主要的生命周期模型,更完整的Spring Bean生命周期如下:
在这里插入图片描述
在这里插入图片描述


Spring理论知识参考

网上教程:spring教程
书籍:《Spring实战 (第4版)》


Spring实战-Spring框架整合

可以参考我的另外两篇博文:
开发工具链-maven核心教程-Maven整合SSH(Spring,SpringMVC,Hibernate)
框架整合-SpringMVC+Spring+Mybatis


Spring实战-常用配置

引用属性文件

参考:Spring里PropertyPlaceholderConfigurer类的使用

<!-- 引入外部属性配置文件,供xml以${key}调用 -->
	<bean id="propertyConfigeurer"
		class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
		<property name="locations">
			<list>
				<value>classpath:hibernate.properties</value>
				<value>classpath:redis.properties</value>
			</list>
		</property>
	</bean>

开启注解

 <context:annotation-config />

<context:annotation-config /> 将隐式地向 Spring容器注册:AutowiredAnnotationBeanPostProcessor、 CommonAnnotationBeanPostProcessor、PersistenceAnnotationBeanPostProcessor 以及equiredAnnotationBeanPostProcessor 这 4 个 BeanPostProcessor。

配置包扫描

 <!--配置包扫描-->
  <context:component-scan base-package="com.aop.transaction.pay" />

提示:当使用 <context:component-scan/ > 后,就可以将\ <context:annotation-config/ > 移除了。

配置数据源datasource

1、使用org.springframework.jdbc.datasource.DriverManagerDataSource
 测试环境可采用driverManagerDataSource

	说明:DriverManagerDataSource建立连接是只要有连接就新建一个connection, 根本没有连接池的作用。 
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> 
              <property name="driverClassName"><value>${jdbc.driverClassName}</value></property> 
              <property name="url"><value>${jdbc.url}</value></property> 
              <property name="username"><value>${jdbc.username}</value></property> 
              <property name="password"><value>${jdbc.password}</value></property> 
 </bean> 

2、使用DBCP 、C3P0、Druid

说明:这3种方式真正使用了连接池技术 

数据库连接池技术的思想非常简单:

 将数据库连接作为对象存储在一个Vector数组中,一旦数据库连接建立后,不同的数据库访问请求就可以共享这些连接,这样,通过循环利用这些已经建立好的数据库连接,就可以节省我们去不断创建新连接的是啊进和资源,极大地节省系统资源和时间。

 数据库连接池的主要操作如下:
(1)建立数据库连接池对象(服务器启动)。
(2)按照事先指定的参数创建初始数量的数据库连接(即:空闲连接数),我们在安装数据库的时候就可以指定。
(3)对于一个数据库访问请求,直接从连接池中得到一个连接。如果数据库连接池对象中没有空闲的连接,且连接数没有达到 最大(即:最大活跃连接数),创建一个新的数据库连接。而如果连接数达到最大,就会再创建事先定好的连接数.
(4)对数据库进行存取操作。
(5)关闭数据库,释放所有数据库连接(此时的关闭数据库连接,并非真正关闭,而是将其放入空闲队列中。如实际空闲连接 数大于初始空闲连接数则释放连接)。
(6)释放数据库连接池对象(服务器停止、维护期间,释放数据库连接池对象,并释放所有连接)。

DBCP数据源配置
 Tomcat 的连接池正是采用该连接池来实现的( tomcat7及以后使用,Tomcat jdbc pool,它能解决dbcp不能解决的一些问题)。该数据库连接池既可以与应用服务器整合使用,也可由应用程序独立使用。

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"> 
              <property name="driverClassName"> 
                     <value>${jdbc.driverClassName}</value> 
              </property> 
              <property name="url"> 
                     <value>${jdbc.url}</value> 
              </property> 
              <property name="username"> 
                     <value>${jdbc.username}</value> 
              </property> 
              <property name="password"> 
                     <value>${jdbc.password}</value> 
              </property> 
              <property name="maxActive"> 
                     <value>100</value> 
              </property> 
              <property name="maxIdle"> 
                     <value>2</value> 
              </property> 
              <property name="maxWait"> 
                     <value>100000</value> 
              </property> 
       </bean> 

常见可选项:

  • defaultAutoCommit:设置从数据源中返回的连接是否采用自动提交机制,默认值为 true;
  • defaultReadOnly:设置数据源是否仅能执行只读操作, 默认值为 false;
  • maxActive:最大连接数据库连接数,设置为0时,表示没有限制;
  • maxIdle:最大等待连接中的数量,设置为0时,表示没有限制;
  • maxWait:最大等待秒数,单位为毫秒, 超过时间会报出错误信息;
  • validationQuery:用于验证连接是否成功的查询SQL语句,SQL语句必须至少要返回一行数据, 如你可以简单地设置为:“select count(*) from user”;
  • removeAbandoned:是否自我中断,默认是 false ;
  • removeAbandonedTimeout:几秒后数据连接会自动断开,在removeAbandoned为true,提供该值;
  • logAbandoned:是否记录中断事件, 默认为 false;

 
C3P0数据源配置
  c3p0是一个开源的JDBC连接池,它实现了数据源和JNDI绑定,实现了JDBC3和JDBC2扩展规范说明的 Connection 和Statement 池。目前使用它开源项目有Hibernate,Spring。(Hibernate项目推荐使用)

<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"       
        destroy-method="close">      
   <property name="driverClass" value=" ${jdbc.driverClassName} "/>      
  <property name="jdbcUrl" value="${jdbc.url}"/>      
<property name="user" value="${jdbc.username}"/>      
 <property name="password" value="${jdbc.password}"/>      
</bean> 

相对来说,C3P0拥有比DBCP更丰富的可选配置属性:

  • acquireIncrement:当连接池中的连接用完时,C3P0一次性创建新连接的数目;
  • acquireRetryAttempts:定义在从数据库获取新连接失败后重复尝试获取的次数,默认为30;
  • acquireRetryDelay:两次连接中间隔时间,单位毫秒,默认为1000;
  • autoCommitOnClose:连接关闭时默认将所有未提交的操作回滚。默认为false;
  • automaticTestTable: C3P0将建一张名为Test的空表,并使用其自带的查询语句进行测试。如果定义了这个参数,那么属性preferredTestQuery将被忽略。你 不能在这张Test表上进行任何操作,它将中为C3P0测试所用,默认为null;
  • breakAfterAcquireFailure:获取连接失败将会引起所有等待获取连接的线程抛出异常。但是数据源仍有效保留,并在下次调 用getConnection()的时候继续尝试获取连接。如果设为true,那么在尝试获取连接失败后该数据源将申明已断开并永久关闭。默认为 false;
  • checkoutTimeout:当连接池用完时客户端调用getConnection()后等待获取新连接的时间,超时后将抛出SQLException,如设为0则无限期等待。单位毫秒,默认为0;
  • connectionTesterClassName: 通过实现ConnectionTester或QueryConnectionTester的类来测试连接,类名需设置为全限定名。默认为 com.mchange.v2.C3P0.impl.DefaultConnectionTester;
  • idleConnectionTestPeriod:隔多少秒检查所有连接池中的空闲连接,默认为0表示不检查;
  • initialPoolSize:初始化时创建的连接数,应在minPoolSize与maxPoolSize之间取值。默认为3;
  • maxIdleTime:最大空闲时间,超过空闲时间的连接将被丢弃。为0或负数则永不丢弃。默认为0;
  • maxPoolSize:连接池中保留的最大连接数。默认为15;
  • maxStatements:JDBC的标准参数,用以控制数据源内加载的PreparedStatement数量。但由于预缓存的Statement属 於单个Connection而不是整个连接池。所以设置这个参数需要考虑到多方面的因素,如果maxStatements与 maxStatementsPerConnection均为0,则缓存被关闭。默认为0;
  • maxStatementsPerConnection:连接池内单个连接所拥有的最大缓存Statement数。默认为0;
  • numHelperThreads:C3P0是异步操作的,缓慢的JDBC操作通过帮助进程完成。扩展这些操作可以有效的提升性能,通过多线程实现多个操作同时被执行。默认为3;
  • preferredTestQuery:定义所有连接测试都执行的测试语句。在使用连接测试的情况下这个参数能显著提高测试速度。测试的表必须在初始数据源的时候就存在。默认为null;
  • propertyCycle: 用户修改系统配置参数执行前最多等待的秒数。默认为300;
  • testConnectionOnCheckout:因性能消耗大请只在需要的时候使用它。如果设为true那么在每个connection提交的时候都 将校验其有效性。建议使用idleConnectionTestPeriod或automaticTestTable
    等方法来提升连接测试的性能。默认为false;
  • testConnectionOnCheckin:如果设为true那么在取得连接的同时将校验连接的有效性。默认为false。
     
    Druid数据源配置
     阿里出品,淘宝和支付宝专用数据库连接池,支持所有JDBC兼容的数据库,包括Oracle、MySql、Derby、Postgresql、SQL Server、H2等等,Druid针对Oracle和MySql做了特别优化。下载druid
    参考:https://www.cnblogs.com/wuyun-blog/p/5679073.html
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" 
  init-method="init" destroy-method="close"> 
  <property name="driverClassName" value="${jdbc.driverClassName}" /> 
  <property name="url" value="${jdbc.url}" /> 
  <property name="username" value="${jdbc.username}" /> 
  <property name="password" value="${jdbc.password}" /> 
  <!-- 配置初始化大小、最小、最大 --> 
  <property name="initialSize" value="1" /> 
  <property name="minIdle" value="1" /> 
  <property name="maxActive" value="10" />
  <!-- 配置获取连接等待超时的时间 --> 
  <property name="maxWait" value="10000" />
  <!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 --> 
  <property name="timeBetweenEvictionRunsMillis" value="60000" />
  <!-- 配置一个连接在池中最小生存的时间,单位是毫秒 --> 
  <property name="minEvictableIdleTimeMillis" value="300000" />
  <property name="testWhileIdle" value="true" />
  <!-- 这里建议配置为TRUE,防止取到的连接不可用 --> 
  <property name="testOnBorrow" value="true" /> 
  <property name="testOnReturn" value="false" />
  <!-- 打开PSCache,并且指定每个连接上PSCache的大小 --> 
  <property name="poolPreparedStatements" value="true" /> 
  <property name="maxPoolPreparedStatementPerConnectionSize" 
   value="20" />
  <!-- 这里配置提交方式,默认就是TRUE,可以不用配置 -->
  <property name="defaultAutoCommit" value="true" />
  <!-- 验证连接有效与否的SQL,不同的数据配置不同 --> 
  <property name="validationQuery" value="select 1 " /> 
  <property name="filters" value="stat" /> 
  <property name="proxyFilters"> 
   <list> 
    <ref bean="logFilter" /> 
   </list> 
  </property> 
 </bean>
 <bean id="logFilter" class="com.alibaba.druid.filter.logging.Slf4jLogFilter"> 
  <property name="statementExecutableSqlLogEnable" value="false" /> 
 </bean>

druid还提供一个监控页面,通过以下配置即可访问:
http://localhost:8080/druid (端口根据自己具体情况修改)

<!--druid web监控配置-->
<servlet> 
     <servlet-name>DruidStatView</servlet-name> 
     <servlet-class>com.alibaba.druid.support.http.StatViewServlet</servlet-class> 
 </servlet> 
 <servlet-mapping> 
     <servlet-name>DruidStatView</servlet-name> 
     <url-pattern>/druid/*</url-pattern> 
 </servlet-mapping> 
 <filter> 
  <filter-name>druidWebStatFilter</filter-name> 
  <filter-class>com.alibaba.druid.support.http.WebStatFilter</filter-class> 
  <init-param> 
   <param-name>exclusions</param-name> 
   <param-value>/public/*,*.js,*.css,/druid*,*.jsp,*.swf</param-value> 
  </init-param> 
  <init-param> 
   <param-name>principalSessionName</param-name> 
   <param-value>sessionInfo</param-value> 
  </init-param> 
  <init-param> 
   <param-name>profileEnable</param-name> 
   <param-value>true</param-value> 
  </init-param> 
 </filter> 
 <filter-mapping> 
  <filter-name>druidWebStatFilter</filter-name> 
  <url-pattern>/*</url-pattern> 
 </filter-mapping>

 
druid、dbcp、c3p0区别及适用场景:
参考:https://blog.csdn.net/wawa3338/article/details/81380662
1.druid与c3p0、dbcp区别:
 druid被称为是专门为监控而生的数据库连接池配置,他可以监控sql的执行情况,以及性能,然后根据结果来优化sql或者做性能调优。若有这种监控需求可以选用druid。

2.c3p0与dbcp区别:

c3p0 dbcp
对数据连接的处理方式 提供最大空闲时间 提供最大连接数
什么时候连接挂断 当连接超过最大空闲连接时间时 当连接数超过最大连接数时
连接资源是否释放 自动回收连接 需要自己手动释放资源
效率 效率比较高
原理 维护多个连接对象Connection,在web项目要连接数据库时直接使用它维护的对象进行连接,省去每次都要创建连接对象的麻烦。提高效率和减少内存使用

3、使用org.springframework.jndi.JndiObjectFactoryBean
说明:JndiObjectFactoryBean 能够通过JNDI获取DataSource

<!--spring jnd连接池数据源配置-->
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean"> 
              <property name="jndiName"><value>java:comp/env/jdbc/roseindiaDB_local</value></property> 
 </bean> 
<!--tomcat resource配置, 默认采用dbcp-->
<Resource 
    name="oracleDataSource" 
    auth="Container" 
    type="javax.sql.DataSource" 
    maxActive="50" 
    maxIdle="10" 
    maxWait="10000" 
    username="lead_oams" 
    password="p" 
    driverClassName="oracle.jdbc.OracleDriver" 
    url="jdbc:oracle:thin:@192.168.1.229:1521:lead"/>

补充-c3p0配置各种数据库JNDI数据源示例(待续)

DBCP与C3P0配置项区别:

DBCP c3p0
用户名 username user username
密码 password password
URL url jdbcUrl
驱动类名 driverClassName driverClass driverClassName
<Context>
    <!-- 使用C3P0配置针对MySQL数据库的JNDI数据源 -->
    <Resource 
        name="jdbc/MysqlDataSource" 
        auth="Container"
        factory="org.apache.naming.factory.BeanFactory" 
        type="com.mchange.v2.c3p0.ComboPooledDataSource"
        driverClass="com.mysql.jdbc.Driver"
        idleConnectionTestPeriod="60"
        maxPoolSize="50" 
        minPoolSize="2"
        acquireIncrement="2" 
        user="root" 
        password="root"
        jdbcUrl="jdbc:mysql://192.168.1.144:3306/leadtest"/>
        
    <!-- 使用C3P0配置针对Oracle数据库的JNDI数据源 -->
    <Resource 
        name="jdbc/OracleDataSource" 
        auth="Container"
        factory="org.apache.naming.factory.BeanFactory" 
        type="com.mchange.v2.c3p0.ComboPooledDataSource"
        driverClass="oracle.jdbc.OracleDriver"
        idleConnectionTestPeriod="60"
        maxPoolSize="50" 
        minPoolSize="2"
        acquireIncrement="2" 
        jdbcUrl="jdbc:oracle:thin:@192.168.1.229:1521:lead"
        user="lead_oams"
        password="p"/>
        
        
    <!--使用C3P0配置针对SQLServer数据库的JNDI数据源-->
    <Resource 
        name="jdbc/SqlServerDataSource"
        auth="Container"
        factory="org.apache.naming.factory.BeanFactory" 
        type="com.mchange.v2.c3p0.ComboPooledDataSource"
        driverClass="com.microsoft.sqlserver.jdbc.SQLServerDriver"
        idleConnectionTestPeriod="60"
        maxPoolSize="50" 
        minPoolSize="2"
        acquireIncrement="2" 
        jdbcUrl="jdbc:sqlserver://192.168.1.51:1433;DatabaseName=demo"
        user="sa" 
        password="p@ssw0rd"/>
</Context>

拓展:spring+hibernate配置多个数据源以及使用
思路:配置多个数据源、多个SessionFactory及事务,获取对应的session来操作数据库。


 

配置sessionFactory

<!--Hibernate-->
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean" lazy-init="false">
        <!-- 注入datasource,给sessionfactoryBean内setdatasource提供数据源 -->
        <property name="dataSource" ref="dataSource" />
        <property name="configLocation" value="classpath:hibernate.cfg.xml"></property>
        <!-- //加载实体类的映射文件位置及名称 -->
        <property name="mappingLocations" value="classpath:com/demo/ssm/po/*.hbm.xml"></property>
 </bean>  

<!-- mybatis -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
      <property name="dataSource" ref="dataSource" />
	<!-- 自动扫描mapping.xml文件 -->
	<property name="mapperLocations" value="classpath:com/leon/ssm/mapper/*.xml"></property>
</bean>
<!-- DAO接口所在包名,Spring会自动查找其下的类 -->
	<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
		<property name="basePackage" value="com.leon.ssm.mapper" />
		<property name="sqlSessionFactoryBeanName"
			value="sqlSessionFactory"></property>
	</bean>

配置事务管理

     1.配置SessionFactory(见上)
     2.配置事务容器TransactionManager
     3.配置事务传播规则
     4.配置事务入口

(1)配置声明式事务

 <!-- 配置Spring声明式事务 -->
    <bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory"></property>
    </bean> 
    <!-- 配置事务事务传播属性 -->
     <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <tx:method name="save*" propagtion="REQUIRED"/>
            <tx:method name="*" />
        </tx:attributes>
    </tx:advice>
    <!-- 配置事务切点,并把切点和事务属性关联起来 -->
    <aop:config>
        <aop:pointcut id="txPointcut" expression="execution(* com.demo.ssm.daoImpl.*.*(..))" />
        <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/>
    </aop:config>
</beans>

(2)配置注解式事务

 <!--配置事物管理-->
    <bean id="transactionManager" class="org.springframework.orm.hibernate5.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory" />
    </bean>
 
    <!-- 配置注解方式管理事务 -->
    <tx:annotation-driven transaction-manager="transactionManager" />

(3)aop拦截器实现事务管理

<!-- aop代理 -->
    <bean id="transactionInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor">
        <!-- 设置事务管理其 -->
        <property name="transactionManager" ref="transactionManager" />
        <!--设置事物属性-->
        <property name="transactionAttributes">
            <props>
                <!-- 设置拦截方法,可以使用通配符 -->
                <!-- 可以设置事务的传播行为,隔离级别,多个值用逗号隔开 -->
                <prop key="transfer*">PROPAGATION_REQUIRED,ISOLATION_REPEATABLE_READ</prop>
                <prop key="add*">PROPAGATION_REQUIRED,ISOLATION_REPEATABLE_READ</prop>
                <prop key="insert*">PROPAGATION_REQUIRED,ISOLATION_REPEATABLE_READ</prop>
            </props>
        </property>
    </bean>
    <!-- 定义BeanNameAutoProxyCreatorf进行Spring的事务处理 -->
    <bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
        <!-- 针对指定的bean自动生成业务代理 -->
        <property name="beanNames" value="*Service" />
        <!-- 这个属性为true时,表示被代理的是目标类本身而不是目标类的接口[cglib] -->
        <property name="proxyTargetClass">
            <value>true</value>
        </property>
        <!-- 依赖注入上面定义的事务拦截器transactionInterceptor -->
        <property name="interceptorNames">
            <list>
                <value>transactionInterceptor</value>
            </list>
        </property>
    </bean>

补充-spring事务相关知识

事务传播行为

  • PROPAGATION_REQUIRED 如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。这是最常见的选择。
  • PROPAGATION_SUPPORTS 支持当前事务,如果当前没有事务,就以非事务方式执行。
  • PROPAGATION_MANDATORY 使用当前的事务,如果当前没有事务,就抛出异常。
  • PROPAGATION_REQUIRES_NEW 新建事务,如果当前存在事务,把当前事务挂起。
  • PROPAGATION_NOT_SUPPORTED 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
  • PROPAGATION_NEVER 以非事务方式执行,如果当前存在事务,则抛出异常。
  • PROPAGATION_NESTED 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作。

事务隔离级别

  • ISOLATION_DEFAULT:这是个 PlatfromTransactionManager 默认的隔离级别,使用数据库默认的事务隔离级别。
  • ISOLATION_READ_UNCOMMITTED:读未提交,允许另外一个事务可以看到这个事务未提交的数据。
  • ISOLATION_READ_COMMITTED:读已提交,保证一个事务修改的数据提交后才能被另一事务读取,而且能看到该事务对已有记录的更新。
  • ISOLATION_REPEATABLE_READ:可重复读,保证一个事务修改的数据提交后才能被另一事务读取,但是不能看到该事务对已有记录的更新。
  • ISOLATION_SERIALIZABLE:一个事务在执行的过程中完全看不到其他事务对数据库所做的更新。

补充-数据库事务特性
事务的特性
①原子性:是指事务是一个不可分割的工作单元,事务中的操作要么都发生,要么都不发生。
eg:张三给李四转钱,要么张三的钱减少李四的增多,要么两个人的钱都不变。
②一致性:是指事务前后数据的完整性要保持一致。
eg:本来 张三有1000元 李四有1000元 一共2000。张三给李四转账100元,成功:张三900元,李四1100元 一共2000元。
③隔离性:是指是指多个用户并发访问数据库的时候,一个用户的事务不能被其他用户的事务所干扰,多个并发事务之间数要相互隔离。
④持久性:是指一个事务一旦提交,他对数据库中数据的改变就是就是永久性的。
eg:张三 1000 李四 1000 张三给李四转100 张三提交了,数据回滚不了了

不考虑隔离性,会引发下列问题
①脏读:是指一个事务读到另一个事务未提交的数据
②不可重复读:在一个事务中,两次查询到的结果不一致(针对 update 操作)
③虚读(幻读):在一个事务中,两次查询到的结果不一致(针对 insert 操作)

通过设置事务隔离级别来解决读的问题
①读未提交(Read uncommitted):最低级别,上述情况都不能避免
②读已提交(Read committed):可避免 脏读 发生。Oracle默认隔离级别
③可重复读(Repeatable read):可避免 脏读、不可重复读 发生。Mysql默认隔离级别
④串行化(Serializable):可避免 脏读、不可重复读、虚读 发生


Spring实战-常用注解

参考:《springMVC详解以及注解说明》

@Autowired

 按类型自动装配:它可以对类成员变量、方法及构造函数进行标注,完成自动装配的工作。(在Spring 2.5 引入了 @Autowired 注释)
(1)对成员变量使用 @Autowired 后,可以省略set ,get方法。
(2)对方法或构造函数进行标注,将查找被标注的方法的入参类型的 Bean,并调用方法自动注入这些 Bean。

	 spring推荐在构造函数上注解,因为不考虑父类,初始化的顺序:静态变量或静态语句块–>实例变量或初始化语句块–>构造方法–>@Autowired。

特殊情况:
a.@Autowired(required = false),这等于告诉 Spring:在找不到匹配 Bean 时也不报错(一般在开发期才用)。
b.@Qualifier 注释指定注入 Bean 的名称,这样歧义就消除
@Autowired
@Qualifier(“userJdbcImps”)
private UserRepository userRepository;
c.类似JSR-250 规范定义的注释@Resource(详见让jsr-250生效的方法)

   与@Resource 区别:@Resource默认先按名称匹配,不依赖spring框架。

使用@Autowired的原理:
  其实在启动spring IoC时,容器自动装载了一个AutowiredAnnotationBeanPostProcessor后置处理器,当扫描到@Autowied、@Resource或@Inject时,就会在IoC容器自动查找需要的bean,并装配给该对象的属性

 <bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/>  

注意事项:
   在使用@Autowired时,首先在容器中查询对应类型的bean
    如果查询结果刚好为一个,就将该bean装配给@Autowired指定的数据
    如果查询的结果不止一个,那么@Autowired会根据名称来查找。
    如果查询的结果为空,那么会抛出异常。解决方法时,使用required=false

@PostConstruct 、@PreDestroy(JSR-250常见方法)

 标注了 @PostConstruct 注释的方法将在类实例化后调用,而标注了@PreDestroy的方法将在类销毁之前调用。

@Component

 @Component是通用标注,不推荐使, 定义Bean,在类定义处使用, 通过 @Scope 指定 Bean 的作用范围。
 @Component 有一个可选的入参,用于指定 Bean 的名称,在 Boss 中,我们就将 Bean 名称定义为“boss”。
注意:在使用 @Component 注释后,Spring 容器必须启用类扫描机制以启用注释驱动 Bean 定义和注释驱动 Bean 自动注入的策略。Spring 2.5 对 context 命名空间进行了扩展,提供了这一功能

<context:component-scan base-package="com.xxx.xx"/>

特殊语义的注释:@Controller、@Service、@Respository

 @Controller标注web控制器,@Service标注Servicec层的服务,@Respository标注DAO层的数据访问,他们包含@Component。

@Scope

 在使用XML 、注解定义Bean 时,可以通过bean 的scope 属性来定义一个Bean 的作用范围,默认是单例模式,即scope=“singleton”,效率较高。另外scope还有prototype、request、session、global session作用域。scope="prototype"多例,每次请求都新建一个实例,可防止输出之前请求返回值。

@RequestMapping (用于springMVC)

@RequestMapping是一个用来处理请求地址映射的注解,可用于类或方法上。用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径。
RequestMapping注解有六个属性:

1、 value, method;
value: 指定请求的实际地址,指定的地址可以是URI Template 模式(后面将会说明);
method: 指定请求的method类型, GET、POST、PUT、DELETE等;

2、 consumes,produces;
consumes: 指定处理请求的提交内容类型(Content-Type),例如application/json, text/html;
produces: 指定返回的内容类型,仅当request请求头中的(Accept)类型中包含该指定类型才返回;

3、 params,headers;
params: 指定request中必须包含某些参数值是,才让该方法处理。
headers: 指定request中必须包含某些指定的header值,才能让该方法处理请求。

@RequestParam

用于参数绑定,实例:
xxxMethod(@RequestParam(“id”)int itemId) 中的将 id 绑定到 itemId 这个 URL 参数上
其他参数绑定常用的注解:

  • A、处理requet uri 部分(这里指uri template中variable,不含queryString部分)的注解: @PathVariable;
  • B、处理request header部分的注解: @RequestHeader, @CookieValue;
  • C、处理request body部分的注解:@RequestParam, @RequestBody;
  • D、处理attribute类型是注解: @SessionAttributes, @ModelAttribute;

@ModelAttribute

  • @ModelAttribute 声明在属性上,表示该属性的value 来源于model里保存的数据,并被保存到model 里
  • @ModelAttribute 声明在方法上,表示该方法的返回值被保存到model 里

@RequestBody

 该注解用于读取Request请求的body部分数据,一般情况下来说常用其来处理application/json类型的请求数据。通过@requestBody可以将请求体中的JSON字符串绑定到相应的bean上,也可以将其分别绑定到对应的字符串上。
 例如说以下情况:

 $.ajax({
        url:"/login",
        type:"POST",
        data:'{"userName":"admin","pwd","admin123"}',
        content-type:"application/json charset=utf-8",
        success:function(data){
          alert("request success ! ");
        }
    });

    @requestMapping("/login")
    public void login(@requestBody String userName,@requestBody String pwd){
      System.out.println(userName+" :"+pwd);
    }

  这种情况是将JSON字符串中的两个变量的值分别赋予了两个字符串,但是呢假如我有一个User类,拥有如下字段:
      String userName;
      String pwd;
  那么上述参数可以改为以下形式:@requestBody User user 这种形式会将JSON字符串中的值赋予user中对应的属性上,需要注意的是,JSON字符串中的key必须对应user中的属性名,否则是请求不过去的。

@ResponseBody

 该注解用于将Controller的方法返回的对象,通过适当的HttpMessageConverter转换为指定格式后,写入到Response对象的body数据区。
 使用时机:返回的数据不是html标签的页面,而是其他某种格式的数据时(如json、xml等)使用, 比如开发rest接口返回json数据。

@Transient(用于ORM框架,如Hibernate)

表示该属性并非一个到数据库表的字段的映射,ORM框架将忽略该属性.

	区别java中的transient修饰符: 被transient的变量不能被序列化,一个静态变量不管是否被transient修饰,均不能被序列化。

总结:注解配置和 XML 配置的适用场合

  对于类级别且不会发生变动的配置可以优先考虑注释配置;而对于那些第三方类以及容易发生调整的配置则应优先考虑使用 XML 配置。
 合理地使用 Spring 2.5 的注释配置,可以有效减少配置的工作量,提高程序的内聚性。但是这并不意味着传统 XML 配置将走向消亡,在第三方类 Bean 的配置,以及那些诸如数据源、缓存池、持久层操作模板类、事务管理等内容的配置上,XML
配置依然拥有不可替代的地位。


Spring Boot

 springboot并不是什么新型的框架,而是整合了spring,springmvc等框架,默认了很多配置,从而减少了开发者的开发时间。
 虽然公司暂时没用它,但我觉得它应该是未来使用spring的趋势所在,应该提前接触一下。

Hello World

一、maven构建项目

1、访问http://start.spring.io/
2、选择构建工具Maven Project、Spring Boot版本1.3.6以及一些工程基本信息,点击“Switch to the full version.”java版本选择1.7,可参考下图所示:
在这里插入图片描述
3、点击Generate Project下载项目压缩包
4、解压后,使用eclipse,Import -> Existing Maven Projects -> Next ->选择解压后的文件夹-> Finsh,OK done!
项目结构介绍
在这里插入图片描述
如上图所示,Spring Boot的基础结构共三个文件:

src/main/java 程序开发以及主程序入口
src/main/resources 配置文件
src/test/java 测试程序

另外,spingboot建议的目录结构如下:

com
  +- example
    +- myproject
      +- Application.java
      |
      +- domain
      |  +- Customer.java
      |  +- CustomerRepository.java
      |
      +- service
      |  +- CustomerService.java
      |
      +- controller
      |  +- CustomerController.java
      |

Application.java 建议放到根目录下面,主要用于做一些框架配置
domain目录主要用于实体(Entity)与数据访问层(Repository)
service 层主要是业务类代码
controller 负责页面访问控制

采用默认配置可以省去很多配置,当然也可以根据自己的喜欢来进行更改
最后,启动Application main方法,至此一个java项目搭建好了!
 
二、引入web模块

1、pom.xml中添加支持web的模块:

<dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
 </dependency>

pom.xml文件中默认有两个模块:
spring-boot-starter :核心模块,包括自动配置支持、日志和YAML;
spring-boot-starter-test :测试模块,包括JUnit、Hamcrest、Mockito。

2、编写controller内容:

@RestController
public class HelloWorldController {
@RequestMapping("/hello")
public String index() {
return “Hello World”;
}
}

	@RestController 的意思就是controller里面的方法都以json格式输出,不用再写什么jackjson配置的了!(这个spring4才有,也可以用@Controller、@ResponeBody实现同样功能)

3、启动主程序,打开浏览器访问http://localhost:8080/hello,就可以看到效果了,有木有很简单!
 
三、如何做单元测试

 打开的src/test/下的测试入口,编写简单的http请求来测试;使用mockmvc进行,利用MockMvcResultHandlers.print()打印出执行结果。

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = MockServletContext.class)
@WebAppConfiguration
public class HelloWorldControlerTests {
    private MockMvc mvc;
    @Before
    public void setUp() throws Exception {
        mvc = MockMvcBuilders.standaloneSetup(new HelloWorldController()).build();
    }
    @Test
    public void getHello() throws Exception {
    mvc.perform(MockMvcRequestBuilders.get("/hello").accept(MediaType.APPLICATION_JSON))
                .andExpect(MockMvcResultMatchers.status().isOk())
                .andDo(MockMvcResultHandlers.print())
                .andReturn();
    }
}

四、开发环境的调试

 热启动在正常开发项目中已经很常见了吧,虽然平时开发web项目过程中,改动项目启重启总是报错;但springBoot对调试支持很好,修改之后可以实时生效,需要添加以下的配置:

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
        <optional>true</optional>
    </dependency>
</dependencies>
 
<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <configuration>
                <fork>true</fork>
            </configuration>
        </plugin>
</plugins>
</build>

 该模块在完整的打包环境下运行的时候会被禁用。如果你使用java -jar启动应用或者用一个特定的classloader启动,它会认为这是一个“生产环境”。

总结:SpringBoot继承了spring之前所有的优点,简化了使用Spring的过程,简直是广大程序员的福音~:)

参考:SpringBoot从入门到精通教程
 
后记: 花了2个多小时,简单总结了一下spring,算是自我巩固一下基础吧。

Thank you for reading.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章