手写spring笔记

Spring

框架概述

  • 轻量级开源的javaEE框架

  • 可以解决企业应用开发的复杂性

  • IOC容器:控制反转,把创建对象过程交给Spring进行管理

  • AOP:面向切面,不改变源代码的情况下进行功能增强

特点

  1. 方便解耦,简化开发

  2. AOP编程支持

  3. 方便程序测试

  4. 方便和其他框架进行整合

  5. 方便进行事务的操作

  6. 降低API开发难度

入门

  1. 创建普通的类,类中创建普通的方法

      
      public class User {
          public void add(){
              System.out.println("add~~~~~");
          }
      }
  2. 创建Spring配置文件,在配置文件中配置创建的对象

      
      <?xml version="1.0" encoding="UTF-8"?>
      <beans xmlns="http://www.springframework.org/schema/beans"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
          <!--配置User对象创建-->
          <bean id="user" class="com.itxiaoli.Spring5_Demo01.User"></bean>
      </beans>
  3. 进行代码编写

      public class DemoSpring5 {
          @Test
          public void testAdd(){
              //1、加载Spring配置文件
              ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
      ​
              //2、获取配置创建的对象
              User user = context.getBean("user", User.class);
      ​
              System.out.println(user);
              user.add();
          }
      }

IOC容器

底层原理

1、什么时IOC

  • 控制反转,把对象的创建和对象之间的调用过程,交给Spring进行管理。

  • 使用IOC的目的:为了耦合度降低。

  • 做入门的案例就是IOC的实现

2、IOC底层原理

  • xml解析、工厂模式、反射。

3、IOC底层原理

 

IOC接口(BeanFactory)

  • IOC思想基于IOC容器完成,IOC容器底层就是对象工厂

  • Spring提供IOC容器实现两种方式:(两个接口)

    (1)BeanFactory:IOC容器基本实现,是Spring内部的使用接口,不提供开发人员使用。

    ​ 特点:加载配置文件的时候不会创建对象,在获取对象(使用)的时候才会创建对象。

    (2)ApplicationContext:BeanFactory接口的子接口,提供更多更强大的功能,一般由开发人员使用。

    ​ 特点:加载配置文件时候就会把在配置文件的对象进行创建

  • ApplicationContext接口有实现类

        

 

IOC操作Bean管理

IOC操作Bean管理(基于xml)

  • 创建对象

  
    <bean id="stu" class="com.itxiaoli.demo01.Student"></bean>
  • 给创建的对象赋值

1.使用setter注入

  
  注入分为简单类型注入和引用类型注入
  简单类型注入值使用value属性
  引用类型注入值使用ref属性
  必须要注意:使用setter注入必须提供无参的构造方法,必须提供setXXX()方法.
  
    <!--创建学生对象-->
    <bean id="stu" class="com.itxiaoli.demo02.Student">
        <property name="name" value="李四"></property>    ===>简单类型注入
        <property name="age" value="22"></property>
        <property name="school" ref="school"></property>  ===>引用类型注入
    </bean>
    <!--创建学校对象-->
    <bean id="school" class="com.itxiaoli.demo02.School">
        <property name="name" value="清华大学"></property>
        <property name="address" value="海淀区"></property>
    </bean>

2、使用构造方法注入

  
    Student stu = new Student("张三",22);
  
    a.使用构造方法的参数名称进行注入值
      <bean id="school" class="com.itxiaoli.demo03.School">
          <constructor-arg name="name1" value="清华大学"></constructor-arg>
          <constructor-arg name="address1" value="海淀区"></constructor-arg>
      </bean>
    b.使用构造方法参数的下标注入值
      <bean id="stu" class="com.itxiaoli.demo03.Student">
          <constructor-arg index="0" value="钱七"></constructor-arg>
          <constructor-arg index="1" value="22"></constructor-arg>
          <constructor-arg index="2" ref="school"></constructor-arg>
      </bean>
    c.使用默认的构造方法的参数的顺序注入值
      <bean id="stuSequence" class="com.itxiaoli.demo03.Student">
          <constructor-arg value="陈十"></constructor-arg>
              <constructor-arg value="22"></constructor-arg>
              <constructor-arg ref="school"></constructor-arg>
      </bean>

IOC操作Bean管理(基于注解)

也称为DI(Dependency Injection),它是IOC的具体实现的技术.

基于注解的IOC,必须要在Spring的核心配置文件中添加包扫描.

  
   <context:component-scan base-package="com.itxiaoli.demo01"></context:component-scan>
  • 创建对象的注解

  1. @Component:可以创建任意对象.创建的对象的默认名称是类名的驼峰命名法.也可以指定对象的名称@Component("指定名称").

  2. @Controller:专门用来创建控制器的对象(Servlet),这种对象可以接收用户的请求,可以返回处理结果给客户端.

  3. @Service:专门用来创建业务逻辑层的对象,负责向下访问数据访问层,处理完毕后的结果返回给界面层.

  4. @Repository:专门用来创建数据访问层的对象,负责数据库中的增删改查所有操作.

  
  案例:
  @Component("stu")  //交给Spring去创建对象,就是在容器启动时创建
  public class Student {
      @Value("张三")  ===>简单类型的值注入
      private String name;
      @Value("22")
      private int age;
      ...}
  • 依赖注入的注解

    1、简单类型(8种基本类型+String)的注入

    @Value:用来给简单类型注入值

    2、引用类型的注入

    ​ @Autowired:使用类型注入值,从整个Bean工厂中搜索同源类型的对象进行注入.

    ​ 同源类型也可注入.

    ​ 什么是同源类型:​ a.被注入的类型(Student中的school)与注入的类型是完全相同的类型​ b.被注入的类型(Student中的school父)与注入的类型(子)是父子类​ c.被注入的类型(Student中的school接口)与注入的类型(实现类)是接口和实现类的类型

    注意:在有父子类的情况下,使用按类型注入,就意味着有多个可注入的对象.此时按照名称进 行二次筛选,选中与被注入对象相同名称的对象进行注入.

    ​ @Autowired @Qualifier("名称"):使用名称注入值,从整个Bean工厂中搜索相同名称的对象进行注入.注意:如果有父子类的情况下,直接按名称进行注入值.、

添加包扫描的方式

  • 单个包扫描(推荐使用

  
    <context:component-scan base-package="com.itxiaoli.controller"></context:component-scan>
    <context:component-scan base-package="com.itxiaoli.service.impl"></context:component-scan>
    <context:component-scan base-package="com.itxiaoli.mapper"></context:component-scan>
  • 多个包扫描,多个包之间以逗号或空格或分号分隔

      
      <context:component-scan base-package="com.itxiaoli.controller com.itxiaoli.service ,com.itxiaoli.mapper">
      </context:component-scan>
  • 扫描根包(不推荐)

      
      <!--会降低容器启动的速度,导致多做无用功-->
      <context:component-scan base-package="com.bjpowernode"></context:component-scan>

为应用指定多个 Spring 配置文件

拆分配置文件的策略

  • 按层拆

    1、applicationContext_controller.xml

      
      <bean id="uController" class="com.itxiaoli.controller.UsersController">
      <bean id="bController" class="com.itxiaoli.controller.BookController"> 

    2、applicationContext_service.xml

      
      <bean id="uService" class="com.itxiaoli.controller.UsersService">
      <bean id="bService" class="com.itxiaoli.controller.BookService">

    3、applicationContext_mapper.xml

      
      <bean id="uMapper" class="com.itxiaoli.controller.UsersMapper">
      <bean id="bMapper" class="com.itxiaoli.controller.BookMapper">
  • 按功能拆

    1、applicationContext_users.xml

      
      <bean id="uController" class="com.itxiaoli.controller.UsersController">
      <bean id="uService" class="com.itxiaoli.controller.UsersService">
      <bean id="uMapper" class="com.itxiaoli.controller.UsersMapper">

    2、applicationContext_book.xml

      
      <bean id="bController" class="com.itxiaoli.controller.BookController">
      <bean id="bService" class="com.itxiaoli.controller.BookService">
      <bean id="bMapper" class="com.itxiaoli.controller.BookMapper">

spring配置文件的整合

  1. 单个文件导入

      
      <import resource="applicatoinContext_mapper.xml"></import>
      <import resource="applicatoinContext_service.xml"></import>
      <import resource="applicatoinContext_controller.xml"></import>
  2. 批量导入

      
      <import resource="applicatoinContext_*.xml"></import>

面向切面编程AOP

AOP(Aspect Orient Programming)面向切面编程。

切面:公共的,通用的,重复的功能称为切面,面向切面编程就是将切面提取出来,单独开发,在需要调用的方法中通过动态代理的方式进行织入.

手写AOP框架

业务:图书购买业务 切面:事务

  • 第一个版本:业务和切面紧耦合在一起,没有拆分.

  • 第二个版本:使用子类代理的方式拆分业务和切面.

  • 第三个版本:使用静态代理拆分业务和切面.业务和业务接口已拆分.此时切面紧耦合在业务中.

  • 第四个版本:使用静态代理拆分业务和业务接口,切面和切面接口.

  • 第五个版本:使用动态代理完成第四个版本的优化.

      
      //最终版本
      public interface Aop {
           default void before(){};
           default void after(){};
           default void exception(){};
      }
      
      public interface Service {
      //    规定业务功能
          void buy();
      //    增加有参数有返回值的方法,测试代理功能
          default String show(int age){
              return null;
          }
      }
      
      public class BookServiceImpl implements Service {
          @Override
          public void buy() {
              System.out.println("图书购买功能实现。。。。。。");
          }
          @Override
          public String show(int age) {
              System.out.println("这是show方法被调用"+age);
              return "abcd";
          }
      }
      
      public class TransaAop implements Aop {
          @Override
          public void before() {
              System.out.println("事务开启!!!");
          }
      ​
          @Override
          public void after() {
              System.out.println("事务提交!!!");
          }
      ​
          @Override
          public void exception() {
              System.out.println("事务回滚!!!");
          }
      
      public class ProxyFactory {
          public static Object getAgent(Service target,Aop aop){
      //        返回生成的动态代理对象
              return Proxy.newProxyInstance(
      //                类加载器
                      target.getClass().getClassLoader(),
      //                目标对象实现的所有的接口
                      target.getClass().getInterfaces(),
      //                代理功能的实现
                      new InvocationHandler() {
                          @Override
                          public Object invoke(
      //                            生成的代理对象
                                  Object proxy,
      //                            正在被调用的目标方法
                                  Method method,
      //                            目标方法的参数
                                  Object[] args) throws Throwable {
                              Object obj = null;
                              try {
      //                        切面
                                  aop.before();  //事务 日志
      //                        业务
                                  obj = method.invoke(target, args);
      //                        切面
                                  aop.after();
                              } catch (IllegalAccessException e) {
                                 aop.exception();
                              }
                              return obj;
                          }
                      }
              );
          }
      }
      
      public class productServiceImpl implements Service {
          @Override
          public void buy() {
              System.out.println("商品购买业务实现了");
          }
      }   
      
      public class LogAop implements Aop {
          @Override
          public void before() {
              System.out.println("前置日志输出");
          }
      }

    测试

      
      public class mytest03 {
          @Test
          public void test(){
              Service agent = (Service) ProxyFactory.getAgent(new BookServiceImpl(), new TransaAop());
              agent.buy();
          }
          @Test
          public void test1(){
              Service agent = (Service) ProxyFactory.getAgent(new BookServiceImpl(), new LogAop());
              String show = agent.show(22);
              System.out.println(show);
          }
      }

    输出

    test():

    事务开启!!!图书购买功能实现。。。。。。事务提交!!!

    test1():

    前置日志输出这是show方法被调用22abcd

Spring支持的AOP的实现

  • Before通知:在目标方法被调用前调用,涉及接口org.springframework.aop.MethodBeforeAdvice;

  • After通知:在目标方法被调用后调用,涉及接口为org.springframework.aop.AfterReturningAdvice;

  • Throws通知:目标方法抛出异常时调用,涉及接口org.springframework.aop.ThrowsAdvice;

  • Around通知:拦截对目标对象方法调用,涉及接口为org.aopalliance.intercept.MethodInterceptor。

AOP常用的术语

  • 切面:就是那些重复的,公共的,通用的功能称为切面,例如:日志,事务,权限.

  • 连接点:就是目标方法.因为在目标方法中要实现目标方法的功能和切面功能.

  • 切入点(Pointcut):指定切入的位置,多个连接点构成切入点.切入点可以是一个目标方法,可以是一个类中的所有方法,可以是某个包下的所有类中的方法

  • 目标对象:操作谁,谁就是目标对象.

  • 通知(Advice):来指定切入的时机.是在目标方法执行前还是执行后还是出错时,还是环绕目标方法切入切面功能.

AspectJ框架

类型

  • 前置通知@Before

  • 后置通知@AfterReturning

  • 环绕通知@Around

  • 最终通知@After

  • 定义切入点@Pointcut(了解)

切入点表达式

规范的公式: execution(访问权限 方法返回值 方法声明(参数) 异常类型) 简化后的公式: execution( 方法返回值 方法声明(参数) )

代码任意个任意的字符(通配符) .. 如果出现在方法的参数中,则代表任意参数 如果出现在路径中,则代表本路径及其所有的子路径

示例:

  
    execution(public * *(..)) :任意的公共方法
    execution(* set*(..)):任何一个以“set”开始的方法
    execution(* com.xyz.service.impl.*.*(..)):任意的返回值类型,在com.xyz.service.impl包下的任意类的任意方法的任意参数
    execution(* com.xyz.service..*.*(..)):任意的返回值类型 ,在com.xyz.service及其子包下的任意类的任意方法的任意参数  
    execution(* *..service.*.*(..)):service之前可以有任意的子包
    execution(* *.service.*.*(..)):service之前只有一个包

AspectJ框架切换JDK动态代理和CGLib动态代理

  
  <aop:aspectj-autoproxy ></aop:aspectj-autoproxy>  ===>默认是JDK动态代理,取时必须使用接口类型
  <aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy> ==>设置为CGLib子类代理,可以使用接口和实现类接
  记住:使用接口来接,永远不出错.

通知

实现的步骤:

  1. 创建业务接口

  2. 创建业务实现

  3. 创建切面类,实现切面方法

  4. 在applicationContext.xml文件中进行切面绑定

添加依赖

  
  <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aspects</artifactId>
      <version>5.2.5.RELEASE</version> 
  </dependency>
  • 前置通知

      
      package com.itxiaoli.demo01;
      ​
      import org.aspectj.lang.JoinPoint;
      import org.aspectj.lang.annotation.Aspect;
      import org.aspectj.lang.annotation.Before;
      ​
      import java.util.ArrayList;
      import java.util.Arrays;
      ​
      /**
       * 此类为切面类,包含各种切面方法
       */
      ​
      @Aspect  //交给AspectJ的框架去识别切面类
      public class MyAspect {
          /**
           * 所有切面的功能求是由切面方法来实现的
           * 可以将各种切面都在此类中进行开发
           *
           * 前置通知的切面方法的规范
           * 1、访问权限是public
           * 2、方法的返回值是void
           * 3、方法名称自定义
           * 4、方法没有参数,如果有也是JoinPoint类型
           * 5、必须使用@before注解来声明切入的时机和切入点
           *      参数:vaule 指定切入点表达式
           */
      //    @Before(value = "execution(public String com.itxiaoli.demo01.SomeServiceImpl.dosome(String,int))")
          @Before(value = "execution(public * com.itxiaoli.demo01.SomeServiceImpl.*(..))")
          public void mybefore(JoinPoint joinPoint){
              System.out.println("切面方法的前置功能实现~~~~~~~~~");
              System.out.println("目标方法的签名:"+joinPoint.getSignature());
              System.out.println("目标方法的参数:"+ Arrays.toString(joinPoint.getArgs()));
          }
      }
  • 后置通知

      
      package com.itxiaoli.demo02;
      ​
      import org.aspectj.lang.annotation.AfterReturning;
      import org.aspectj.lang.annotation.Aspect;
      import org.springframework.stereotype.Component;
      ​
      @Aspect
      @Component
      public class MyAspect {
          /**
           * 后置通知的方法规范
           *  1、访问的权限是public
           *  2、方法没有返回值
           *  3、方法名称自定义
           *  4、方法有参数(也可以没有参数,如果目标方法没有返回值,则可以写无参的构造方法,但一般会写有参,
           *     这样可以处理无参也可以处理有参),这个切面方法的参数就是目标的方法的返回值。
           *  5、使用@AfterReturning注解表明是后置通知
           *      参数:
           *          value:指定切入点表达式
           *          returning:指定目标方法的返回值名称,则名称必须与切面方法的参数保持一致。
           * 注意:
           *      1、如果目标方法的返回值是八种基本类型或者是String,则不可改变返回值。
           *      2、如果目标方法的返回值是引用类型,则返回值可以改变。
           */
          @AfterReturning(value = "execution(* com.itxiaoli.demo02.*.*(..))",returning = "object")
          public void myAfterReturning(Object object){
              System.out.println("后置通知功能实现~~~~~~~~~~");
              if (object != null){
                  if (object instanceof String){
                      object = object.toString().toUpperCase();
                      System.out.println("在切面方法中目标方法的返回值:"+object);
                  }
                  if (object instanceof Student){
                      Student student = (Student) object;
                      student.setName("小李");
                      System.out.println("在切面方法中目标方法的返回值是"+student);
                  }
              }
          }
      }
  • 环绕通知

      
      package com.itxiaoli.demo03;
      ​
      import org.aspectj.lang.ProceedingJoinPoint;
      import org.aspectj.lang.annotation.Around;
      import org.aspectj.lang.annotation.Aspect;
      import org.springframework.stereotype.Component;
      ​
      @Aspect
      @Component
      public class MyAspect {
          /**
           * 环绕通知方法的规范
           *  1、访问权限是public
           *  2、切面方法有返回值,此返回值就是目标的方法的返回值
           *  3、方法名称自定义
           *  4、方法有参数,参数就是目标方法
           *  5、回避异常Throwable
           *  6、使用@Around直接是声明环绕通知
           *      参数:
           *          value:指定切入点表达式
           * 注意:就算是String 也能该返回值
           */
          @Around(value = "execution(* com.itxiaoli.demo03.*.*(..))")
          public Object MyAround(ProceedingJoinPoint pjp) throws Throwable {
      //        前切功能实现
              System.out.println("环绕通知中的前置功能实现~~~~");
      //        目标方法调用
              Object obj = pjp.proceed(pjp.getArgs());
      //        后切功能实现
              System.out.println("环绕通知中的后置功能实现~~~~");
              return obj.toString().toUpperCase(); //改变了目标方法的返回值
          }
      }
  • 最终通知

      
      package com.itxiaoli.demo04;
      ​
      import org.aspectj.lang.annotation.After;
      import org.aspectj.lang.annotation.Aspect;
      import org.springframework.stereotype.Component;
      ​
      @Aspect
      @Component
      public class MyAspect {
          /**
           * 最终通知的方法的规范
           *  1、访问权限是public
           *  2、方法没有返回值
           *  3、方法名称自定义
           *  4、方法没有参数,如果有也只能是JoinPoint
           *  5、使用@After注解表明最终通知
           *      参数:
           *          value:指定切入点表达式
           */
          @After(value = "execution(* com.itxiaoli.demo04.*.*(..))")
          public void MyAfter(){
              System.out.println("最终通知!!!!!!!!!");
          }
      }

给切入点表达式起别名@Pointcut

如果多个切面切入到同一个切入点,可以使用别名简化开发. 使用@Pointcut注解,创建一个空方法,此方法的名称就是别名.

  
  @Aspect
  @Component
  public class MyAspect {
      @After(value = "mycut()")
      public void myAfter(){
          System.out.println("最终通知的功能........");
      }
  ​
      @Before(value = "mycut()")
      public void myBefore(){
          System.out.println("前置通知的功能........");
      }
  ​
      @AfterReturning(value = "mycut()",returning = "obj")
      public void myAfterReturning(Object obj){
          System.out.println("后置通知的功能........");
      }
      @Around(value = "mycut()")
      public Object myAround(ProceedingJoinPoint pjp) throws Throwable {
          System.out.println("环绕通知中的前置通知的功能........");
          Object obj = pjp.proceed(pjp.getArgs());
          System.out.println("环绕通知中的后置通知的功能........");
          return obj;
      }
  ​
      @Pointcut(value = "execution(* com.bjpowernode.s04.*.*(..))")
      public void mycut(){}
  }

SM整合的步骤

  1. 建表

  2. 新建项目,选择quickstart模板

  3. 修改目录

  4. 修改pom.xml文件,添加相关的依赖(使用老师提供)

      
      <dependencies>
          <!--单元测试-->
          <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.11</version>
            <scope>test</scope>
          </dependency>
          <!--aspectj依赖-->
          <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>5.2.5.RELEASE</version>
          </dependency>
          <!--spring核心ioc-->
          <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.2.5.RELEASE</version>
          </dependency>
          <!--做spring事务用到的-->
          <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>5.2.5.RELEASE</version>
          </dependency>
          <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.2.5.RELEASE</version>
          </dependency>
          <!--mybatis依赖-->
          <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.1</version>
          </dependency>
          <!--mybatis和spring集成的依赖-->
          <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>1.3.1</version>
          </dependency>
          <!--mysql驱动-->
          <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.32</version>
          </dependency>
          <!--阿里公司的数据库连接池-->
          <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.12</version>
          </dependency>
        </dependencies>
      ​
        <build>
          <!--目的是把src/main/java目录中的xml文件包含到输出结果中。输出到classes目录中-->
          <resources>
            <resource>
              <directory>src/main/java</directory><!--所在的目录-->
              <includes><!--包括目录下的.properties,.xml 文件都会扫描到-->
                <include>**/*.properties</include>
                <include>**/*.xml</include>
              </includes>
              <filtering>false</filtering>
            </resource>
            <resource>
              <directory>src/main/resources</directory><!--所在的目录-->
              <includes><!--包括目录下的.properties,.xml 文件都会扫描到-->
                <include>**/*.properties</include>
                <include>**/*.xml</include>
              </includes>
              <filtering>false</filtering>
            </resource>
          </resources>
        </build>
  5. 添加MyBatis相应的模板(SqlMapConfig.xml和XXXMapper.xml文件)

      
      <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
              "http://mybatis.org/dtd/mybatis-3-config.dtd">
      <configuration>
      ​
          <!--读取属性文件中数据库的配置-->
          <properties resource="db.properties"></properties>
          <!--设置日志输出语句,显示相应操作的sql语名-->
          <settings>
              <setting name="logImpl" value="STDOUT_LOGGING"/>
          </settings>
          <typeAliases>
              <package name="com.bjpowernode.pojo"></package>
          </typeAliases>
          <environments default="development">
              <environment id="development">
                  <transactionManager type="JDBC"/>
                  <dataSource type="POOLED">
                      <property name="driver" value="com.mysql.jdbc.Driver"/>
                      <property name="url"
                                value="jdbc:mysql://localhost:3308/ssm?useSSL=false&amp;serverTimezone=UTC&amp;allowPublicKeyRetrieval=true"/>
                      <property name="username" value="root"/>
                      <property name="password" value="123456"/>
                  </dataSource>
              </environment>
          </environments>
          <mappers>
              <package name="mapper文件所在的包名"></package>
          </mappers>
      </configuration>
  6. 添加SqlMapConfig.xml文件(MyBatis核心配置文件),并拷贝jdbc.propertiest属性文件到resources目录下

      
      jdbc.driverClassName=com.mysql.jdbc.Driver
      jdbc.url=jdbc:mysql://localhost:3306/ssm?useUnicode=true&characterEncoding=utf8
      jdbc.username=root
      jdbc.password=123
  7. 添加applicationContext_mapper.xml

  8. 添加applicationContext_service.xml

  9. 添加Users实体类,Accounts实体类

  10. 添加mapper包,添加UsersMapper接口和UsersMapper.xml文件并开发

  11. 添加service包,添加UsersService接口和UsersServiceImpl实现类

  12. 添加测试类进行功能测试

事务

基于注解的事务添加步骤

  1. 在applicationContext_service.xml文件中添加事务管理器

      
      <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
              <!--因为事务必须关联数据库处理,所以要配置数据源-->
              <property name="dataSource" ref="dataSource"></property>
           </bean>
  2. 在applicationContext_service.xml文件中添加事务的注解驱动

      
      <tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
  3. 在业务逻辑的实现类上添加注解@Transactional(propagation = Propagation.REQUIRED) REQUIRED表示增删改操作时必须添加的事务传播特性

@Transactional注解参数详解

  @Transactional(
          propagation = Propagation.REQUIRED, //事务的传播
          noRollbackForClassName = "ArithmeticException",  //指定发生什么异常不回滚,使用的是异常的名称
          noRollbackFor = ArithmeticException.class,      //指定发生什么异常不回滚,使用的是异常的类型
          rollbackForClassName = "",                      //指定发生什么异常必须回滚
          rollbackFor = ArithmeticException.class,        //指定发生什么异常必须回滚
          timeout = -1,                                   //连接超时设置,默认值为-1,表示永不超时
          readOnly = true,                                //默认是false,如果是查询操作,必须设置为true
          isolation = Isolation.DEFAULT                   //使用数据库自己的隔离级别
  )

Spring的两种事务处理方式

  • 注解式的事务

  • 声明式事务(必须掌握),在配置文件中添加一次,整个项目遵循事务的设定.

Spring中事务的五大隔离级别

  • 未提交读(Read Uncommitted):允许脏读,也就是可能读取到其他会话中未提交事务修改的数据

  • 提交读(Read Committed):只能读取到已经提交的数据。Oracle等多数数据库默认都是该级别 (不重复读)

  • 可重复读(Repeated Read):可重复读。在同一个事务内的查询都是事务开始时刻一致的,InnoDB默认级别。在SQL标准中,该隔离级别消除了不可重复读,但是还存在幻象读,但是innoDB解决了幻读

  • 串行读(Serializable):完全串行化的读,每次读都需要获得表级共享锁,读写相互都会阻塞

  • 使用数据库默认的隔离级别isolation = Isolation.DEFAULT

注意(面试!):

  • MySQL:mysql默认的事务处理级别是'REPEATABLE-READ',也就是可重复读

  • Oracle:oracle数据库支持READ COMMITTED 和 SERIALIZABLE这两种事务隔离级别。默认系统事务隔离级别是READ COMMITTED,也就是读已提交

Spring事务的传播特性

多个事务之间的合并,互斥等都可以通过设置事务的传播特性来解决.

  • PROPAGATION_REQUIRED:必被包含事务(增删改必用)

  • PROPAGATION_REQUIRES_NEW:自己新开事务,不管之前是否有事务

  • PROPAGATION_SUPPORTS:支持事务,如果加入的方法有事务,则支持事务,如果没有,不单开事务

  • PROPAGATION_NEVER:不能运行中事务中,如果包在事务中,抛异常

  • PROPAGATION_NOT_SUPPORTED:不支持事务,运行在非事务的环境

  • PROPAGATION_MANDATORY:必须包在事务中,没有事务则抛异常

  • PROPAGATION_NESTED:嵌套事务

声明式事务

Spring非常有名的事务处理方式.声明式事务. 要求项目中的方法命名有规范

  1. 完成增加操作包含 add save insert set

  2. 更新操作包含 update change modify

  3. 删除操作包含 delete drop remove clear

  4. 查询操作包含 select find search get

  
  <!--导入applicationContext_mappers.xml-->
      <import resource="applicationCintext_mapper.xml"></import>
  <!--    添加包扫描-->
      <context:component-scan base-package="com.itxiaoli.service.impl"></context:component-scan>
  <!--    添加事务管理器-->
      <bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
          <property name="dataSource" ref="dataSource"></property>
      </bean>
  <!--    配置事务切面-->
      <tx:advice id="myadvice" transaction-manager="dataSourceTransactionManager">
          <tx:attributes>
              <tx:method name="*select*" read-only="true"/>
              <tx:method name="*find*" read-only="true"/>
              <tx:method name="*search*" read-only="true"/>
              <tx:method name="*get*" read-only="true"/>
              <tx:method name="*insert*" propagation="REQUIRED"/>
              <tx:method name="*add*" propagation="REQUIRED"/>
              <tx:method name="*save*" propagation="REQUIRED"/>
              <tx:method name="*set*" propagation="REQUIRED"/>
              <tx:method name="*update*" propagation="REQUIRED"/>
              <tx:method name="*change*" propagation="REQUIRED"/>
              <tx:method name="*remove*" propagation="REQUIRED"/>
              <tx:method name="*drop*" propagation="REQUIRED"/>
              <tx:method name="*delete*" propagation="REQUIRED"/>
              <tx:method name="*clear*" propagation="REQUIRED"/>
              <tx:method name="*" propagation="SUPPORTS"/>
          </tx:attributes>
      </tx:advice>
  <!--    绑定切面和切入点-->
      <aop:config>
          <aop:pointcut id="mycut" expression="execution(* com.itxiaoli.service.impl.*.*(..))"/>
          <aop:advisor advice-ref="myadvice" pointcut-ref="mycut"></aop:advisor>
      </aop:config>
  </beans>

示例

<!--    读取属性文件jdbc.properties-->
    <context:property-placeholder location="jdbc.properties"></context:property-placeholder>
<!--    创建数据源 -->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${jdbc.driverClassName}"></property>
        <property name="url" value="${jdbc.url}"></property>
        <property name="username" value="${jdbc.username}"></property>
        <property name="password" value="${jdbc.password}"></property>
    </bean>
<!--    配置SqlSessionFactoryBean类-->
    <bean class="org.mybatis.spring.SqlSessionFactoryBean">
<!--        配置数据源-->
        <property name="dataSource" ref="dataSource"></property>
<!--        配置mybatis的核心配置文件-->
        <property name="configLocation" value="SqlMapConfig.xml"></property>
<!--        注册实体类的别名-->
        <property name="typeAliasesPackage" value="com.itxiaoli.pojo"></property>
    </bean>
<!--    注册mapper.xml-->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.itxiaoli.mapper"></property>
    </bean>

    <!-- 导入applicationContext_mapper .xml-->
    <import resource="applicationCintext_mapper.xml"></import>
    <!--    SM是基于注解的开发,所以添加包扫描-->
    <context:component-scan base-package="com.itxiaoli.service.impl"></context:component-scan>
<!--    事务处理-->

<!--    添加事务管理器-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--        1、因为事务必须关联数据库处理,所以要配置数据源-->
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    <!--        2、添加事务的注解驱动-->
    <tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>

<!--导入applicationContext_mappers.xml-->
    <import resource="applicationCintext_mapper.xml"></import>
<!--    添加包扫描-->
    <context:component-scan base-package="com.itxiaoli.service.impl"></context:component-scan>
<!--    添加事务管理器-->
    <bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
<!--    配置事务切面-->
    <tx:advice id="myadvice" transaction-manager="dataSourceTransactionManager">
        <tx:attributes>
            <tx:method name="*select*" read-only="true"/>
            <tx:method name="*find*" read-only="true"/>
            <tx:method name="*search*" read-only="true"/>
            <tx:method name="*get*" read-only="true"/>
            <tx:method name="*insert*" propagation="REQUIRED"/>
            <tx:method name="*add*" propagation="REQUIRED"/>
            <tx:method name="*save*" propagation="REQUIRED"/>
            <tx:method name="*set*" propagation="REQUIRED"/>
            <tx:method name="*update*" propagation="REQUIRED"/>
            <tx:method name="*change*" propagation="REQUIRED"/>
            <tx:method name="*remove*" propagation="REQUIRED"/>
            <tx:method name="*drop*" propagation="REQUIRED"/>
            <tx:method name="*delete*" propagation="REQUIRED"/>
            <tx:method name="*clear*" propagation="REQUIRED"/>
            <tx:method name="*" propagation="SUPPORTS"/>
        </tx:attributes>
    </tx:advice>
<!--    绑定切面和切入点-->
    <aop:config>
        <aop:pointcut id="mycut" expression="execution(* com.itxiaoli.service.impl.*.*(..))"/>
        <aop:advisor advice-ref="myadvice" pointcut-ref="mycut"></aop:advisor>
    </aop:config>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: Spring Framework是一个开源的Java平台,它提供了一组全面的工具来支持Java应用程序开发。它主要包括IoC容器、AOP框架、事务管理、MVC框架、DAO框架、连接池等。它可以帮助程序员更好地组织代码,减少重复性工作,提高代码质量。手写Spring框架需要对Java编程和设计模式有较深的了解,并对Spring框架的源码有着深入的研究。 ### 回答2: Spring框架是一个开源的Java平台,用于构建企业级应用程序。它提供了一种全面的编程和配置模型,用于开发基于Java的应用程序和服务。手写Spring框架意味着从头开始实现Spring的核心功能。 手写Spring框架的基本步骤包括: 1. 创建一个核心容器类,用于管理应用程序中的Bean对象。这个容器类需要提供注册、获取和销毁Bean的功能。 2. 定义一个Bean注解,用于标识哪些类应该被容器所管理。 3. 创建一个Bean定义类,用于存储每个Bean的元数据信息,包括类名、作用域和依赖关系等。 4. 实现依赖注入功能,通过读取Bean定义中的依赖关系,将相关的Bean对象注入到目标Bean中。 5. 提供AOP(面向切面编程)功能,允许开发者在应用程序的特定点进行横切关注点的处理。 6. 实现声明式事务管理功能,使用注解或XML配置方式来处理数据库事务。 7. 提供对不同数据访问技术(如JDBC、ORM框架、NoSQL等)的支持,通过集成相应的库来简化数据访问代码。 8. 增加对Web开发的支持,如处理请求、渲染视图等。 手写Spring框架需要具备对Java语言的深入了解,熟悉反射、代理、设计模式等概念和技术。还需要对依赖注入、AOP、事务管理、Web开发等方面有一定的理解。实现一个完整的Spring框架是一个庞大而复杂的任务,需要经过反复的设计、开发和测试。通过手写Spring框架,可以更深入地理解Spring的原理和内部机制,提高对框架的使用和调试能力。 ### 回答3: 手写Spring框架是一个相当复杂的任务,但我可以简要介绍手写Spring框架的一些关键步骤和组成部分。 1. 依赖注入:Spring框架的核心概念之一是依赖注入。我们需要编写一个容器,负责管理和维护各个对象之间的依赖关系。可以使用反射机制来实现依赖注入。 2. 控制反转:Spring框架通过控制反转(IoC)来管理对象的创建和生命周期。我们需要编写一个BeanFactory,负责加载和实例化对象,并将依赖注入到相应的对象中。 3. 配置文件:手写Spring框架也需要一个配置文件,用于定义对象的依赖关系和属性。我们可以使用XML、注解或者JavaConfig等方式来定义配置文件。 4. AOP支持:Spring框架提供了面向切面编程(AOP)的支持,可以通过编写切面和通知来实现横切关注点的统一处理。我们需要实现一个AOP框架,用于拦截和处理切面逻辑。 5. MVC模式:Spring框架也提供了一个MVC框架,用于处理Web应用程序的请求和响应。我们需要编写一个DispatcherServlet,负责将请求分发给相应的控制器,并处理模型和视图的交互。 6. 整合其他技术:Spring框架还可以与其他技术进行整合,例如数据库访问、事务管理、安全性控制等。我们需要编写相应的模块,将这些技术与Spring框架集成起来。 虽然这只是一个简要的介绍,手写Spring框架是一个非常庞大的工程,需要深入理解Spring的原理和设计思想,并具备扎实的Java编程能力。但通过手写Spring框架,我们可以更好地掌握Spring的核心概念和原理,并加深对框架的理解。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值