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 创建组建之间协作的行为 装配

构造器注入


  

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 也要加扫描配置文件

5自动扫描
spring-base.xml


    

spring-mvc.xml 要分开写 两个是两个容器

有了上端就包含了

面向切面 AOP

Spring In Action DI AOP_第1张图片
Paste_Image.png

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

Spring In Action DI AOP_第2张图片
Paste_Image.png

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

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


  
    
    
   

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);
}
}

数据访问


Spring In Action DI AOP_第3张图片
image.png

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

Spring In Action DI AOP_第4张图片
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避免和数据库进行不必要的对象异步,并将所有的更新延迟到事务结束。


    
        
            
            
            
            
            
            
                                    
            
        
    
    
        
        
            
           
        
    

你可能感兴趣的:(Spring In Action DI AOP)