7

图片 3
  1. 声明式

图片 1
    1. ApplicationContext它是扩展BeanFactory接口;
    2.
BeanFactory它采取延迟加载的方案,只有真正在getBean时才会实例化Bean在开发中我们一般使用的是
ApplicationContext,
  
真正使用的是其实现类,FileSystemXmlAppliCationContext根据文件路径获取,ClassPathXmlApplicationContext
根据类路径获
   取;
    3.
AppliCationContext它会在配置文件加载时,就会初始化Bean并且ApplicationContext它提供不同的应用层的Context实现。
五、Bean的作用域
    在bean声明时它有一个scope(作用域)属性,它是用于描述bean的作用域。
        可取值有:
        singleton:单例 代表在spring
ioc容器中只有一个Bean实例(默认的scope)
        prototype 多例
每一次从spring容器中获取时,都会返回一个新的实例
        request
用在web开发中,将bean对象request.setAttribute()存储到request域中
        session
用在web开发中,将bean对象session.setAttribute()存储到session域中
    在开如常用的值是singleton与prototype。
六、Bean的生命周期

对于纯JDBC操作数据库,想要用到事务,可以按照以下步骤进行:

public Object invoke(final MethodInvocation invocation) throws Throwable { Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis : null); // Adapt to TransactionAspectSupport's invokeWithinTransaction... return invokeWithinTransaction(invocation.getMethod(), targetClass, new InvocationCallback() { @Override public Object proceedWithInvocation() throws Throwable { return invocation.proceed; }

图片 2
  (1)核心容器(Core Container)
    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,它也支持列表投影、选
  择和一般的列表聚合等。
 (2)数据访问/
集成部分(Data Access/Integration)
  
 1:JDBC模块,提供对JDBC的抽象,它可消除冗长的JDBC编码和解析数据库厂商特有的错误代码。
    2:ORM模块,提供了常用的”对象/关系”映射API的集成层。
其中包括JPA、JDO、Hibernate和iBatis 。利用ORM封装包,可以混
  合使用所有Spring提供的特性进行”对象/关系”映射,如简单声明性 事务管理

  
 3:OXM模块,提供一个支持Object和XML进行映射的抽象层,其中包括JAXB、Castor、XMLBeans、JiBX
和 XStream。
    4:JMS模块,提供一套”消息生产者、消费者”模板用于更加简单的使用
JMS,JMS 用于在两个应用程序之间,或分布式系统中发
  送消息,进行异步通信。
  
 5:Transaction模块,支持程序通过简单声明性事务管理,只要是Spring管理对象都能得到Spring管理事务的好处,即使是POJO,
  也可以为他们提供事务。
 (3)Web
    1:Web-Socket模块,WebSocket
protocol是HTML5一种新的协议。它实现了浏览器与服务器全双工通信,spring支持webSocket通信。
  
 2:Web模块,提供了基础的web功能。例如多文件上传、集成IOC容器、远程过程访问、以及Web
Service支持,并提供一个
  RestTemplate类来提供方便的Restful services访问
  
 3:Web-Servlet模块,提供了Web应用的Model-View-ControllerMVC)实现。Spring
MVC框架提供了基于注解的请求资源注入、更
 
简单的数据绑定、数据验证等及一套非常易用的JSP标签,完全无缝与Spring其他技术协作。
    4: Web-Portlet模块,提供了在Portlet环境下的MVC实现。
 (4)AOP
  
 1:AOP模块,提供了符合AOP联盟规范的面向方面的编程实现,让你可以定义如方法拦截器和切入点,从逻辑上讲,可以减弱代码
 
的功能耦合,清晰的被分离开。而且利用源码级的元数据功能,还可以将各种行为信息合并到你的代码中

    2:Aspects模块,提供了对AspectJ的集成。
    3:Instrumentation模块,
提供一些类级的工具支持和ClassLoader级的实现,可以在一些特定的应用服务器中使用。
 (5)Test
  
 Test模块,提供对使用JUnit和TestNG来测试Spring组件的支持,它提供一致的ApplicationContexts并缓存这些上下文,它还能
  提供一些mock对象,使得你可以独立的测试代码。
三、Spring的优点
    方便解耦,简化开发
     
Spring就是一个大工厂,可以将所有对象创建和依赖关系维护,交给Spring管理;
    AOP 编程的支持
     
Spring提供面向切面编程,可以方便的实现对程序进行权限拦截、运行监控等功能
    声明式事务的支持
      只需要通过配置就可以完成对事务的管理,而无需手动编程
    方便程序的测试
     
Spring对Junit4支持,可以通过注解方便的测试Spring程序方便集成各种优秀框架Spring不排斥各种优秀的开源框架,其内部
    提供了对各种优秀框架(如:Struts、Hibernate、MyBatis、Quartz
等)的直接支持;
    降低JavaEE API的使用难度  
      Spring对
JavaEE开发中非常难用的一些API(JDBC、JavaMail、远程调用等),都提供了封装,使这些API应用难度大大降低。
四、ApplicationContext文件与BeanFactory类

2、基础

  • 基于事务管理器API 的编程式事务管理
  • 基于TransactionTemplate 的编程式事务管理

 

ApplicationContext:容器

  • 基于 TransactionProxyFactoryBean的声明式事务管理
  • 基于 <tx> 和 <aop> 命名空间的事务管理
  • 基于 @Transactional 的声明式事务管理

          Hibernate 开发
          

PROPAGATION_REQUIRES_NEW:新建事务,如果当前存在事务,把当前事务挂起。

Spring的事务是通过AOP代理类中的一个Advice(TransactionInterceptor)进行生效的,而传播级别定义了事务与子事务获取连接、事务提交、回滚的具体方式。

Connection con=……;
con.setAutoCommit(false);//开启事务
con.rollback();
con.commit();

如果目标对象的实现类实现了接口,Spring AOP 将会采用 JDK 动态代理来生成
AOP 代理类;

TransactionAspectSupport

 

CGLIB

但如果修改为CGLIB代理时则会成功注入,所以如果有接口,建议注入时该类属性都定义为接口。另外事务切点都配置在实现类和接口都可以生效,但建议加在实现类上。官网关于Spring
AOP的详细介绍

          PlatformTransactionManager 接口API
          DataSourceTransactionManager
主要针对于JdbcTemplate开发MyBatis开发;
          HibernateTransactionManasger 主要针对于Hibernate开发;
          JpaTransactionManager 主要针对于JPA开发。
        (2)TransactionDefinition
         
它描述的是事务的定义信息,在TransactionDefinition中定义了大量的常量。
    8.1 隔离
        事务的四个特性:ACID原子性、一致性、隔离性、持久性。
        脏读,不可重复读 虚读。
            ISOLATION_DEFUALT 它使用后端数据库的默认隔离级别(spring
中选项)
            ISOLATION_READ_UNCOMMITTED 不能解决问题,会发生脏读
不可重复读 虚读
            ISOLATION_READ_COMMITTED 可以解决脏读
会产生不可重复读与虚读。
            ISOLATION_REPEATABLE_READ 可以解决脏读,不可重复读
解决不了虚读
            ISOLATION_SERIALIZABLE 串行化,可以解决所有问题
        对于不现的数据库,它的底层默认事务隔离级别不一样。
            Oracle 数据库它默认的是 read_committed
            Mysql 数据库它默认的是 repeatable_read.
    8.2 超时
        默认值是-1它使用的是数据库默认的超时时间。
    8.3 只读
        它的值有两个true/false,如果选择true一般是在select操作时
    8.4 传播
      
 解决的是两个被事务管理的方法互相调用问题。它与数据库没关系,是程序内部维护的问题。其中:
           PROPAGATION_REQUIRED 默认值
两个操作处于同一个事务,如果之前没有事务,新建一个事务;
           PROPAGATION_REQUIRES_NEW两个操作处于不同的事务;
           PROPAGATION_NESTED是一种嵌套事务,它是使用 SavePoint
来实现的。事务回滚时可以回滚到指定的savepoint,
         注意:它只对DataSourceTransactionManager有作用;
           PROPAGATION_SUPPORTS
支持当前事务,如果不存在,就不使用事务;
           PROPAGATION_MANDATORY 支持当前事务,如果不存在,抛出异常;
           PROPAGATION_NOT_SUPPORTED
以非事务运行,如果有事务存在,挂起当前事务;
           PROPAGATION_NEVER 以非事务运行,如果有事务存在,抛出异常;
    8.5 TransactionStatus
        定义了事务状态信息,在事务运行过程中,得到某个时间点的状态。
    8.6 声明式事务管理
     (1)事务管理方式
        1. 编码方案
不建议使用,它具有侵入性。在原有的业务代码基础上去添加事务管理代码。
        2. 声明式事务控制,基于 AOP 对目标进行代理,添加 around
环绕通知。
        这种方案,它不具有侵入性,不需要修改原来的业务代码
     (2)基于xml配置声明式事务管理方案
        第一步:在applicationContext.xml文件中添加aop与tx的名称空间
        第二步:在applicationContext.xml件中配置
        Spring提供的advice是传统的 spring advice
          1. 声明事务管理器
          2. 配置通知
            
Spring为我们提供了一个ransactionInterceptor来完成增强对于这个增强,我们可以使用spring为我们提供的一个标签
          <tx:advice>来完成操作
          3. 配置切面
            
因为使用的是传统的Spring的Advice,需要使用<aop:advisor>。
     (3)基于Annotation声明式事务管理方案
          可以使用@Transaction来在类或方法上添加声明式事务管理。
            注意:需要在
applicationContext.xml 文件中使用相当于开启注解事务控制。

1)首先用户发送请求给DispatcherServlet(前端控制器):接收请求,响应结果,相当于转发器,中央处理器。;

在了解Spring代理的两种特点后,我们也就知道在做事务切面配置时的一些注意事项,例如JDK代理时方法必须是public,CGLIB代理时必须是public、protected,且类不能是final的;在依赖注入时,如果属性类型定义为实现类,JDK代理时会报如下注入异常:

一、Spring简述
  
 Spring是一个分层的JavaSE/EEfull-stack(一站式)轻量级开源框架,Spring致力于提供一种方法管理你的业务对象,Spring的主要
目的是使JavaEE易用和促进好编程习惯,Spring致力于J2EE应用的各层的解决方案,而不是仅仅专注于某一层的方案,Spring贯穿表现
层、业务层及持久层。然而,Spring并不想取代那些已有的框架,而是与它们无缝地整合。
二、Spring体系结构
  
 Spring框架是一个分层架构,它包含一系列的功能要素并被分为大约20个模块。这些模块分为Core
Container、Data Access/Integration
Web、AOP(Aspect Oriented Programming)、Instrumentation和测试部分;

2、SpringMVC

  1. 编程式
 Session session=….;
 Transaction t=session.beginTransaction();
 t.commit();
 t.rollback();

需要面向接口,产生代理对象,因此真实实现类必须实现了接口才可以。代理的只是接口中的方法

三、Spring事务的那些坑

通过之前章节,相信您已经掌握了spring事务的使用方式与原理,不过还是要注意,因为一不小心就可能就掉坑。首先看第一个坑:

测试代码,事务AOP配置:

<tx:advice transaction-manager="myTxManager"> <tx:attributes> <!-- 指定在连接点方法上应用的事务属性 --> <tx:method name="openAccount" isolation="DEFAULT" propagation="REQUIRED"/> <tx:method name="openStock" isolation="DEFAULT" propagation="REQUIRED"/> <tx:method name="openStockInAnotherDb" isolation="DEFAULT" propagation="REQUIRES_NEW"/> <tx:method name="openTx" isolation="DEFAULT" propagation="REQUIRED"/> <tx:method name="openWithoutTx" isolation="DEFAULT" propagation="NEVER"/> <tx:method name="openWithMultiTx" isolation="DEFAULT" propagation="REQUIRED"/> </tx:advice>

public class StockProcessServiceImpl implements IStockProcessService{@Autowired private IAccountDao accountDao; @Autowired private IStockDao stockDao; @Override public void openAccount(String aname, double money) { accountDao.insertAccount(aname, money); } @Override public void openStock(String sname, int amount) { stockDao.insertStock(sname, amount); } @Override public void openStockInAnotherDb(String sname, int amount) { stockDao.insertStock(sname, amount);}}public void insertAccount(String aname, double money) { String sql = "insert into account(aname, balance) values"; this.getJdbcTemplate().update(sql, aname, money); DbUtils.printDBConnectionInfo("insertAccount",getDataSource;} public void insertStock(String sname, int amount) { String sql = "insert into stock(sname, count) values "; this.getJdbcTemplate().update(sql , sname, amount); DbUtils.printDBConnectionInfo("insertStock",getDataSource;} public static void printDBConnectionInfo(String methodName,DataSource ds) { Connection connection = DataSourceUtils.getConnection; System.out.println(methodName+" connection hashcode="+connection.hashCode; }

//调用同类方法,外围配置事务 public void openTx(String aname, double money) { openAccount(aname,money); openStock; }

1.运行输出:insertAccount connection hashcode=319558327insertStock
connection hashcode=319558327

//调用同类方法,外围未配置事务 public void openWithoutTx(String aname, double money) { openAccount(aname,money); openStock; }

2.运行输出:insertAccount connection hashcode=1333810223insertStock
connection hashcode=1623009085

//通过AopContext.currentProxy()方法获取代理 @Overridepublic void openWithMultiTx(String aname, double money) { openAccount(aname,money); openStockInAnotherDb(aname, 11);//传播级别为REQUIRES_NEW }

3.运行输出:insertAccount connection hashcode=303240439insertStock
connection hashcode=303240439

可以看到2、3测试方法跟我们事务预期并一样,结论:调用方法未配置事务、本类方法直接调用,事务都不生效!究其原因,还是因为Spring的事务本质上是个代理类,而本类方法直接调用时其对象本身并不是织入事务的代理,所以事务切面并未生效。具体可以参见#Spring事务实现机制#章节。Spring也提供了判断是否为代理的方法:

public static void printProxyInfo(Object bean) { System.out.println("isAopProxy"+AopUtils.isAopProxy; System.out.println("isCGLIBProxy="+AopUtils.isCGLIBProxy; System.out.println("isJdkProxy="+AopUtils.isJdkDynamicProxy; }

那如何修改为代理类调用呢?最直接的想法是注入自身,代码如下:

 @Autowired private IStockProcessService stockProcessService;//注入自身类,循环依赖,亲测可以 public void openTx(String aname, double money) { stockProcessService.openAccount(aname,money); stockProcessService.openStockInAnotherDb ; }

当然Spring提供了获取当前代理的方法:代码如下:

//通过AopContext.currentProxy()方法获取代理 @Override public void openWithMultiTx(String aname, double money) {((IStockProcessService)AopContext.currentProxy.openAccount(aname,money);((IStockProcessService)AopContext.currentProxy.openStockInAnotherDb(aname, 11); }

另外Spring是通过TransactionSynchronizationManager类中线程变量来获取事务中数据库连接,所以如果是多线程调用或者绕过Spring获取数据库连接,都会导致Spring事务配置失效。最后Spring事务配置失效的场景:

  1. 事务切面未配置正确
  2. 本类方法调用
  3. 多线程调用
  4. 绕开Spring获取数据库连接

接下来我们看下Spring的事务的另外一个坑:

测试代码:

<tx:advice transaction-manager="myTxManager"> <tx:attributes> <!-- 指定在连接点方法上应用的事务属性 --> <tx:method name="buyStock" isolation="DEFAULT" propagation="REQUIRED"/> </tx:attributes> </tx:advice>

public void buyStock(String aname, double money, String sname, int amount) throws StockException { boolean isBuy = true; accountDao.updateAccount(aname, money, isBuy); // 故意抛出异常 if  { throw new StockException; } stockDao.updateStock(sname, amount, isBuy); }

 @Test public void testBuyStock() { try { service.openAccount("dcbs", 10000); service.buyStock("dcbs", 2000, "dap", 5); } catch (StockException e) { e.printStackTrace(); } double accountBalance = service.queryAccountBalance; System.out.println("account balance is " + accountBalance); }

输出结果:insertAccount connection hashcode=656479172updateAccount
connection hashcode=517355658account balance is 8000.0

应用抛出异常,但accountDao.updateAccount却进行了提交。究其原因,直接看Spring源代码:TransactionAspectSupport

protected void completeTransactionAfterThrowing(TransactionInfo txInfo, Throwable ex) { if (txInfo != null && txInfo.hasTransaction { if (logger.isTraceEnabled { logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() + "] after exception: " + ex); } if (txInfo.transactionAttribute.rollbackOn { try { txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus; } catch (TransactionSystemException ex2) { logger.error("Application exception overridden by rollback exception", ex); ex2.initApplicationException; throw ex2; } …}public class DefaultTransactionAttribute extends DefaultTransactionDefinition implements TransactionAttribute {@Override public boolean rollbackOn(Throwable ex) { return (ex instanceof RuntimeException || ex instanceof Error); }…}

由代码可见,Spring事务默认只对RuntimeException和Error进行回滚,如果应用需要对指定的异常类进行回滚,可配置rollback-for=属性,例如:

 <!-- 注册事务通知 --> <tx:advice transaction-manager="myTxManager"> <tx:attributes> <!-- 指定在连接点方法上应用的事务属性 --> <tx:method name="buyStock" isolation="DEFAULT" propagation="REQUIRED" rollback-for="StockException"/> </tx:attributes> </tx:advice>

事务不回滚的原因:

  1. 事务配置切面未生效
  2. 应用方法中将异常捕获
  3. 抛出的异常不属于运行时异常(例如IOException),
  4. rollback-for属性配置不正确

接下来我们看下Spring事务的第三个坑:

测试代码:

<!-- 注册事务通知 --> <tx:advice transaction-manager="myTxManager"> <tx:attributes> <tx:method name="openAccountForLongTime" isolation="DEFAULT" propagation="REQUIRED" timeout="3"/> </tx:attributes> </tx:advice>

@Override public void openAccountForLongTime(String aname, double money) { accountDao.insertAccount(aname, money); try { Thread.sleep;//在数据库操作之后超时 } catch (InterruptedException e) { e.printStackTrace(); } }

 @Test public void testTimeout() { service.openAccountForLongTime("dcbs", 10000); }

正常运行,事务超时未生效

public void openAccountForLongTime(String aname, double money) { try { Thread.sleep; //在数据库操作之前超时 } catch (InterruptedException e) { e.printStackTrace(); } accountDao.insertAccount(aname, money); }

抛出事务超时异常,超时生效org.springframework.transaction.TransactionTimedOutException:
Transaction timed out: deadline was Fri Nov 23 17:03:02 CST 2018at
org.springframework.transaction.support.ResourceHolderSupport.checkTransactionTimeout(ResourceHolderSupport.java:141)…

通过源码看看Spring事务超时的判断机制:ResourceHolderSupport

/** * Return the time to live for this object in milliseconds. * @return number of millseconds until expiration * @throws TransactionTimedOutException if the deadline has already been reached */ public long getTimeToLiveInMillis() throws TransactionTimedOutException{ if (this.deadline == null) { throw new IllegalStateException("No timeout specified for this resource holder"); } long timeToLive = this.deadline.getTime() - System.currentTimeMillis(); checkTransactionTimeout(timeToLive <= 0); return timeToLive; } /** * Set the transaction rollback-only if the deadline has been reached, * and throw a TransactionTimedOutException. */ private void checkTransactionTimeout(boolean deadlineReached) throws TransactionTimedOutException { if (deadlineReached) { setRollbackOnly(); throw new TransactionTimedOutException("Transaction timed out: deadline was " + this.deadline); } }

通过查看getTimeToLiveInMillis方法的Call
Hierarchy,可以看到被DataSourceUtils的applyTimeout所调用,
继续看applyTimeout的Call
Hierarchy,可以看到有两处调用,一个是JdbcTemplate,一个是TransactionAwareInvocationHandler类,后者是只有TransactionAwareDataSourceProxy类调用,该类为DataSource的事务代理类,我们一般并不会用到。难道超时只能在这调用JdbcTemplate中生效?写代码亲测:

 <!-- 注册事务通知 --> <tx:advice transaction-manager="myTxManager"> <tx:attributes> <tx:method name="openAccountForLongTimeWithoutJdbcTemplate" isolation="DEFAULT" propagation="REQUIRED" timeout="3"/> </tx:attributes> </tx:advice>

 public void openAccountForLongTimeWithoutJdbcTemplate(String aname, double money) { try { Thread.sleep; } catch (InterruptedException e) { e.printStackTrace(); } accountDao.queryAccountBalanceWithoutJdbcTemplate; } public double queryAccountBalanceWithoutJdbcTemplate(String aname) { String sql = "select balance from account where aname = ?"; PreparedStatement prepareStatement; try { prepareStatement = this.getConnection().prepareStatement; prepareStatement.setString; ResultSet executeQuery = prepareStatement.executeQuery(); while(executeQuery.next { return executeQuery.getDouble; } } catch (CannotGetJdbcConnectionException | SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } return 0; }

运行正常,事务超时失效

由上可见:Spring事务超时判断在通过JdbcTemplate的数据库操作时,所以如果超时后未有JdbcTemplate方法调用,则无法准确判断超时。另外也可以得知,如果通过Mybatis等操作数据库,Spring的事务超时是无效的。鉴于此,Spring的事务超时谨慎使用。

JDBC规范中Connection
的setAutoCommit是原生控制手动事务的方法,但传播行为、异常回滚、连接管理等很多技术问题都需要开发者自己处理,而Spring事务通过AOP方式非常优雅的屏蔽了这些技术复杂度,使得事务管理变的异常简单。但凡事有利弊,如果对实现机制理解不透彻,很容易掉坑里。最后总结下Spring事务的可能踩的坑:

  1. Spring事务未生效a) 调用方法本身未正确配置事务b) 本类方法直接调用c)
    数据库操作未通过Spring的DataSourceUtils获取Connectiond) 多线程调用
  2. Spring事务回滚失效a) 未准确配置rollback-for属性b)
    异常类不属于RuntimeException与Errorc) 应用捕获了异常未抛出
  3. Spring事务超时不准确或失效a)
    超时发生在最后一次JdbcTemplate操作之后b)
    通过非JdbcTemplate操作数据库,例如Mybatis

图片 3
    1. instantiate bean 对象实例化;
    2. populate properties 封装属性;
    3. 如果 Bean 实现 BeanNameAware 执行 setBeanName;
    4. 如果 Bean 实现 BeanFactoryAwar 或 ApplicationContextAwar 设置工厂
setBeanFactory 或上;
       下文对象 setApplicationContext;
    5. 如果存在类实现 BeanPostProcess(后处理 Bean),执行
postProcessBeforeInitialization;
    6. 如果 Bean 实现 InitializingBean 执行 afterPropertiesSet;
    7. 调用自定义的 init-method 方法;
    8. 如果存在类实现 BeanPostProcessor(处理 Bean),执行
postProcessAfterInitialization;
    9. 执行业务处理;
    10. 如果 Bean 实现 DisposableBean 执行 destroy;
    11. 调用自定义的 destroy-method;
七、AOP
    1. 简述
      
 AOP(面向切面编程)通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是(面向对象编程)的延续,
  
 是软件是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使
  
 得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
      
 AOP是一个概念,并没有设定具体语言的实现,它能克服那些只有单继承特性语言的缺点,spring2.0之后整合AspectJ第三
  
 方AOP技术。AspectJ是一个面向切面的框架,它扩展了Java语言。AspectJ定义了AOP语法所以它有一个专门的编译器用来生成遵
    守Java字节编码规范的Class文件。
      1.1 主要功能
          日志记录,性能统计,安全控制,事务处理,异常处理等等
      1.2 主要意图
         
将日志记录,性能统计,安全控制,事务处理,异常处理等代码从业务逻辑代码中划分出来,通过对这些行为的分离,我
     
们希望可以将它们独立到非指导业务逻辑的方法中,进而改变这些行为的时候不影响业务逻辑的代码。
    2. AOP与OOP区别
      
OOP针对业务处理过程的实体及其属性和行为进行抽象封装,以获得更加清晰高效的逻辑单元划分。而AOP则是针对业务处理过
  
 程中的切面进行提取,它所面对的是处理过程中的某个步骤或阶段,以获得逻辑过程中各部分之间低耦合性的隔离效果。这两种
    设计思想在目标上有着本质的差异。
    3. 相关术语
      3.1 目标对象(target)
         
指的是需要被增强的对象,由于aop是通过代理模式实现,从而这个对象永远是被代理对象。
      3.2 连接点(join point)
         
所谓连接点是指那些被拦截到的点,在spring中这些点指的是方法,spring只支持方法类型的连接点。
      3.3 切入点(pointcut)
          表示一组joint point,这些joint
point或是通过逻辑关系组合起来,或是通过通配、正则表达式等方式集中起来,它定
     
义了相应的Advice将要发生的地方简单说切入点是指我们要对哪些连接点进行拦截的定义。
      3.4 通知(advice)
         
所谓通知是指拦截到连接点之后所要做的事情就是通知,通知分为前置通知,后置通知,异常通知,最终通知,环绕通知
      Advice定义了在pointcut里面定义的程序点具体要做的操作。
      3.5 引介(introduction)
         
引介是一种特殊的通知,在不修改类代码的前提下,introduction可以在运行期为类动态地添加一些方法或属性。
      3.6 切面(aspect)
          是切入点和通知的结合。
      3.7 织入(weaving)
         
织入是一个过程,是将切面应用到目标对象从而创建出AOP代理对象的过程,织入可以在编译期,类装载期,运行期进行。
      Spring采用动态织入,而aspectj采用静态织入。
      3.8 代理(Proxy)
          一个类被AOP织入增强后,就产生一个结果代理类。
    4.AOP的动态代理
      
 AOP的底层实现就是动态代理,一般AOP分为静态AOP和动态AOP。静态AOP是指AspectJ实现的AOP,他是将切面代码直接编译到
    Java类文件中。动态
AOP是指将切面代码进行动态织入实现的AOP。Spring的AOP为动态AOP,实现的技术为:JDK提供的动态代理
    技术和CGLIB(动态字节码增强技术)。
      4.1 JDK动态代理
          在JVM运行时,内部动态生成class字节码对象(即Class 对象),注:JDK动态代理只针对于接口操作。
      4.2 CGLIB动态代理
         
CGLIB是一个开源项目是一个高性能,高质量的Code生成类库,它可以在运行期扩展Java类与实现Java接口。CGLIB包的底
     
层是通过使用一个小而快的字节码处理框架ASM,来转换字节码并生成新的类,单独使用CGLIB,那么需要导入CGLIB的jar包还
      需要一个asm相关jar包,但是spring框架的spring-core.jar
包中已经集成了CGLIB与asm。
         
注意:JDK动态代理只可以为接口去完成操作,而CGLIB动态代理可以为没有实现接口的类去做代理,也可以为实现接口的类
     
去做代理。CGLIB动态代理它可以为没有实现接口的类做代理,也可以为接口类做代理。
     
如果目标对象,有接口,优先使用:JDK动态代理只,如果目标对象,无接口,使用CGLIB动态代理。
    5.AOP的传统编程
        在传统的Spring AOP开发中它支持增强(advice)有五种:
            1. 前置通知
目标方法执行前增强org.springframework.aop.MethodBeforeAdvice;
            2. 后置通知
目标方法执行后增强org.springframework.aop.AfterReturningAdvice;
            3. 环绕通知
目标方法执行前后进行增强org.aopalliance.intercept.MethodInterceptor;
            4. 异常抛出通知
目标方法抛出异常后的增强org.springframework.aop.ThrowsAdvice;
            5. 引介通知
在目标类中添加一些新的方法或属性org.springframework.aop.IntroductionInterceptor;
    6.Spring
整合aspectj框架实现AOP
        Aspect:切面 =切点+通知(多个切点与多个通知的组合)
        AspectJ它是一个第三方框架,spring 从 2.0 后可以使用 aspectJ
框架的部分语法。
        AspectJ框架它定义的通知类型有六种:
            1. 前置通知 Before相当于BeforeAdvice;
            2. 后置通知 AfterReturning相当于AfterReturningAdvice;
            3. 环绕通知 Around相当于MethodInterceptor;
            4. 抛出通知 AfterThrowing相当于ThrowAdvice;
            5. 引介通知 DeclareParents相当于IntroductionInterceptor;
            6. 最终通知
After不管是否异常,该通知都会执行,相比Spring的传统AOP
Advice多了一个最终通知。
八、Spring的事务管理
    Spring的事务管理的四个优点:
      1. 提供一致的对于不同的事务管理的 API;
      2. 支持声明式事务管理;
      3. 编程事务管理;
      4. 优秀的整合与Spring的数据访问:
    Spring的事务管理主要提供了三个接口来完成:
      1. org.springframework.transaction.PlatformTransactionManager
        这是一个事务管理器,可以来选择相关的平台(jdbc hibernate jpa…)
      2. TransactionDefinition
        它定义事务的一些相关信息 例如:隔离、传播、超时、只读
      3. TransactionStatus
        (1)PlatformTransactionManager
          平台事务管理器,在不同的持久化层解决技术它的事务代码不一样。
          JDBC 开发
           

模板方法:父类定义方法的整体执行流程,具体的实现交给子类。很多抽象类中都用到了。

在事务管理器类AbstractPlatformTransactionManager中,getTransaction获取事务时,会处理不同的事务传播行为,例如当前存在事务,但调用方法事务传播级别为REQUIRES_NEW、PROPAGATION_NOT_SUPPORTED时,对当前事务进行挂起、恢复等操作,以此保证了当前数据库操作获取正确的Connection。具体是在子事务提交的最后会将挂起的事务恢复,恢复时重新调用TransactionSynchronizationManager.
bindResource设置之前的connection
holder,这样再获取的连接就是被恢复的数据库连接,
TransactionSynchronizationManager当前激活的连接只能是一个。AbstractPlatformTransactionManager

Spring:

接下来我们详细看下Spring事务的源代码,进而了解其工作原理。我们从<tx>标签的解析类开始:

5)关闭连接 conn.close();

至此我们了解事务的整个调用流程,但还有一个重要的机制没分析到,那就是Spring
事务针对不同的传播级别控制当前获取的数据库连接。接下来我们看下Spring获取连接的工具类DataSourceUtils,JdbcTemplate、Mybatis-Spring也都是通过该类获取Connection。

3、事务

目前大部分项目使用的是声明式的后两种:基于 <tx> 和 <aop>
命名空间的声明式事务管理可以充分利用切点表达式的强大支持,使得管理事务更加灵活。基于
@Transactional 的方式需要实施事务管理的方法或者类上使用 @Transactional
指定事务规则即可实现事务管理,在Spring
Boot中通常也建议使用这种注解方式来标记事务。

which might an XML file, properties file, or relational database schema.

protected Object invokeWithinTransaction(Method method, Class<?> targetClass, final InvocationCallback invocation) throws Throwable { // If the transaction attribute is null, the method is non-transactional. final TransactionAttribute txAttr = getTransactionAttributeSource().getTransactionAttribute(method, targetClass); final PlatformTransactionManager tm = determineTransactionManager; final String joinpointIdentification = methodIdentification(method, targetClass, txAttr); if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) { // Standard transaction demarcation with getTransaction and commit/rollback calls. TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification); Object retVal = null; try { // This is an around advice: Invoke the next interceptor in the chain. // This will normally result in a target object being invoked. retVal = invocation.proceedWithInvocation(); } catch (Throwable ex) { // target invocation exception completeTransactionAfterThrowing(txInfo, ex); throw ex; } finally { cleanupTransactionInfo; } commitTransactionAfterReturning; return retVal; }}

2)开启事务con.setAutoCommit(true/false);

public class DefaultAopProxyFactory implements AopProxyFactory, Serializable { @Override public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException { if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces { Class<?> targetClass = config.getTargetClass(); if (targetClass == null) { throw new AopConfigException("TargetSource cannot determine target class: " + "Either an interface or a target is required for proxy creation."); } if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) { return new JdkDynamicAopProxy; } return new ObjenesisCGLIBAopProxy; } else { return new JdkDynamicAopProxy; } }}

AOP(Aspect Oriented Programming),即面向切面编程。Spring
AOP技术实现上其实就是代理类,具体可分为静态代理和动态代理两大类,其中静态代理是指使用
AOP 框架提供的命令进行编译,从而在编译阶段就可生成 AOP
代理类,因此也称为编译时增强;;而动态代理则在运行时借助于
默写类库在内存中“临时”生成 AOP
动态代理类,因此也被称为运行时增强。其中java是使用的动态代理模式
(JDK+CGLIB)。JDK动态代理
JDK动态代理主要涉及到java.lang.reflect包中的两个类:Proxy和InvocationHandler。InvocationHandler是一个接口,通过实现该接口定义横切逻辑,并通过反射机制调用目标类的代码,动态将横切逻辑和业务逻辑编制在一起。
Proxy利用InvocationHandler动态创建一个符合某一接口的实例,生成目标类的代理对象。CGLIB动态代理
CGLIB全称为Code Generation
Library,是一个强大的高性能,高质量的代码生成类库,可以在运行期扩展Java类与实现Java接口,CGLIB封装了asm,可以再运行期动态生成新的class。
和JDK动态代理相比较:JDK创建代理有一个限制,就是只能为接口创建代理实例,而对于没有通过接口定义业务方法的类,则可以通过CGLIB创建动态代理。CGLIB
创建代理的速度比较慢,但创建代理后运行的速度却非常快,而 JDK
动态代理正好相反。如果在运行的时候不断地用 CGLIB
去创建代理,系统的性能会大打折扣。 因此如果有接口,Spring默认使用JDK
动态代理,源代码如下:

2)DispatcherServlet访问HandlerMapping(处理器映射器):根据请求的url查找Handler;

 @Override public void init() { registerBeanDefinitionParser("advice", new TxAdviceBeanDefinitionParser; registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenBeanDefinitionParser; registerBeanDefinitionParser("jta-transaction-manager", new JtaTransactionManagerBeanDefinitionParser; }}

class TxAdviceBeanDefinitionParser extends AbstractSingleBeanDefinitionParser { @Override protected Class<?> getBeanClass(Element element) { return TransactionInterceptor.class; }}

如果目标对象的实现类没有实现接口,Spring AOP 将会采用 CGLIB 来生成 AOP
代理类。

** * Create a TransactionStatus for an existing transaction. */ private TransactionStatus handleExistingTransaction( TransactionDefinition definition, Object transaction, boolean debugEnabled) throws TransactionException {… if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW) { if (debugEnabled) { logger.debug("Suspending current transaction, creating new transaction with name [" + definition.getName; } SuspendedResourcesHolder suspendedResources = suspend(transaction); try { boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER); DefaultTransactionStatus status = newTransactionStatus( definition, transaction, true, newSynchronization, debugEnabled, suspendedResources); doBegin(transaction, definition); prepareSynchronization(status, definition); return status; } catch (RuntimeException beginEx) { resumeAfterBeginException(transaction, suspendedResources, beginEx); throw beginEx; } catch (Error beginErr) { resumeAfterBeginException(transaction, suspendedResources, beginErr); throw beginErr; } }/** * Clean up after completion, clearing synchronization if necessary, * and invoking doCleanupAfterCompletion. * @param status object representing the transaction * @see #doCleanupAfterCompletion */ private void cleanupAfterCompletion(DefaultTransactionStatus status) { status.setCompleted(); if (status.isNewSynchronization { TransactionSynchronizationManager.clear(); } if (status.isNewTransaction { doCleanupAfterCompletion(status.getTransaction; } if (status.getSuspendedResources() != null) { if (status.isDebug { logger.debug("Resuming suspended transaction after completion of inner transaction"); } resume(status.getTransaction(), (SuspendedResourcesHolder) status.getSuspendedResources; } }

4、运用的设计模式

You can leave a response, or trackback from your own site.

Leave a Reply

网站地图xml地图