美文网首页
Spring In Action DI AOP

Spring In Action DI AOP

作者: wi11iam | 来源:发表于2017-07-18 13:23 被阅读0次

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>

相关文章

  • Spring In Action DI AOP

    spring 关键策略 1 基于pojo的轻量级和最小侵入性编程 2 通过依赖注入和面向接口实现松耦合 3 基于切...

  • 0、spring知识脉络

    参考书籍《spring in action》第四版 第一部分 spring框架核心知识(容器、DI、AOP) 1、...

  • AOP

    java创建对象的方法(5种): Spring AOP: spring分为: 1、IOC/DI 2、AOP AOP...

  • 初识Spring的DI及其基本用法

    作为Spring新手,边学《Spring in Action》边总结相关知识。 什么是DI DI,Dependen...

  • 8、AOP

    Spring AOP: spring分为:1、IOC/DI 2、AOPAOP的使用场景:日志和事务概念:AOP为A...

  • springMVC+maven+mybatis+mysql入门

    (三)DI,IOC,AOP等基本概念 本文简单讲解一下DI,IOC,AOP,spring的基本理念就是这几个,想要...

  • 初见spring

    框架 spring IOC AOP 配置文件 IOC/DI 依赖注入(Dependecy Injection) ...

  • 2019-01-29

    参考链接:《Spring in Action(4th Edition)》阅读笔记 DI(dependency in...

  • Java 注解依赖注入简易实现

    最近在学习 Java 的 Spring Boot 框架, 知道其精髓就是 DI 和 AOP, 其中对于 DI(依赖...

  • AOP

    反射 java创建对象的方法(5种): Spring AOP: spring分为:1、IOC/DI 2、AOPA...

网友评论

      本文标题:Spring In Action DI AOP

      本文链接:https://www.haomeiwen.com/subject/fkxhkxtx.html