spring学习笔记

如何学习spring

spring理论(能听懂技术介绍,并且可以对其他人说出去)

spring基础(IoC、DI、AOP)---很重要(spring boot、spring cloud 、spring data)

spring源码(重点是帮助深入理解spring应用)

spring应用(JDBC支持、事务支持、和mybatis整合)

可以解决spring框架中暴露出的问题(调bug)

交接(spring信息同步)

Spring介绍

  • 我们现在学习的spring,spring framework(包含了20多个模块)其中里面有web mvc模块(springmvc)

  • springboot 、springcloud 与 spring framework不存在包含关系。

  • spring提供了一站式企业应用解决方案(企业开发的一条龙服务、邮件、消息服务、开发框架)。

  • spring容器其实指的就是IoC容器,Ioc容器指的就是BeanFactory工厂(DefaultListableBeanFactory)。BeanFactory有一个子接口叫ApplicationContext(应用上下文接口)。

  • 我们需要了解spring容器的初始化过程(BeanFactory是如何管理Bean的实例的,需要源码专题去解决)

  • IoC:控制反转,创建Bean对象的角色发送了反转,由程序员创建,反转为Spring容器创建。

  • DI:基于IoC的,在Bean对象创建的过程中,需要注入属性(基本属性、对象属性、集合数组属性)

  • AOP:

    • 面向切面的编程,它只是一种aop联盟提出来的编程思想,根据这种编程思想,有很多的实现:AspectJ、Spring AOP、Spring 整合了AspectJ。

    • AOP的主要作用:横向抽取重复代码,实现代码的重用(事务、日志监控等)、AOP是为了弥补OOP的一些不足。

      • 纵向抽取(继承)
      1543843592214.png
      • 横向抽取(AOP)
    1543843558302.png

Spring 入口

所谓的spring入口,指的就是如何启动spring容器。

  • 基于XML

    • java应用

      ApplicationContext ctx = new ClasspathXmlApplicationContext("spring.xml");
      
    • web应用

      web.xml

      <context-param>
          <param-name>contextConfigLocation</param-name>
          <param-value>classpath:spring.xml</param-value>
      </context-param>
      <listener>
          <listener-class>
              ContextLoaderListener
          </listener-class>
      </listener>
      

      ContextLoaderListener监听器中,会去调用getWebApplicationContext()—>AbstractApplicationContext()

  • 基于注解

    • java应用

      ApplicationContext ctx = new AnnotationConfigApplicationContext(@Configuration配置类);
      
    • web应用

      web.xml

      <context-param>
          <param-name>contextConfigLocation</param-name>
          <param-value>@Configuration配置类</param-value>
      </context-param>
      <listener>
          <listener-class>
              ContextLoaderListener
          </listener-class>
      </listener>
      

      ContextLoaderListener监听器中,会去调用getWebApplicationContext()—>AbstractApplicationContext()

      getWebApplicationContext得到的默认实现类AnnotationConfigWebApplicationContext

IoC和DI的三种实现方式

基于XML

  • java代码---面向接口开发(正常编写)

  • spring xml配置文件

    • IoC---bean标签 ,表示该bean交给spring容器管理
      • id
      • init-method 初始化方法(源码分析部分,看到该属性啥时候执行)
      • destroy-method 它的值就是一个方法名称
        • 数据库连接池配置的时候,一定要配置它,具体配置看bean的class类中定义的销毁方法是什么
    • DI —bean标签的property子标签和constractor�-arg子标签
      • ref
      • value

基于注解和XML混合

  • java代码

    • IoC注解:@Component、@Controller、@Service、@Repository
    • DI注解:第一步:在IoC容器中查找指定的依赖第二步:属性注入
      • @Value(注入基本类型和String类型)
        • ${xxx}
        • context:property-placeholder:第一个去加载指定的properties文件、第二个就是将读取到的key/value数据,去替换spring上下文中出现的属性占位符 ${xxx}
      • @Autowired(byType---class类型)---spring提供的注解。
        • byName—需要配合@Qualifier注解
      • @Resource(默认先byName[bean的id或者name])、再byType),建议使用。它是由java提供的注解。
      • @Inject(默认是byType)
        • byName — @Name
  • spring xml配置

    • dataSource这种第三方的Bean对应的Bean标签

    • context:component-scan:

      • 开启@Autowired等几个注解的功能(BeanFactoryPostProcessor)。
        • 专门开启@Autowired注解的配置 context:annotation-driven
      • 扫描该应用上下文中指定包下面的IoC注解,将这些扫描到的Bean,交给spring容器进行管理。

基于纯注解

  • 零配置:是说的没有spring xml配置文件了,有没有可能包含mybatis(映射文件)
  • java代码:
    • @Configuration:替代XML配置文件
    • @ComponentScan:替代context:component-scan标签
    • @Bean:替代bean标签的。
    • @ProperySource:主要是替代context:property-placeholder标签的
    • @Import:替代import标签,可以将另一个@Configuration类引入到当前配置类中

基于XML和注解方式的优缺点

注解的优势:

​ 配置简单,维护方便(我们找到类,就相当于找到了对应的配置)。

l XML 的优势:

​ 修改时,不用改源码。不涉及重新编译和部署。

AOP的三种实现方式

AOP原理

AOP的作用:在不修改代码的情况下,对功能进行增强(开闭原则)

预编译方式和运行时代理方式

  • AspectJ是采取的预编译方式(静态织入)
  • Spring AOP是采取的运行时代理方式(动态代理)
    • JDK动态代理---基于接口
    • CGLib动态代理---基于继承(任何一个非final类都可以被继承)

AOP术语

  • 切入点:待增强的方法
  • 通知(增强):日志、事务等功能
  • 织入
  • 切面:切入点和通知的组合
  • 目标对象:表现层、业务层、持久层的相关代码。目标对象无须被修改。
  • 代理:最终生成的对象。

一句话概括AOP就是:在【目标对象】中定位【切入点】,【织入】对应的【通知】,就变成了【代理对象】

基于XML(spring整合aspectJ)

  • 目标对象(Service实现类)

  • 编写通知类(单独的类,无须继承任何类和实现任何接口)

  • spring配置文件

    <bean class="目标类的全路径"></bean>
    <bean class="MyAdvice的全路径"></bean>
    <aop:config>
      <!-- 这是使用的Spring AOP实现 -->
      <!-- <aop:advisor advice-ref="" pointcut=""/> -->   
        
        <!-- 这是使用的Spring + AspectJ整合方式实现 -->
        <!-- 配置切面:切面由通知和切入点组成 -->
        <aop:aspect ref="myAdvice">
            <!-- method属性值:指的是通知类的方法名称 -->
          <!-- pointcut属性值:切入点表达式 -->
          <aop:before method="before"
                  pointcut="execution(* *..*.*ServiceImpl.*(..))" />
        </aop:aspect>
    </aop:config>
    
    • 通知类型(五种)

      • * 通知类型(五种):前置通知、后置通知、最终通知、环绕通知、异常抛出通知。

        * 前置通知:

        ​ * 执行时机:目标对象方法之前执行通知

        ​ * 配置文件:<aop:before method="before" pointcut-ref="myPointcut"/>

        ​ * 应用场景:方法开始时可以进行校验

        * 后置通知:

        ​ * 执行时机:目标对象方法之后执行通知,有异常则不执行了

        ​ * 配置文件:<aop:after-returning method="afterReturning" pointcut-ref="myPointcut"/>

        ​ * 应用场景:可以修改方法的返回值

        * 最终通知:

        ​ * 执行时机:目标对象方法之后执行通知,有没有异常都会执行

        ​ * 配置文件:<aop:after method="after" pointcut-ref="myPointcut"/>

        ​ * 应用场景:例如像释放资源

        * 环绕通知:

        ​ * 执行时机:目标对象方法之前和之后都会执行。

        ​ * 配置文件:<aop:around method="around" pointcut-ref="myPointcut"/>

        ​ * 应用场景:事务、统计代码执行时机

        * 异常抛出通知:

        ​ * 执行时机:在抛出异常后通知

        ​ * 配置文件:<aop:after-throwing method=" afterThrowing " pointcut- ref="myPointcut"/>

        ​ * 应用场景:包装异常

    • 切入点表达式

      execution(返回值 包名.类名.方法名(参数类型))

基于注解和XML混合(spring整合aspectJ)

  • 目标对象(Service实现类)

  • 编写切面类

    • 类上必须加上@Aspect(标记该类是一个AOP 切面类)、@Component(标记该类可以被组件扫描器扫描到spring容器中)

    • 方法上需要加上@Before、@AfterReturning等五个注解,分别对应五种通知类型。

    • 可以在一些方法上加上@PointCut注解(为了去声明一个切入点表达式),该方法可以被@Before、@AfterReturning注解使用。

    • 示例:

      @Component("myAspect")
      @Aspect
      public class MyAspect {
          
          private static final String pcut="execution(* *..*.*ServiceImpl.*(..))";
          
          @Before(value="MyAspect.fn()")
          public void before() {
              System.out.println("这是注解方式的前置通知");
          }
          
          @After(value="execution(* *..*.*ServiceImpl.*(..))")
          public void after() {
              System.out.println("这是注解方式的最终通知");
          }
          
          @AfterReturning(pcut)
          public void after() {
              System.out.println("这是注解方式的后置通知");
          }
          
          @Pointcut("execution(* *..*.*ServiceImpl.*(..))")
          public void fn() {}
      }
      
      
  • spring配置文件

      <!-- 扫描切面类和目标类 -->
      <context:component-scan
          base-package="com.kkb.spring.aop"></context:component-scan>
      
      <!-- 开启aspectj的自动代理,用于AOP的注解方式 -->
      <aop:aspectj-autoproxy/>
    

基于纯注解(spring整合aspectJ)

以下代码,主要替换的就是spring配置文件

@Configuration
@ComponentScan("com.kkb.spring.aop")
@EnableAspectJAutoProxy
public class SpringConfiguration{
    
}

Spring整合Junit

为Springmvc的MockMVC做铺垫

  • junit是专门实现单元测试的

    单元测试,主要测试的是业务逻辑。

  • 编写spring单元测试代码遇到的问题

    ApplicationContext ctx = 
                  new ClassPathXmlApplicationContext("spring.xml");
    UserService service1 = context.getBean(UserService.class);
    
    

    以上代码每一个单元测试代码都要编写,但是它又和我们要测试的业务逻辑,没有关系。

  • 解决思路:Junit是通过@RunWith注解,让我们制定一个自定义的运行器(spring已经实现)去运行单元测试代码。

  • 示例

    @RunWith(SpringJunit4ClassRunner.class)
    //加载XML配置文件的写法
    @ContextConfiguration(locations="classpath:spring.xml")
    //加载Java配置类的写法
    //@ContextConfiguration(classes=SpringConfiguration.class)
    public class TestSpring{
        
        @Resource
        private UserService service;
        
        @Test
        public void testAop(){
            service.saveUser();
        } 
    }
    

Spring应用之JDBC实现

模板模式:将模板化的代码,抽象为一个抽象类,然后定义一个或多个abstract方法待子类去实现。

持久层的相关框架(封装了JDBC):

  • mybatis:和spring整合需要第三方中间整合包(mybatis)
  • ibatis
  • hibernate
  • spring JDBC:本来就是spring的模块,无需和spring整合。
    • JdbcTemplate:模板类,主要就是通过该类实现增删改查。
  • DBUtils

示例代码:

    @Test
    public void run1(){
        // 创建连接池,先使用Spring框架内置的连接池
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql:///spring");
        dataSource.setUsername("root");
        dataSource.setPassword("root");
        // 创建模板类
        JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
        // 完成数据的添加
        jdbcTemplate.update("insert into account values (null,?,?)", "测试",10000);
    }

  • JdbcDaoSupport
    • 封装了JdbcTemplate
    • 继承了该类,则不需要在spring配置文件中,注入JdbcTemplate对象了。

spring应用之事务支持

​ (看源码--分析事务是如何实现的并且深刻理解AOP的功能)

事务

  • Spring事务:只是做了事务管理。

    Spring并不直接管理事务,而是提供了多种事务管理器,他们将事务管理的职责委托给Hibernate或者JTA等持久化机制所提供的相关平台框架的事务来实现。 Spring事务管理器的接口是PlatformTransactionManager,通过这个接口,Spring为各个平台如JDBC、Hibernate等都提供了对应的事务管理器,但是具体的实现就是各个平台自己的事情了。

1544017570886.png
  • jdbc事务

  • MySQL事务:讲解MySQL的时候会去详细介绍(redo日志、undo日志)

    总结:事务最终都是由数据库本身去实现的。

事务的四大特性

ACID的理解:

  • A:原子性

    操作不可分割,要么都成功、要么都失败。

  • C:一致性

    账户A(600元)和账户B(400元)总共有1000块钱。

    账户A(600元)给账户B(400元)转账200元,最终的结果不管是成功还是失败,A和B的总额还是1000元。

  • I:隔离性(由锁机制实现的。会引起并发访问问题)

    为了保证A事务和B事务之间操作是互不影响。

  • D:持久性:将结果保存到数据库文件中。

事务并发问题

隔离性不好会引起事务并发问题。

  • 更新丢失
  • 脏读:A事务读到了B事务未提交的数据。
  • 不可重复读:A事务两次读取同一行记录,显示的结果不一致。原因是两次读取期间,B事务对该记录进行了更新操作。
  • 幻读:A事务两次读取同一张表,显示的结果条数不一致。原因是两次读取期间,B事务对该表进行了增加和删除操作。

SQL92标准提出了四种隔离级别:

① Read uncommitted (读未提交):最低级别,任何情况都无法保证。

② Read committed (读已提交):可避免脏读的发生。

③ Repeatable read (可重复读):可避免脏读、不可重复读的发生。(注意事项:MySQL在该级别的时候,就可以将幻读给解决掉

④ Serializable (串行化):可避免脏读、不可重复读、幻读的发生。

MySQL数据库的默认隔离级别是Repeatable Read

注意事项:

隔离级别越高,越能保证数据的完整性和一致性,但是对并发性能的影响也越大。

spring两种事务实现

spring有两种事务实现方式:编程式事务(不推荐使用)、声明式事务。

spring声明式事务

XML方式

  • spring配置文件

    <bean id="dataSource"></bean>
    <!-- spring提供的事务管理器 -->
    <bean id="transactionManager" class="DataSourceTransactionManager全路径">
      <property name="dataSource" ref="dataSource"></property>
    </bean>
    <!-- 配置通知 spring提供的增强类,但是该类需要指定事务管理器去完成事务管理-->
      <tx:advice id="txAdvice"
          transaction-manager="transactionManager">
            <!-- 配置事务属性 -->
              <!-- 常见事务属性: 事务隔离级别、事务传播特性 -->
            <!-- 事务传播特性:指定的两个都拥有事务的方法,发生调用,那么此时事务该如何处理-->
          <tx:attributes>
              <tx:method name="save*" propagation="REQUIRED" />
              <tx:method name="update*" propagation="REQUIRED" />
              <tx:method name="transfer*" propagation="REQUIRED" />
              <tx:method name="query*" read-only="true" />
          </tx:attributes>
      </tx:advice>
    <!-- 类似于以下配置 -->
    <!-- <bean id="" class="MyTransactionAdvice"></bean> -->
    
    <!-- 配置AOP切面 -->
    <aop:config>
          <!-- 这使用的是Spring AOP的实现 -->
          <!-- advice-ref:指定advice增强类 -->
          <aop:advisor advice-ref="txAdvice"
              pointcut="execution(* *..*.*ServiceImpl.*(..))" />
      </aop:config>
    

混合方式

由同学们自己去实现

纯注解方式

由同学们自己去实现

Spring和Mybatis整合

需求

查询account表的记录

整合思路

需要整合的,就是项目中的对象(这些对象都要被spring管理)

  • 分析有哪些对象需要被spring管理(确定是XML方式还是纯注解方式来管理)

    • 业务层
      • 实现类(多个)
      • 事务相关的对象
        • 事务管理器
        • 通知类
        • 切面类
    • 持久层(mybatis)
      • 数据源(一个)
      • SqlSessionFactory对象(一个)
      • Mapper代理对象(多个)
  • 配置spring文件(分模块配置思想---便于维护)

    • 持久层---一个spring配置文件

      <!-- org.mybatis.spring.SqlSessionFactoryBean -->
      <!-- 可以通过该标签配置mybatis的别名、配置mybatis的插件功能等 -->
      <!-- 只要mybatis的全局配置文件能做的事情,SqlSessionFactory都可以做 -->
      <bean id="sqlSessionFactory" class="SqlSessionFactoryBean的全路径">
          <property name="dataSource" ref="dataSource"></property>
      </bean>
      
      <!-- 该类可以动态生成mapper代理对象 -->
      <bean class="MapperScannerConfigurer的全路径">
          <property name="basePackage" value="mapper映射文件所在的包名"></property>
      </bean>
      
    • 业务层

      • 业务类---一个spring配置文件
      • 事务类---一个spring配置文件
    • 将所有spring配置文件整合到一起(方式有多种,具体有哪些??????

  • 问题:

    • 不知道加哪些依赖?只需要添加最基本的依赖,保证程序不报错即可。

源码专题

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

推荐阅读更多精彩内容