Spring In Action DI AOP

spring 关键策略

1 基于pojo的轻量级和最小侵入性编程

2 通过依赖注入和面向接口实现松耦合

3 基于切面和惯例进行声明式编程

4 通过切面和模板减少样板式代码

依赖注入 DI

1 耦合在一起 无法更改 只能完成特定Quest

public class BraveKnight implements Knight {

private RescueDamselQuest quest;

public BraveKnight(){

quest = new RescueDamselQuest();

}

public void embarkOnQuest(){

quest.embark();

}

}

2 构造器注入 利用接口参数解除耦合(DI)

public class BraveKnight implements Knight {

private Quest quest;

public BraveKnight(Quest quest){

  this.quest = quest;

}

public void embarkOnQuest(){

  quest.embark();

}

}

3 创建组建之间协作的行为 装配

构造器注入

<bean id="duke" class="com.wi11iam.springidol.Juggler">
  <constructor-arg value="15"/>
</bean>
ApplicationContest ctx = new ClassPathXmlApplicationContext("com/wi11iam/springidol/spring-idol.xml");
Performer performer = (Performer)ctx.getBean("duke");
performer.perform();
package com.wi11iam.springidol;
public class Juggler implements Performer {
  private int beanBags = 3;
  public Juggler(){}
  public Juggler(int beanBags) {
    this.beanBags = beanBags;
  }
  public void perform() {
    System.out.println("JUGGLING"+beanBags);
  }
}

4注解
@Component 通用的构造型注解 标识该类为Spring组件 Component是这几个的父类
@Controller 标识该类定义为 SpringMVC controllor
@Repository 标记为数据仓库
@Service 标识为服务

@Autowired 让Spring自动装入标识的Bean byType方式
@Inject 同Autowired 只是不同的标准
@Resource byName

@Value 给属性赋值

@Value("${app.url}")
private String url;

如果想要在springMVC的Controllor层也获得配置文件
spring-mvc.xml 也要加扫描配置文件
<context:property-placeholder location="classpath:*.properties" />

5自动扫描
spring-base.xml

<context:component-scan base-package="com.wi11iam.spring">
    <context:exclude-filter type="regex" expression="com.wi11iam.spring.controller"/>
</context:component-scan>

spring-mvc.xml 要分开写 两个是两个容器
<context:component-scan base-package="com.wi11iam.spring.controller" />
有了上端就包含了
<context:annotation-config/>

面向切面 AOP

Paste_Image.png

Advice通知 + pointcut切点 = Aspect切面
JoinPoints连接点
Weaving织入 Spring在运行期将切面织入,AOP容器为目标对象动态创建一个代理对象。

Paste_Image.png

通过在代理累中包裹切面,Spring在运行期将切面织入到Spring管理的Bean中,代理类封装了目标类,并拦截被通知的方法得调用,再将调用转发给真正的目标Bean。

1 环绕通知
切面要传入ProceedingJoinPoint 对象实例 用该对象的proceed()方法执行被通知方法(就是真正的目标Bean)

<aop:config>
  <aop:aspect ref="audience">
    <aop:pointcut id="performance" expression="execution(* com.wi11iam.spring.Performer.perform(..))"/>
    <aop:around pointcut-ref="performance" method="watchPerformance()"/>
   </aop:aspect>
<aop:config>
public void watchPerformance(ProceedingJoinPoint jointpoint){
  long start = System.currentTimeMillis();
  joinpoint.proceed();
  long end = System.currentTimeMillis();
  System.out.println(end-start);
}

2注解的环绕通知

@Aspect
public class WatchPerformance {
  @Pointcut("execution(* com.wi11iam.spring.Performer.perform(..))")
  public void performance(){}
  @Around("performance()")
  public void watchPerformance(ProceedingJoinPoint jointpoint){
    long start = System.currentTimeMillis();
    joinpoint.proceed();
    long end = System.currentTimeMillis();
    System.out.println(end-start);
}
}

数据访问


image.png

Spring的DAO模板类负责通用的数据访问职能,
对于特定任务则调用自定义DAO回调对象。

image.png

DAO层将数据访问层和业务层进行分离

Spring对ORM的支持
1.Spring声明式事务的集成支持
2.透明的异常处理
3.线程安全的 轻量级的模版类
4.资源管理

声明式事务(声明式:注解或配置文件)
传播行为
1.REQUIRED 当前方法必须在事务中执行 没有事务开启一个
2.SUPPORTS 不需要在事务中执行 但存在当前事务会在事务中执行
隔离级别 (当前事务受到其他并发事务的影响程度)
1.脏读:一个事务读取了另一个事务改写但尚未提交的数据,如果改写在稍后被回滚,那么第一个事务获取的数据就是无效的。
2.不可重复读:一个事务执行相同的查询两次,但得到不同的数据,这通常是因为另一个并发事务在两次查询期间更新了数据。例如事务T1在读取某一数据,而事务T2立马修改了这个数据并且提交事务给数据库,事务T1再次读取该数据就得到了不同的结果,发送了不可重复读。
3.幻读:与不可重复读相似,一个事务读取了几行数据,接着另一个并发事务插入了一些数据,在随后的查询中,第一个事务就会发现多了一些原本不存在的记录。例如事务T1对一个表中所有的行的某个数据项做了从“1”修改为“2”的操作,这时事务T2又对这个表中插入了一行数据项,而这个数据项的数值还是为“1”并且提交给数据库。而操作事务T1的用户如果再查看刚刚修改的数据,会发现还有一行没有修改,其实这行是从事务T2中添加的,就好像产生幻觉一样,这就是发生了幻读。

不可重复读和脏读的区别是,脏读是某一事务读取了另一个事务未提交的脏数据,而不可重复读则是读取了前一事务提交的数据。幻读和不可重复读都是读取了另一条已经提交的事务(这点就脏读不同),所不同的是不可重复读查询的都是同一个数据项,而幻读针对的是一批数据整体(比如数据的个数)。

在理想情况下,事务之间是完全隔离的,从而可以防止这些问题发生,但是完全的事务隔离会导致性能问题,通常会涉及锁定数据库中的记录(表),阻碍并发,要求事务相互等待以完成各自工作。

隔离级别 含义
ISOLATION_DEFAULT 使用后端数据库默认的隔离级别
ISOLATION_READ_UNCOMMITED 允许读取尚未提交的数据变更 可能会导致脏读 幻读 不可重复读
ISOLATION_READ_COMMITED 允许读取并发事务已经提交的数据 可以阻止脏读 但是幻读或不可重复读扔可能发生
ISOLATION_REPEATABLE_READ 对同一字段的多次读取结果是一致的 除非数据是被本事务自己修改 可以阻止脏读和不可重复读 但幻读仍有可能发生
ISOLATION_SERIALIZABLE 完全服从ACID的隔离级别 确保阻止脏读 不可重复读 幻读 这是最慢的事务隔离级别 通常是通过完全锁定事务相关的数据库表来实现的

一般情况是Spring中不配置事务的隔离级别,使用默认的数据库的事务隔离级别,常用的MySQL数据库的InnoDB是Read committed类型的事务隔离级别,(事务的隔离很多是通过数据库的行级锁实现的,一个猜想不一定对)

MySQL的事务隔离级别

隔离级别 含义
Serializable (串行化) 可避免脏读、不可重复读、幻读的发生。
Repeatable read (可重复读) 可避免脏读、不可重复读的发生。
Read committed (读已提交) 可避免脏读的发生。
Read uncommitted (读未提交) 最低级别,任何情况都无法保证。

为了避免幻读和可重复读可以在程序中实现乐观锁(如在数据库中加版本号,更新的时候拿更新前的版本号和现在查出的版本号对比,不同则不更新)。
数据库隔离级别高的话容易发生数据库死锁,如两个两个更新语句都要更改一张表的id为1和100的记录,第一个更新语句(事务1)拿到id为1的记录并在数据库中锁了这条记录,而第二个更新语句(事务2)拿到id为100的记录也在数据库中锁了这条记录,这样事务1还要更新id为100的记录,但这条记录被事务2锁住,同理事务2也拿不到id为1的记录,这样就锁死了2行记录,造成了死锁,据说阿里的某些这种更新操作规定了先从id大的记录先更新这样就规避了中死锁的情况。

只读
声明式事务的第三个特性是否是只读事务。如果事务只对后端的数据库进行读操作,数据库可以利用事物的 只读特性来进行一些特定的优化。通过将事务设置为只读,让数据库对那些具备启动一个新事务的传播行为(REQUIRED,REQUIRED_NEW,NESTED)的方法进行优化,如采用HIbernate作为持久化机制,会导致Hibernate的flush模式被设置成FLUSH_NEVER。这会告诉Hibernate避免和数据库进行不必要的对象异步,并将所有的更新延迟到事务结束。

<!-- 拦截器方式配置事物 -->
    <tx:advice id="transactionAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <tx:method name="add*" propagation="REQUIRED" />
            <tx:method name="append*" propagation="REQUIRED" />
            <tx:method name="insert*" propagation="REQUIRED" />
            <tx:method name="save*" propagation="REQUIRED" />
            <tx:method name="update*" propagation="REQUIRED" />
            <tx:method name="query*" read-only="true"/>
            <tx:method name="put*" read-only="true"/>                        
            <tx:method name="*" propagation="REQUIRED" />
        </tx:attributes>
    </tx:advice>
    <aop:config>
        <aop:pointcut id="transactionPointcut"
            expression="(execution(* com.hengxin.qianee.service.impl.*.*(..))) 
                        or (execution(* com.hengxin.qianee.wechat.serviceImpl.*.*(..))) or (execution(* com.hengxin.qianee.talent.wechat.serviceImpl.*.*(..)))" />
        <aop:advisor pointcut-ref="transactionPointcut"
            advice-ref="transactionAdvice" />
            <aop:aspect order="-2147483648" ref="readWriteDataSourceTransactionProcessor">
           <aop:around pointcut-ref="transactionPointcut" method="determineReadOrWriteDB"/>
        </aop:aspect>
    </aop:config>
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,189评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,577评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,857评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,703评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,705评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,620评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,995评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,656评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,898评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,639评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,720评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,395评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,982评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,953评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,195评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,907评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,472评论 2 342

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,594评论 18 139
  • Spring Boot 参考指南 介绍 转载自:https://www.gitbook.com/book/qbgb...
    毛宇鹏阅读 46,732评论 6 342
  • MySQL技术内幕:InnoDB存储引擎(第2版) 姜承尧 第1章 MySQL体系结构和存储引擎 >> 在上述例子...
    沉默剑士阅读 7,388评论 0 16
  • 很多人喜欢这篇文章,特此同步过来 由浅入深谈论spring事务 前言 这篇其实也要归纳到《常识》系列中,但这重点又...
    码农戏码阅读 4,699评论 2 59
  • 曾经最美的是你那干净的明眸 穿越世俗的目光 你说我是不食烟火的仙女 你是我的牛郎 在灿烂的四月天里 我们尽情舞着梦...
    金指尖的花园阅读 266评论 0 3