Spring自学笔记(学完老杜视频后再进行修改)

2023-05-16

Spring

 

概念

  • Spring框架是一个储存对象的容器,是一个轻量级的开源Java开发框架,它的核心是控制反转(IoC)和面向切面编程(AOP),它由20多个模块构成,在很多领域都提供优秀的解决方案

  • Spring特点:

    • 轻量级框架

      • 由20多个模块构成,核心jar包3M大小,对代码无污染

    • 面向接口编程,解耦合

      • 使用接口,更加灵活,增强项目的可扩展性和可维护性

    • AOP 编程的支持

      • 面向切面编程:将公共的、通用的、重复的代码单独开发,在需要的时候反织回去,底层的原理是动态代理

    • 方便集成各种优秀框架

      • 整合其它框架,使其它框架更易用

Spring框架体系结构

  • Spring框架采用的是分层架构,这些模块大体分为:核心容器(Core Container)、面向切面编程(AOP,Aspects)、提供JVM代理、设备支持(Instrumentation)、数据访问/集成(Data Access/Integeration)、Web、消息(Messaging)、测试(Test)

IoC思想

  • 控制反转IoC(Inversion of Control)是一个概念,一种思想,由Spring容器进行对象的创建和依赖注入,程序员在使用时直接取出使用即可

  • 正转:由程序员进行对象的创建和依赖注入称为正转

    
    Student stu = new Student();//程序员创建对象
    stu.setName("张三");//程序员进行操作
    stu.setAge(22);  
  • 反转:由Spring容器创建对象和依赖注入称为反转,将控制权从程序员手中夺走,交给Spring容器

    
    <bean id="stu" class="com.java.spring.pojo.Student"><!--Spring容器负责对象的创建-->
    <property name="name" value="张三"></property><!--Spring容器依赖注入值-->
     <property name="name" value="张三"></property>
    </bean>  

Spring容器创建对象

  • 引入spring依赖

    
    <dependency>
     <groupId>org.springframework</groupId>
     <artifactId>spring-context</artifactId>
     <version>5.3.23</version>
    </dependency>  
  • 创建spring核心配置文件applicationContext.xml

    
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xmlns:context="http://www.springframework.org/schema/context"
          xmlns:aop="http://www.springframework.org/schema/aop"
          xmlns:tx="http://www.springframework.org/schema/tx"
          xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
                              http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
                              http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd
                              http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">
    </beans>  
  • 创建Student对象stu(在spring核心配置文件中编写)

    
    <bean id="stu" class="com.java.spring.pojo.Student"></bean>  
  • 获取对象

    
    //创建容器对象并启动,核心配置文件中创建的对象在启动时一齐创建
    ApplicationContext applicationContext = newClassPathXmlApplicationContext("applicationContext.xml");
    //获取对象
    Student student = (Student) applicationContext.getBean("student");  
  • 给创建对象赋值

    • 使用setter注入

      • 使用setter注入必须提供无参构造方法,必须提供setXxx()方法

      • 注入分为简单类型注入和引用类型注入

      • 简单类型注入使用value属性

      • 引用类型注入使用ref属性

      
      <bean id="school" class="com.java.spring.pojo.School"></bean>
      <bean id="stu" class="com.java.spring.pojo.Student">
      <property name="name" value="张三"></property>
       <property name="age" value="18"></property>
       <!--ref属性的值必须对应引用类型对象的id值-->
       <property name="school" ref="school"></property>
      </bean>  
    • 使用构造方法注入(提供有参构造方法)

      • 使用构造方法的参数名称注入值

      
      <bean id="school" class="com.java.spring.pojo.School">
      <constructor-arg name="sName" value="清华大学"></constructor-arg>
       <constructor-arg name="address" value="绿园区"></constructor-arg>
      </bean>  
      • 使用构造方法的下表注入值

      
      <bean id="stu" class="com.java.spring.pojo.Student">
      	<constructor-arg index="0" value="张三"></constructor-arg>
        <constructor-arg index="1" value="18"></constructor-arg>
        <constructor-arg index="2" ref="school"></constructor-arg>
      </bean>  
      • 使用默认的构造方法的参数的顺序注入值

      
      <bean id="stu" class="com.java.spring.pojo.Student">
      	<constructor-arg value="张三"></constructor-arg>
        <constructor-arg value="18"></constructor-arg>
        <constructor-arg ref="school"></constructor-arg>
      </bean>  

基于注解的IoC基本概念

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

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

    • 添加包扫描的方式

      • 单个包扫描(推荐)

      
      <!--添加单个包扫描-->
      <context:component-scan base-package="com.java.spring.pojo"></context:component-scan>  
      • 多个包扫描

      
      <!--添加多个包扫描,以逗号/空格/分号分隔开-->
      <context:component-scan base-package="com.java.spring.pojo,com.java.spring.controller com.java.spring.mapper;com.java.spring.service"></context:component-scan>  
      • 扫描根包(不推荐,降低容器启动速度)

      
      <!--添加根包扫描-->
      <context:component-scan base-package="com.java.spring"></context:component-scan>  
  • 创建对象的注解:

    • @Component:可以创建任意对象,创建的对象默认id名称为xxxXxx格式,指定对象的id名称:@Component("指定id名称")

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

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

    • @Repository:专门用来创建数据访问层的对象(Mapper),负责数据库中的CRUD操作

  • 依赖注入的注解:

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

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

      • 自动注入autowire属性:byType为自动寻找Bean工厂中对应类型的对象注入进来

      
      <bean id="student" class="com.java.spring.pojo.Student" autowire="byType">
      	<property name="name" value="张三"></property>
        <property name="age" value="18"></property>
        <!--	<property name="school" ref="school"></property> 不需要编写,会自动注入 -->
      </bean>
      <bean id="school" class="com.java.spring.pojo.School">
      	<property name="sName" value="清华大学"></property>
        <property name="address" value="绿园区"></property>
      </bean>  
      • 同源类型

        • 被注入的类型(Student中的school)与注入的类型是完全相同的类型

        • 被注入的类型(Student中的school为父类)与注入的类型(子类)是父子类的类型

          • 在有父子类的情况下,使用类型注入值,意味着有多个可注入的对象,此时按照名称进行二次筛选,选中与被注入对象相同名称的对象进行注入(解释:如果父类School类,子类SubSchool类,Student类中有Student类对象属性,则如果都没有设置创建对象id名称,则会默认注入School父类的对象,如果将School类对象设置为其他id名称,子类SubSchool类对象设置为school名称,则注入SubSchool类对象)

        • 被注入的类型(Student中的school为接口)与注入的类型(实现类)是接口实现类的类型

    • @Autowired+@Qualifier:使用名称注入值,从整个Bean工厂搜索相同名称的对象进行注入

      • 单独使用@Qualifier注解,不会报错,但是注入值为null

      • 自动注入autowire属性:byName为自动寻找Bean工厂中对应类型的对象注入进来

      
      <bean id="student" class="com.java.spring.pojo.Student" autowire="byName">
      	<property name="name" value="张三"></property>
        <property name="age" value="18"></property>
        <!--	<property name="school" ref="school"></property> 不需要编写,会自动注入 -->
      </bean>
      <bean id="school" class="com.java.spring.pojo.School">
      	<property name="sName" value="清华大学"></property>
        <property name="address" value="绿园区"></property>
      </bean>  
    • @Resource:标注的属性默认按照ByName进行注入(@Resource(type=LaService.class)/@Resource(type=LaServiceImpl.class))

  • 拆分配置文件策略

    • 按层拆

    
    <!--applicationContext_controller.xml-->
    <bean id="usersController" class="com.java.spring.controller.UsersController"></bean>
    <bean id="rootsController" class="com.java.spring.controller.RootsController"></bean>
    <!--applicationContext_service.xml-->
    <bean id="usersService" class="com.java.spring.service.UsersService"></bean>
    <bean id="rootsService" class="com.java.spring.service.RootsService"></bean>
    <!--applicationContext_mapper.xml-->
    <bean id="usersMapper" class="com.java.spring.mapper.UsersMapper"></bean>
    <bean id="rootsMapper" class="com.java.spring.mapper.RootsMapper"></bean>  
    • 按功能拆

    
    <!--applicationContext_users.xml-->
    <bean id="usersController" class="com.java.spring.controller.UsersController"></bean>
    <bean id="usersService" class="com.java.spring.service.UsersService"></bean>
    <bean id="usersMapper" class="com.java.spring.mapper.UsersMapper"></bean>
    <!--applicationContext_roots.xml-->
    <bean id="rootsController" class="com.java.spring.controller.RootsController"></bean>
    <bean id="rootsService" class="com.java.spring.service.RootsService"></bean>
    <bean id="rootsMapper" class="com.java.spring.mapper.RootsMapper"></bean>  
  • Spring核心配置文件整合

    • total.xml

      
      <!--total.xml文件为整合配置文件,将拆分的分层xml整合成一个文件-->
      <?xml version="1.0" encoding="UTF-8"?>
      <beans xmlns="http://www.springframework.org/schema/beans"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xmlns:context="http://www.springframework.org/schema/context"
             xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
        <!--单个xml导入-->
        <import resource="applicationContext_controller.xml"></import>
        <import resource="applicationContext_service.xml"></import>
        <import resource="applicationContext_mapper.xml"></import>
        
        <!--批量xml导入-->
        <import resource="applicationContext_*.xml"></import>
      </beans>  

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

  • 公共的、通用的、重复的代码称为切面,将切面提取出来单独开发,在需要调用的方法中通过动态代理的方式进行织入

  • Spring原生AOP的通知

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

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

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

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

  • Spring原生AOP实现原理:提供业务接口、业务功能、切面功能即可(底层动态代理实现)

    
    <!--创建业务对象-->
    <bean id="bookServiceTarget" class="com.java.spring.service.impl.BookServiceImpl"></bean>
    <!--创建切面对象-->
    <bean id="logAdvice" class="com.java.spring.advice.LogAdvice"></bean>
    <!--绑定业务和切面-->
    <bean id="bookService" class="org.springframework.aop.framework.ProxyFactoryBean">
    	<property name="interfaces" value="com.java.spring.service.BookService"></property>
      <property name="interceptorNames">
      	<list>
        	<value>logAdvice</value>
        </list>
      </property>
      <!--织入-->
      <property name="target" ref="bookServiceTarget"></property>
    </bean>  
  • AOP中的常用术语

    • 切面:重复的、公共的、通用的功能被称为切面,例如:日志、事务、权限

      • 使用@Aspect注解,将一个类标注为切面供容器读取

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

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

      • 例子如下:(value值相当于一个切入点)

      
      @Aspect
      public class myAspect{
        //这个切入点为一个具体权限、返回值、包目录下的具体类中的具体方法,将日志处理切入到这个具体方法之前
        @Before(value="execution(public void com.java.spring.service.BookServiceImpl.doSome(String,int))")
        //这个切入点为任意权限、返回值、包目录下的具体类中的任意方法,将日志处理切入到这些方法之前
        @Before(value="execution(* *...service.BookServiceImpl.*(..))")
        //这个切入点为所有类的所有方法,将日志处理切入到所有方法之前
        @Before(value="execution(* *.*(..))")
        public void myAspect(){
          System.out.println("前置日志处理");
        }
      }  
    • 目标对象:操作谁,谁就是目标对象

    • 通知(Advice):来指定切入的时机,是在目标方法执行前/后/出错/环绕目标方法切入切面功能,例如:@Before、@AfterReturning、@Around等

AspectJ框架

  • AspectJ是一个优秀面向切面的框架,它扩展了java语言,提供了强大的切面实现,兼容Java平台,可以无缝扩展

  • AspectJ的通知类型

    • @Before:前置通知

      • 在目标方法执行前切入切面功能,只能获得目标方法的签名,获得不到目标方法的返回值,因为目标方法未执行

      • 前置通知的切面方法规范:

        • 访问权限public

        • 方法返回值void

        • 方法没有参数,有只能是JoinPoint接口类型对象(目标方法签名的拦截)

          • 获取目标方法的签名:JoinPoint对象的getSignature方法

          • 获取目标方法的参数:JoinPoint对象的getArgs方法(返回的为Object[]数组)

        • 必须使用@Before注解来声明切入时机

          • 参数:

            • value:指定切入点表达式

    • @AfterReturning:后置通知

      • 在目标方法执行后切入切面功能,切入功能方法参数为目标方法的返回值,因为目标方法已执行完毕

      • 如果目标方法的返回值为基本数据类型+String类型,则不可更改值,如果返回值为引入类型,则可以更改值

      • 后置通知的切面方法规范:

        • 访问权限public

        • 方法返回值void

        • 方法有参数,参数为目标方法的返回值(如果目标方法没有返回值,则无参)

        • 必须使用@AfterReturning注解来声明切入时机

          • 参数:

            • value:指定切入点表达式

            • returning:指定目标方法的返回值的名称,则名称必须与切面方法的参数名称一致

    • @Around:环绕通知

      • 通过拦截目标方法的方式,在目标方法执行前后增强功能的通知,一般事务使用此通知

      • 环绕通知的切面方法规范:

        • 访问权限public

        • 方法有返回值,返回值为目标方法的返回值

        • 方法有参数,参数为目标方法本身(目标方法为ProceedingJoinPoint接口类型对象)

          • 目标方法调用:Object obj = ProceedingJoinPoint对象.proceed(ProceedingJoinPoint对象.getArgs());

        • 回避异常Throwable

        • 使用@Around注解声明环绕目标方法

          • 参数:

            • value:指定切入点表达式

        
        @Around()
        public Object myAround(ProceedingJoinPoint pjp) throws Throwable{
          //前置通知功能
          System.out.println("前置通知功能实现");
          //业务功能实现
          Object obj = pjp.proceed(pjp.getArgs());
          //后置通知功能
          System.out.println("后置通知功能实现");
          return obj;
        }  
    • @After:最终通知

      • 无论目标方法是否正常执行,最终通知的代码都会被执行

      • 最终通知的切面方法规范:

        • 访问权限public

        • 方法返回值void

        • 方法没有参数,有只能是JoinPoint接口类型对象(目标方法签名的拦截)

        • 使用@After注解声明切面方法永远被执行

          • 参数:

            • value:指定切入点表达式

    • @Aspect:将一个类标注为切面供容器读取

    • @Pointcut:定义切入点,给切入点表达式起别名(@Before的value值)

      • Pointcut是切入通知的触发条件。每个Pointcut的定义包括2部分,一是表达式,二是方法签名。方法签名必须是 public及void型。可以将Pointcut中的方法看作是一个被通知引用的助记符,因为表达式不直观,因此我们可以通过方法签名的方式为 此表达式命名。因此Pointcut中的方法只需要方法签名,而不需要在方法体内编写实际代码。

      
      @Around(value="myPointcut()")
      public Object myAround(ProceedingJoinPoint pjp) throws Throwable{
        //前置通知功能
        //业务功能实现
        //后置通知功能
        return obj;
      }
      @Pointcut(value="execution(* com.java.spring.service.*.*(..))")
      public void myPointcut(){}  
    • @AfterThrowing:异常抛出通知

  • AspectJ的通知顺序:环绕通知中前置通知->前置通知->业务方法->环绕通知中后置通知->最终通知->后置通知

  • AspectJ的切入点表达式

    • 规范公式:execution(访问权限? 方法返回值 包名类名.方法名(参数) 抛出异常类型?)

      • ?表示可选择的部分,可以省略

      • 使用"*"通配符来代表任意

      • 使用"..",如果出现在参数上,则代表任意参数;如果出现在路径上,则代表本路径及其所有子路径

  • 使用AspectJ框架开发

    • 第一步:引入依赖

    
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aspects</artifactId>
      <version>5.3.23</version>
    </dependency>  
    • 第二步:创建业务接口/业务实现类/切面类

    
    //创建业务接口
    public interface SomeService { 
      String doSome(String name, int age);
    }
    //创建业务实现类
    public class SomeServiceImpl implements SomeService { 
      public String doSome(String name, int age) {
        return "abc";
      }
    }
    //创建切面类
    @Aspect
    public class LogAspect { 
      public void myBefore(){
        System.out.println("切面方法中的前置通知功能");
      }
    }  
    • 第三步:在Spring核心配置文件applicationContext.xml文件中进行切面绑定

    
    <!--创建业务对象-->
    <bean id="someService" class="com.java.spring.service.SomeServiceImpl"></bean>
    <!--创建切面对象-->
    <bean id="logAspect" class="com.java.spring.asperts.LogAspect"></bean>
    <!--默认JDK动态代理绑定-->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
    <!--切换CGLib动态代理(子类代理)绑定-->
    <aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy>  

Spring集成MyBatis

  • 第一步:建表

    
    create table users(
    	userid int primary key,
      uname varchar(255),
      upass varchar(255)
    );  
  • 第二步:新建项目,修改目录,创建文件存放目录

  • 第三步:修改pom.xml配置文件,添加相关依赖

    
    <properties>
      <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
      <maven.compiler.source>17</maven.compiler.source>
      <maven.compiler.target>17</maven.compiler.target>
    </properties>
    <dependencies>
      <!--单元测试-->
      <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.13.2</version>
        <scope>test</scope>
      </dependency>
      <!--MySQL驱动-->
      <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.28</version>
      </dependency>
      <!--MyBatis依赖-->
      <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.5.10</version>
      </dependency>
      <!--logback依赖-->
      <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-classic</artifactId>
        <version>1.2.11</version>
      </dependency>
      <!--lombok依赖-->
      <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.22</version>
      </dependency>
      <!--数据库连接池-->
      <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid</artifactId>
        <version>1.2.5</version>
      </dependency>
      <!--servlet依赖-->
      <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>4.0.1</version>
        <scope>provided</scope>
      </dependency>
      <!--Spring核心IoC-->
      <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.3.23</version>
      </dependency>
      <!--AspectJ依赖-->
      <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aspects</artifactId>
        <version>5.3.23</version>
      </dependency>
      <!--Spring事务-->
      <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-tx</artifactId>
        <version>5.3.23</version>
      </dependency>
      <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>5.3.23</version>
      </dependency>
      <!--MyBatis与Spring集成依赖-->
      <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis-spring</artifactId>
        <version>2.0.4</version>
      </dependency>
    
    </dependencies>
    <build>
      <finalName>SM</finalName>
      <!--目的是把src/main/java目录下的xml文件包含到输出结果中,输出到classes目录下-->
      <resources>
        <resource>
          <directory>src/main/java</directory>
          <includes>
            <include>**/*.xml</include>
            <include>**/*.properties</include>
          </includes>
        </resource>
        <resource>
          <directory>src/main/resources</directory>
          <includes>
            <include>**/*.xml</include>
            <include>**/*.properties</include>
          </includes>
        </resource>
      </resources>
    </build>  
  • 第四步:提供MyBatis的核心配置文件mybatis-config.xml和jdbc.properties文件

    
    <?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>
    <!--	 	   	 注释掉的代码都是applicationContext_mapper.xml文件中已经配置好的信息						 	 -->
    <!--    <properties resource="jdbc.properties"></properties>-->
        <!--设置日志输出语句,显示相应操作的sql语名-->
        <settings>
            <setting name="logImpl" value="STDOUT_LOGGING"/>
        </settings>
    <!--    <typeAliases>-->
    <!--        <package name="com.java.spring.pojo"/>-->
    <!--    </typeAliases>-->
    <!--    <environments default="dev">-->
    <!--        <environment id="dev">-->
    <!--            <transactionManager type="JDBC"/>-->
    <!--            <dataSource type="POOLED">-->
    <!--                <property name="driver" value="${jdbc.driver}"/>-->
    <!--                <property name="url" value="${jdbc.url}"/>-->
    <!--                <property name="username" value="${jdbc.username}"/>-->
    <!--                <property name="password" value="${jdbc.password}"/>-->
    <!--            </dataSource>-->
    <!--        </environment>-->
    <!--    </environments>-->
    <!--    <mappers>-->
    <!--        <package name="com.java.spring.mapper"/>-->
    <!--    </mappers>-->
    </configuration>  
    
    jdbc.driver=com.mysql.cj.jdbc.Driver
    jdbc.url=jdbc:mysql://localhost:3306/testnode?serverTimezone=UTC
    jdbc.username=root
    jdbc.password=xiangxi666  
  • 第五步:提供Spring的核心配置文件applicationContext_mapper.xml(Spring整合MyBatis的配置信息)

    
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:context="http://www.springframework.org/schema/context"
           xmlns:aop="http://www.springframework.org/schema/aop"
           xmlns:tx="http://www.springframework.org/schema/tx"
           xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
                               http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
                               http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd
                               http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">
    
      <!--读取属性文件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.driver}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
      </bean>
      <!--配置SqlSessionFactoryBean类-->
      <bean class="org.mybatis.spring.SqlSessionFactoryBean">
        <!--配置数据源-->
        <property name="dataSource" ref="dataSource"></property>
        <!--配置MyBatis核心配置文件-->
        <property name="configLocation" value="mybatis-config.xml"></property>
        <!--注册实体类别名-->
        <property name="typeAliasesPackage" value="com.java.spring.pojo"></property>
      </bean>
      <!--注册XxxMapper.xml文件-->
      <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.java.spring.mapper"></property>
      </bean>
    </beans>  

    和applicationContext_service.xml(Spring核心配置文件功能xml)

    
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:context="http://www.springframework.org/schema/context"
           xmlns:aop="http://www.springframework.org/schema/aop"
           xmlns:tx="http://www.springframework.org/schema/tx"
           xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
                               http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
                               http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd
                               http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">
    
      <!--导入applicationContext_mapper.xml文件-->
      <import resource="applicationContext_mapper.xml"></import>
      <!--SM整合是基于注解开发,添加包扫描-->
      <context:component-scan base-package="com.java.spring.service.impl"></context:component-scan>
      <!--事务处理-->
      <!--1.添加事务管理器-->
      <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <!--事务必须关联数据库处理,所以要配置数据源-->
        <property name="dataSource" ref="dataSource"></property>
      </bean>
      <!--2.添加事务的注解驱动(annotation-driven是http://www.springframework.org/schema/tx下的)-->
      <tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
    </beans>  
    • 添加事务管理器原因

      • 事务管理器用来生成相应技术的连接对象

        • JDBC:Connection对象 conn.commit() conn.rollback()

        • MyBatis:SqlSession对象 sqlSession.commit() sqlSession.rollback()(使用DataSourceTransactionManager类完成处理)

        • Hibernate:Session对象 session.commit() session.rollback()(使用HibernateTransactionManager类完成处理)

  • 第六步:提供Users POJO类

    
    //使用lombok注解来简化POJO类
    @NoArgsConstructor
    @AllArgsConstructor
    @EqualsAndHashCode
    @ToString
    public class Users {
      @Setter
      @Getter
      private int userid;
      @Setter
      @Getter
      private String uname;
      @Setter
      @Getter
      private String upass;
    }  
  • 第七步:添加UsersMapper接口和对应UsersMapper.xml文件

    
    public interface UsersMapper {
      int insert(Users users);
    }  
    
    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapper
            PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="com.java.spring.mapper.UsersMapper">
      <!--parameterType值可以写成users,因为在applicationContext_mapper.xml中已经开启设置别名配置-->
      <insert id="insert" parameterType="com.java.spring.pojo.Users">	
        insert into users values(#{userid},#{uname},#{upass})
      </insert>
    </mapper>  
  • 第八步:添加UsersService接口和对应UsersServiceImpl实现类

    
    public interface UsersService {
      int insert(Users users);
    }  
    
    @Service
    //设置传播特性
    @Transactional(propagation = Propagation.REQUIRED)	//必须添加事务
    public class UsersServiceImpl implements UsersService {
    
      @Autowired
      UsersMapper usersMapper;
    
      @Override
      public int insert(Users users) {
        int count = 0;
        count = usersMapper.insert(users);
        return count;
      }
    }  
  • 第九步:添加测试类进行功能测试

    
    @Test
    public void testInsert(){
      //创建容器并启动
      ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext_service.xml");
      //获取UsersServiceImpl对象
      UsersService usersService = (UsersService) applicationContext.getBean("usersServiceImpl");
      int count = usersService.insert(new Users(1001,"张三","123456"));
      }
    }  

Spring的两种事务处理方式

  • 注解式的事务

    • 使用@Transactional注解完成事务控制,此注解可添加到方法上,只是对此方法执行事务处理,此注解可添加到类上,则对类中所有方法执行事务的设定

    • Spring事务传播特性@Transactional注解

      • 参数:

        • propagation:设置事务传播机制,多个事务之间的合并、互斥等都可以通过设置事务的传播特性来解决(默认为REQUIRED)

          • REQUIRED:支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。 (增删改必用)

          • SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行。

          • REQUIRES_NEW:新建事务,如果当前存在事务,把当前事务挂起。

          • NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。

          • NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。

          • MANDATORY:支持当前事务,如果当前没有事务,就抛出异常。

          • NESTED:支持当前事务,如果当前事务存在,则执行一个嵌套事务,如果当前没有事务,就新建一个事务。

        • timeout:事务超时设置(单位为秒,默认-1,永不超时)

        • isolation:事务隔离级别(默认为DEFAULT)

          • Isolation.DEFAULT:使用各个数据库默认的隔离级别

            • MYSQL:默认为REPEATABLE_READ

              • MySQL数据库,当且仅当引擎是InnoDB,才支持事务(MyIsam引擎不支持事务)

            • SQLSERVER:默认为READ_COMMITTED

            • Oracle:默认为READ_COMMITTED

          • Isolation.READ_UNCOMMITTED : 读取未提交数据(会出现脏读, 不可重复读) 基本不使用

          • Isolation.READ_COMMITTED : 读取已提交数据(会出现不可重复读和幻读)

          • Isolation.REPEATABLE_READ:可重复读(会出现幻读)

          • Isolation.SERIALIZABLE:串行化

        • readOnly:事务读写性(默认为false)

          • 如果是查询操作,必须设置为true

        • noRollbackFor:指定发生什么异常不回滚,使用异常类型(例:ArithmeticException.class)

        • noRollbackForClassName:指定发生什么异常不回滚,使用异常名称(例:{"ArithmeticException","RuntimeException"})

        • rollbackFor:指定发生什么异常回滚,使用异常类型(例:ArithmeticException.class)

        • rollbackForClassName:指定发生什么异常回滚,使用异常名称(例:{"ArithmeticException","RuntimeException"})

    • UsersServiceImplAccountsServiceImpl(抛异常)结果
      场景一无事务无事务users=OK accounts=OK
      场景二无事务REQUIREDusers=OK accounts=NO
      场景三REQUIRED无事务users=NO accounts=NO
      场景四REQUIREDNOT_SUPPORTEDusers=NO accounts=OK
      场景五REQUIREDSUPPORTSusers=NO accounts=NO
      场景六REQUIREDREQUIRES_NEWusers=NO accounts=NO
      场景七REQUIREDREQUIREDusers=NO accounts=NO
      场景八REQUIREDNEVERAccountsServiceImpl直接跳出报异常
  • 声明式的事务

    • 在配置文件中添加一次,整个项目遵循事务的设定

      
      <?xml version="1.0" encoding="UTF-8"?>
      <beans xmlns="http://www.springframework.org/schema/beans"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xmlns:context="http://www.springframework.org/schema/context"
             xmlns:aop="http://www.springframework.org/schema/aop"
             xmlns:tx="http://www.springframework.org/schema/tx"
             xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
                                 http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
                                 http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd
                                 http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">
      
        <!--此配置文件与applicationContext_service.xml功能一样,只是事务配置不同-->
        <!--导入applicationContext_mapper.xml-->
        <import resource="applicationContext_mapper.xml"></import>
        <!--添加包扫描-->
        <context:component-scan base-package="com.java.spring.service.impl"></context:component-scan>
        <!--添加事务管理器-->
        <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
          <property name="dataSource" ref="dataSource"></property>
        </bean>
        <!--配置事务切面-->
        <tx:advice id="advice" transaction-manager="transactionManager">
          <tx:attributes>
            <tx:method name="*select*" read-only="true"></tx:method>
            <tx:method name="*add*" read-only="true"></tx:method>
            <tx:method name="*find*" read-only="true"></tx:method>
            <tx:method name="*search*" read-only="true"></tx:method>
            <tx:method name="*get*" read-only="true"></tx:method>
            <tx:method name="*insert*" propagation="REQUIRED"></tx:method>
            <tx:method name="*add*" propagation="REQUIRED"></tx:method>
            <tx:method name="*save*" propagation="REQUIRED"></tx:method>
            <tx:method name="*set*" propagation="REQUIRED"></tx:method>
            <tx:method name="*update*" propagation="REQUIRED"></tx:method>
            <tx:method name="*change*" propagation="REQUIRED"></tx:method>
            <tx:method name="*modify*" propagation="REQUIRED"></tx:method>
            <tx:method name="*delete*" propagation="REQUIRED"></tx:method>
            <tx:method name="*drop*" propagation="REQUIRED"></tx:method>
            <tx:method name="*remove*" propagation="REQUIRED"></tx:method>
            <tx:method name="*clear*" propagation="REQUIRED"></tx:method>
            <tx:method name="*" propagation="SUPPORTS"></tx:method>
          </tx:attributes>
        </tx:advice>
        <!--绑定切面和切入点-->
        <aop:config>
          <aop:pointcut id="pointcut" expression="execution(* com.java.spring.service.impl.*.*(..))"/>
          <aop:advisor advice-ref="advice" pointcut-ref="pointcut"></aop:advisor>
        </aop:config>
      </beans>  
    • 当个别事务想屏蔽全局事务控制,则可以添加注解式事务和声明式事务的优先级order

Spring中事务的五大隔离级别

  • 数据库默认的隔离级别

    • MYSQL:Repeated Read

      • MySQL数据库,当且仅当引擎是InnoDB,才支持事务(MyIsam引擎不支持事务)

    • SQLSERVER:Read Committed

    • Oracle:READ_COMMITTED

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

  • 提交读(Read Committed):只能读取到已经提交的数据(不可重复读)

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

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

学习过程另一套笔记

一.介绍Spring框架

1.1学习Spring框架的原因

企业级应用是指那些为商业组织,大型企业而创建并部署的解决方案。这些大型企业级应用的结构复杂,涉及的外部资源众多,事务密集,数据规模大,用户数量多,有较强的安全性考虑和较高的性能要求。

而且企业级应用不但要有强大的功能,还要能够满足未来业务需求的变化,易于扩展和维护。

传统JavaEE解决企业级应用问题时的开发效率,开发难度和实际的性能都令人失望。正在人们苦苦寻找解决办法的时候,Spring以一个"救世主"的形象出现在广大java程序员面前。

说到Spring就得提到它的作者Rod Johnson ,2002年他在编写的书中对 传统的JavaEE技术日益臃肿和低效提出了质疑,他觉得应该有更便捷的做法。2003年2月Spring框架正式成为一个开源项目。

Spring致力于Java EE应用的各种解决方案,而不是仅仅专注于某一层的方案。可以说,Spring是企业应用开发的“一站式”选择,Spring贯穿表现层,业务层,持久层。然而,Spring并不想取代那些已有的框架,而是以高度的开放性与它们无缝整合。

总结:使用传统javaEE开发企业级引用存在 代码层和层之间的耦合性比较高;后期的扩展性比较低** Spring 解决了业务层和其他各层之间的耦合 (高内聚、低耦合)**

1.2介绍Spring

Spring 的全称: Spring Framework

Spring是一个优秀的开源的轻量级的企业应用开发框架,是为了解决企业应用程序开发复杂性而创建的。它大大简化了java企业级开发的复杂性,提供了强大,稳定的功能,能够创建出松耦合,易测试,易扩展,易维护的java应用系统,又没有带来额外的负担。它坚持一个原则:不重新发明轮子。已经有较好解决方案的领域,Spring绝不做重复性的实现。例如对象持久化和ORM,Spring只是对现有的JDBC,mybatis,等技术提供支持,使之更易用,而不是重新做一个实现。框架的主要优势之一就是其分层架构,分层架构允许您选择使用哪一个组件。

Spring 的核心代码均来自于真实的项目,Rod Johnson是这个产品的创造者,是从商业项目开发实践中逐步提炼出的一种架构基调。

从2003年正式启动,整个项目的开发始终贯彻着如下的核心架构理念:

A.降低开发成本,方便使用,促进良好的编程习惯

B.整合各类框架,遵守轮子理论(不重复的造轮子 ,使用现有的轮子)

C.易于选择,方便测试

D.统一配置,灵活可扩展

E.非侵入式

F.提供最好的IOC解决方案

G.提供最好的AOP解决方案

1.3介绍Spring的架构图


  Spring框架由大约20个功能模块组成。组成Spring 框架的每个模块(或组件)都可以单独存在,或者与其他一个或多个模块联合实现。每个模块的功能如下:  

Spring Core:核心容器提供Spring 框架的基本功能,为Spring提供了基础服务支持,核心容器的主要组件是BeanFactory 。

通过BeanFactory,Spring使用工厂模式来实现控制反转(IOC ) ,将应用程序的配置和依赖关系与实际的应用程序代码分开

Spring之所以称为容器,就是由于BeanFactory的自动装备和注入。

Spring Context:Spring 上下文是一个配置文件,向Spring 框架提供上下文信息。主要用于加载属性文件,扫描本地的包等

BeanFactory使Spring成为容器,上下文模块使Spring成为框架。

这个模块对BeanFactory进行了扩展,添加了对I18N,系统生命周期事件以及验证的支持。这个模块提供了许多企业级服务,例如:邮件服务、JNDI访问 、EJB集成、远程调用以及定时服务,并且支持与模板框架的集成。

Spring AOP : 通过配置管理特性,Spring AOP 模块直接将面向切面编程功能集成到了Spring 框架中(AOP把一个业务流程分成几部分,例如权限检查、业务处理、日志记录, 每个部分单独处理,然后把它们组装成完整的业务流程。每个部分被称为切面)。所以,可以很容易地使Spring 框架管理的任何对象支持AOP 。Spring AOP 模块为基于Spring 的应用程序中的对象提供了事务管理服务。

Spring JDBC:这个模块封装了数据库连接的创建、语句对象生成、结果集处理、连接关闭等操作,而且重构了所有数据库系统的异常信息,用户不在需要处理数据库异常了。提供了JDBC的抽象层,简化了JDBC编码,同时使代码更健壮。 在这个模块中,利用了Spring的AOP模块完成了为系统中对象提供事务管理的服务。

Spring ORM :Spring没有实现自己的ORM方案,而是为当前主流的ORM框架预留了整合接口,包括Mybatis,Hibernate等。所有这些都遵从Spring 的通用事务和DAO 异常层次结构。 Spring的事务管理支持所有这些ORM框架以及JDBC。

Spring web:集成各种优秀的web层框架的模块(Struts、Springmvc)

1.4Spring框架学习

1.4.1 Spring 学习的核心内容

  1. IOC:控制反转--帮助我们创建对象的

  2. AOP:面向切面编程---提升代码的扩展性,有点像过滤器.针对方法.

  3. TX:声明式事务管理---强大事务管理机制.事务过程不需要程序员编写,只需要声明出哪些方法需要进行事务管理.

1.4.2Spring学习必备资料

A) jar 包 B) API C) 源码

⦁ 官方jar下载地址 JFrog ⦁ 源码下载地址 https://github.com/spring-projects/spring-framework/tags

从Spring3开始把jar拆分成了多个: Spring2及SPring2之前只有一个jar包

二.Spring IOC简介和环境搭建

责任链 我们在使用MVC进行开发的时候数据在各层之间进行传递,数据传递的时候在业务上形成一个链条,这个链条称之为责任链 ​ 基于责任链模式开发的缺点 ​ 层和层之间的相互调用造成了耦合性比较高 ​ 解决的方案 ​ Spring IOC :控制反转 ​ 英文全称:Inversion of Control

控制:对类实例化的控制.指的是创建对象这个事情.

反转:以前由程序员实例化的过程,转交给Spring进行实例化. ​ 通俗解释:由Spring帮助实化对象,释放程序员对对象的关注度,所有的关注度都放在业务上.同时还可以达到解耦的效果.

项目应用场景

1.帮助创建SqlSessionFactory ​ 2.管理所有Mapper接口,管理所有BizImpl类.

理解示意图

Spring不依赖于容器的框架.没有tomcat也能运行.

(maven版)环境搭建步骤:

  1. pom.xml里添加依赖:


<!--进行junit单元测试 -->
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.11</version>
    <scope>test</scope>
  </dependency>
​
<!--依赖于commons-logging日志管理 -->
  <dependency>
    <groupId>commons-logging</groupId>
    <artifactId>commons-logging</artifactId>
    <version>1.2</version>
  </dependency>
​
<!--提供了框架的基本组成部分,包括IOC 和 DI-->
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-core</artifactId>
    <version>4.1.6.RELEASE</version>
  </dependency>
​
<!-- 提供了BeanFactory-->
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-beans</artifactId>
    <version>4.1.6.RELEASE</version>
  </dependency>
​
<!--上下文配置对象,提供一个框架式的对象访问方式-->
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>4.1.6.RELEASE</version>
  </dependency>
   
<!--提供了强大的表达式语言-->
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-expression</artifactId>
    <version>4.1.6.RELEASE</version>
  </dependency>  
  1. resources下创建applicationContext.xml:


<?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 user =new User();
      id:通过这个属性获取类的对象
   class:配置哪个类的对象
    -->
      <bean id="us" class="com.jr.pojo.User"></bean>
</beans>  

【注解】Schema和DTD的区别和联系 1 联系:都是XML文件的验证器. 2 Schema是DTD的升级版.可扩展性更强. 2.1 在一个xml中引入多个XSD文件. xmlns:自定义名称=”路径”

2.2在一个xml中只能引入1个DTD文件

  1. 测试类代码:


//[1]解析applicationContext.xml
​
//Spring配置文件运行后产生ApplicationContext接口对象.
//Spring中所有内容都放入到ApplicationContext容器中.
​
ApplicationContext app =new ClassPathXmlApplicationContext("applicationContext.xml") ;
​
//[2]获得user对象
User us = (User) app.getBean("us");

// getBean(“<bean>id属性值”,对象是什么类型);
// 如果省略第二个参数,getBean()返回值为Object
​
us.eat();  

4) 总结:

IOC实现的好处 ​ 实现代码之间的解耦 ​ IOC :控制反转 控制:创建对象的过程 反转:创建对象的操作本身是程序员自己完成的,现在反交给Spring 进行创建。

(java版)环境搭建步骤:

1.创建Java项目,导入jar包:

2.src下创建applicationContext.xml:


<?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">
​
   
​
​
</beans>  

3.创建实体类User:


public class User {
​
  private String name;
​
  public String getName() {
      return name;
  }
​
  public void setName(String name) {
      this.name = name;
  }
​
  public User() {
  }
​
  public User(String name) {
      this.name = name;
  }
​
  @Override
  public String toString() {
      return "User{" +
              "name='" + name + '\'' +
              '}';
  }
​
  public void eat(){
      System.out.println(name+"在吃汉堡。。。");
  }
}  

4.编写applicationContext.xml配置文件:


<?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">
​
  <bean id="user" class="com.jr.pojo.User"/>
​
   
</beans>  

5.编写测试类:


public class MyTest {
​
  @Test
  public void testioc(){
      //1.加载Spring核心配置文件
    ApplicationContext applicationContext =new ClassPathXmlApplicationContext("applicationContext.xml");
      //2.根据bean id获得user对象
      User user=applicationContext.getBean("user",User.class);
      user.setName("娜娜");
      user.eat();
  }
}  

三.Spring IOC创建对象方式


 A.在核心配置xml中进行显示装配:(重点)  

  <!-- 配置UserDaoImpl:完成对象注入
        id="userDao"  :唯一标识一个bean对象。
        class:  表示创建出来的bean对象的类型
  -->
   <bean id="userDao" class="com.neuedu.dao.impl.UserDaoImpl"/>  

 B.使用java类进行显示装配:(了解)  

第四步:编写一个工具java类:

@Configuration   // 当前是beans标签目的:告诉当前项目,对于bean的标签的装配,是在当前类下完成的。
public class AppConfig{
    
	@Bean(name="userDao")  //当前是bean标签:<bean id="udao" class="com.neuedu.dao.impl.UserDaoImpl"/>
	public UserDao getUserDao(){
		return new UserDaoImpl();
	}
	
	                             /*
	                              * <bean id="userbiz" class="com.neuedu.biz.impl.UserBizImpl">
      										 <property name="udi" ref="udao"/> 
      							    </bean>			 
	                              */
	@Bean(name="userbiz")
	public UserBiz getUserBiz(UserDao uDao){  //自动根据参数类型查找。
		UserBizImpl ub=new UserBizImpl();
		ub.setUserdao(uDao);
		return ub;
	}
}

加载代码:ApplicationContext context=new AnnotationConfigApplicationContext(AppConfig.class);  


 C。使用注解进行自动装配  

3.1 IOC改造代码的原始社会

3.1.1 使用无参构造


public class User {
    private Integer uid;
    private String uname;
    private  Integer uage;
    private  String usex;
    ==省略get/set,toString方法
    public User(){}
 }  


<!--[1]使用无参构造创建对象-->
<bean id="stu" class="com.jr.pojo.User"></bean>
  

3.1.2 使用有参构造


public class User {
    private Integer uid;
    private String uname;
    private  Integer uage;
    private  String usex;
    ==省略get/set,toString方法
    public User(int uid,String uname,int uage,String usex){
     	this.uid = uid;
        this.uname = uname;
        this.uage=uage;
        this.usex = usex;
    }
 }  


<!--[2]使用有参构造
     A、name属性和对应类中的有参构造的形参名称一致
     B、书写constructor-arg 标签的顺序和有参构造的形参的顺序无关
     C、我们可以使用 name 、index  和 type   共同约束我们调用的方法
-->
<bean id="stu2" class="com.jr.pojo.User">

    <!--<constructor-arg name="uid" value="111"></constructor-arg>
    	<constructor-arg name="usex" value="男"></constructor-arg>
    	<constructor-arg name="uname" value="zs"></constructor-arg>-->	

    <constructor-arg  index="0" type="int" value="112"></constructor-arg>
    <constructor-arg  index="1" type="java.lang.String" value="李四"></constructor-arg>
    <constructor-arg  index="1" type="java.lang.String" value="女"></constructor-arg>
</bean>  

3.2 IOC改造代码的封建社会(了解)

3.2.1 介绍工厂设计模式

1)设计模式:解决某种特定问题的代码编写方案. 2)工厂设计模式:某个特定类型(父类及子类)对象由工厂统一生产.以达到对象统一管理.

3)实例工厂 需要实例化工厂对象,根据工厂对象调用生成对象的方法. 4)实例实现步骤:

4.1)创建PeopleFactory public class PeopleFactory { public People getInstance(String name) { switch (name) { case "teacher": return new Teacher(); case "student": return new Student(); case "programmer": return new Programmer(); } return null; } } 4.2) 编写测试代码 //实例工厂:先创建工厂对象,调用工厂中方法 PeopleFactory factory = new PeopleFactory(); People people = factory.getInstance("teacher");

5)静态工厂 5.1) 与实例方法的区别是,生产方法上添加static public class PeopleFactory { public static People getInstance(String name) { switch (name) { case "teacher": return new Teacher(); case "student": return new Student(); case "programmer": return new Programmer(); } return null; } } 5.2) 测试代码,获取对象更加方便 People people = PeopleFactory.getInstance("student");

3.2.2 使用工厂模式

设计模式:解决某一类问题的产生 工厂设计模式:可以达到对象的统一管理,可以批量的产生某一类对象。

实现步骤:

【方案一:使用实例工厂类 + 无参】

1) 创建一个实例工厂类


public class UsersFactory {
    public  User getInstance(){
        return new User(123,"李思思","女");
    }  
}  

2) 在applicationContext.xml 先实例工厂对象,创建对应Bean的对象


<!-- UsersFactory  factory=new  UsersFactory()-->
<bean id="factory" class="com.jr.util.UsersFactory"></bean>

<!-- User  user1= factory.getInstance()-->
<bean id="user1" factory-bean="factory" factory-method="getInstance" ></bean>   

【方案二:使用静态工厂类 + 无参】

1)创建一个静态工厂类 public class UsersFactory { public static User getStaticInstance(){ return new User(123,"李思思","女"); } } 2) applicationContext.xml直接指定哪个工厂类的哪个方法生成对应Bean对象


<!-- User  user2= UsersFactory.getStaticInstance()-->
<bean id="user2" class="com.jr.util.UsersFactory" factory-method="getStaticInstance" ></bean>  

【方案三:使用实例工厂类 + 有参】

1) 创建一个实例工厂类


public class UsersFactory {
    public  User getInstance1(User user){
        return user;
    }
}  

2) 在applicationContext.xml 先实例工厂对象,创建对应Bean的对象,同时设置参数。


<!-- UsersFactory  factory=new  UsersFactory()-->
<bean id="factory" class="com.jr.util.UsersFactory"></bean>


<!-- User  user3= factory.getInstance1(us)-->
<bean id="user3" factory-bean="factory" factory-method="getInstance1" >
 	<constructor-arg name="user" ref="us"></constructor-arg>
</bean>   

【方案四:使用静态工厂类 + 有参】

1) 创建一个静态工厂类


public class UsersFactory {
    public static User getInstance2(User user){
        return user;
    }
}  

2) applicationContext.xml直接指定哪个工厂类的哪个方法生成对应Bean对象,同时设置参数


 <!--User  user2= UsersFactory.getInstance2(us)--->
<bean id="user4" class="com.jr.util.UsersFactory" factory-method="getInstance2">
    <constructor-arg name="user" ref="us"></constructor-arg>
</bean>  

3.3介绍IOC容器内部协作

加载多配置文件的时候:

方式一:ApplicationContext app=new ClassPathXmlApplicationContext("applicationContext-*.xml");

方式二:ApplicationContext app=new ClassPathXmlApplicationContext(new String[]{"applicationContext-1.xml","applicationContext-2.xml"});

核心配置文件,没有直接在src下,怎么加载?

ApplicationContext context=new ClassPathXmlApplicationContext("config/ApplicationContext.xml");

根据同一个bean id默认 只能创建一个对象。 (默认是单例模式)

3.4 介绍Bean标签

⦁ <bean>的一个属性,控制如何实例化对象 3.5.1 lazy-init 属性

true:懒加载

false:立即加载

<beans>里default-lazy-init:当前配置文件里的所有bean对象都设置为懒加载。

3.5.2 init-method 属性

用于设置对象 初始化阶段 调用的方法。

3.5.3 destory-method 属性

用于设置对象 销毁阶段 调用的方法

3.5.4 Scope属性可取值 singleton: 默认值,单例模式.使用ApplicationContext启动时实例化对象

(同一个id值,不管获得几个bean对象,地址指向都是同一个位置。底层map集合生成) ​ prototype:原型模式.每次调用时实例化.(每次根据id值获得的时候,都会产生一个新的对象) ​ request:每次请求时实例化对象. ​ session:每次产生session(HttpSession)时实例化 ​ application:产生application对象时实例化.一般都实例化一次. ​ golbal session: 全局Golbal Session,web应用中一个新的全局HttpSessin对象.在spring-webmvc-portlet提供

3.4.1 单例设计模式

1)单例设计模式:让整个应用程序中只能产生某个类的一个对象. 2)好处: 2.1 通过对象共享数据.(application) 2.2 减少系统内存占用 3)分类: 3.1 懒汉式 public class People { private static People people; private People(){} public static People getInstance(){ if(people==null){ synchronized (People.class) { if(people==null){ people = new People(); } } } return people; } }

3.2 饿汉式 public class People2 { ​ private static People2 people=new People2(); ​ private People2(){} ​ public static People2 getInstance(){ ​ return people; ​ } }

3.5面试题:

1、面试题1 BeanFactory 和 ApplicationContext 两个接口的区别:(?)


 BeanFactory   :延迟加载,第一次使用getBean()方法的时候获得bean对象;
  ---好处:按需加载。  

 ApplicationContext  :加载配置文件的时候,把文件里的所有bean 标签所对应的对象都加载出来。
 ---好处:把问题,由运行期转换到编译器。
 ---如果某些项目,很在意内存的使用,还是要考虑使用BeanFactory  

2、面试题2 介绍一下,ApplicationContext接口的两个实现类:


ClassPathXmlApplicationContext;------配置文件在类路径下。  

FileSystemXmlApplicationContext----系统文件中。  

四.Spring DI注入的三种方式

4.1 利用DI进行解决

1.为什么使用DI(依赖注入)

作用:给对象中的全局属性进行赋值的操作

2.英文全称(Dependency Injection)

3.中文名称:依赖注入 3.1 依赖:一个类在另一个类中作为全局属性时 ​ 3.2 注入:通过Spring容器为自己的属性注入一个值

4.DI的意义

4.1 解除类与类之间高耦合性,给对象中全局对象赋值的操作

5.为什么称DI和IoC是同一个事情. 5.1 Spring帮助创建对象的过程叫做IoC,创建对象时给对象中全局对象赋值叫做DI,所以认为IoC和DI是同一个事情.

4.2 DI注入的三种方式

前期代码实现 (1)创建实体类: public class People { private int id; private String name; private String address; private Classroom classroom;

}

1.构造注入

<!--【A】使用有参构造进行值的注入--> <!-- value 和 ref的使用场景 如果给基本数据类型+String 注入值的时候使用 value 如果给对象注入值的时候 使用 ref -->

.提供有参构造方法,通过<bean>的<constructor-arg>注入 <bean id="classroom" class="com.jr.pojo.Classroom"></bean> <bean id="peo" class="com.jr.pojo.People"> <constructor-arg index="0" value="1"></constructor-arg> <constructor-arg index="1" value="张三"></constructor-arg> <constructor-arg index="2" value="西三旗"></constructor-arg> <constructor-arg index="3" ref="classroom"></constructor-arg> </bean>

2.设值注入

:执行属性的set方法. ===结合<property>标签进行实现 <bean id="classroom" class="com.jr.pojo.Classroom"> <property name="id" value="1"></property> <property name="name" value="C01"></property> </bean> <bean id="peo" class="com.msb.pojo.People"> <property name="id" value="123"></property> <property name="name" value="张三"></property> <property name="classroom" ref="classroom"></property> </bean>

2.1.设置注入时不同数据类型的注入方式

  1. String或基本数据类型等 <bean id="classroom" class="com.jr.pojo.Classroom"> <property name="id" value="1"></property> </bean>

  2. 属性是对象类型 <bean id="peo" class="com.jr.pojo.People"> <property name="classroom" ref="classroom"></property> </bean>

  3. 属性是数组时,和list可以相互替换 <property name="strs"> <array> <value>1</value> <value>2</value> <value>3</value> <value>4</value> </array> </property>

  4. 属性是List集合时,可以和array相互替换 <property name="list"> <list> <value>1</value> <value>2</value> <value>3</value> <value>4</value> </list> </property>

  5. 属性是Set集合时 <property name="set"> <set> <value>2222</value> <value>3333</value> <value>444</value> </set> </property>

  6. 属性是Map集合时 <property name="map"> <map> <entry> <key> <value>a</value> </key> <value>a的内容</value> </entry> <entry> <key> <value>b</value> </key> <value>b的内容</value> </entry> </map> ​ </property>

3.自动注入(了解)

配置自动注入的方式有两种,一种是全局配置,另一种是局部单独配置。

  全局配置:只配置一次,之后配置文件中的所有bean,都按照全局配置进行注入,全局配置是在<beans>标签中配置default-autowire="Xxx";

  局部单独配置:对于每一个bean,单独设置注入方式,单独配置是在单独的<bean>标签中配置autowire="xxx"。

全局配置 default-autowire 和 局部配置autowire区别: 1 default-autowire配置<beans>当前xml文件所有<bean>都使用这种注入方式 2 autowire:配置<bean>只针对这个<bean>生效 3 如果配置了default-autowire和autowire时候,autowire生效.

通过<bean>的autowire属性控制类中属性自动注入方式,对于全局配置和局部单独配置,都有5个值可以选择:

  1、no:当autowire设置为no的时候,Spring就不会进行自动注入,相当于不给引用属性赋值。

  2、byName:在Spring容器中查找id与引用类型的属性名相同的bean,并进行注入。 *底层调用的是属性的set方法

   ===无法注入String或基本数据类型或value赋值的属性,若没有对应的名称则返回null。

3、byType:在Spring容器中查找类型与引用类型的数据类型相同的bean,并进行注入。*底层调用的是属性的set方法

   ===无法注入String或基本数据类型或value赋值的属性,若有多个同类型bean定义,则报异常。

4、constructor:先使用byName方式进行匹配,如果没有对应的值,再根据byType方式进行匹配。 *底层调用的是构造器方法

  5、default:默认值.看全局<beans>的default-autowire属性的值


<bean id="user" class="com.jr.pojo.User">
    <constructor-arg name="uid" value="000"/>
    <constructor-arg name="name" value="用户名字"/>
    <constructor-arg name="uage" value="11"/>
    <constructor-arg name="usex" value="女"/>
</bean>

<bean id="stu" class="com.jr.pojo.Student" autowire="byName"></bean>  

五.代理模式实现AOP

5.1介绍代理模式

1.代理模式 设计模式的一种,解决某一类问题的产生 分为:静态代理

动态代理【JDK动态代理、CGLIB动态代理】

2.代理模式的角色 1.抽象对象(抽象父类或接口):需要完成的功能 2.被代理对象:隐藏起来的对象 3.代理对象:暴露给其他人的对象,访问被代理对象通过代理对象进行访问

3.代理模式案例:我们找中介租房 1.抽象对象: 租房 2.被代理对象:房东 3.代理对象:中介(做了额外事情,包房东保护起来) 4.调用者:我们

4.代理模式的好处 1.被代理对象可以专注完成自己的业务(房东安心的做自己的事情即可,不用管理其他的事情) 2.保护了被代理对象(房东对象比较的安全) 3.增强了代码的扩展性

5.实现静态代理的步骤

5.1 创建抽象对象: Zufang接口


public interface Zufang {
	/*
 	 * 需要完成的事情
	 */
	void zufang();
}  

5.2 创建被代理对象Fangdong


public class Fangdong implements Zufang {
	public void zufang() {
		System.out.println("出租五环科技园C座c01");
	}
}  

5.3 创建代理对象Zhongjie


public class Zhongjie implements Zufang {
	//房东人:张三
	private Fangdong fangdong = new Fangdong();
	@Override
	public void zufang() {
		System.out.println("收房东的中介费");
		fangdong.zufang();
		System.out.println("收我们的中介费");
	}
}  

5.4 创建调用者Women


public class Women {
	public static void main(String[] args) {
		//小王
		Zhongjie zhongjie = new Zhongjie();
		zhongjie.zufang();
	}
}  

6.静态代理缺点: 缺点:1.随着房东/被代理对像的增多,中介的压力就会越来越大,体现到代码上就是代码越来越臃肿

5.2介绍AOP

1.为什么使用AOP IOC :控制反转--帮助我们创建对象--实现解耦 AOP:面向切面编程--提升代码的扩展性

按照软件重构思想的理念,在OOP中通过抽象把相同的代码抽取到父类中(纵向抽取),但无法通过抽象父类的方式消除重复性的横切代码(如事务处理这种非业务性的重复代码),而AOP就是为了解决将分散在各个业务逻辑代码中的相同代码通过横向切割的方式抽取到一个独立的模块中。

AOP面向切面编程,并不是要替代OOP,仅做为OOP的有益补充。 利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

2.AOP的简介 AOP的概念:Aspect Oriented Programming AOP的中文: 面向切面编程

AOP有特定的应用场合,它只适合具有横切逻辑的应用场合,如:性能检测,访问控制,事务控制,日志记录等。就像面向对象编程的关注点在于对象 即类;而面向切面编程的关注的在于切面;

那么什么是切面?可以理解为程序执行时的某个节点,或者更具体一点,在某个方法执行之前,执行之后等节点。

使用AOP技术,可以将一些系统性相关的编程工作,独立提取出来,独立实现,然后通过切面切入进系统。从而避免了在业务逻辑的代码中混入很多的系统相关的逻辑——比如权限管理,事务管理,日志记录等等。这些系统性的编程工作都可以独立编码实现,然后通过AOP技术再切入进系统即可。从而达到了 将不同的关注点分离出来的效果。

举个例子:我现在要实现一个删除功能,在Servlet里 调用了 业务逻辑层里的删除方法。而在业务逻辑层Service实现类里,需要在删除方法前进行权限检查,在删除方法后进行日志记录。那我就将权限检查和日志记录两个方法提取出来,放到单独的一个类里去 ,而不是跟删除的业务代码杂糅在一块。最后在通过AOP技术动态织入到删除方法周围。在service实现类里的删除方法就是切点/连接点(连接点范围更大,管符合一定条件规则的连接点叫切点);而权限检查和日志记录就是切面;切面的工作内容叫做通知 同时通知也规定了什么时候执行切面。

3.AOP中的几个要素

1) Aspect :切面,切入系统的一个切面。比如事务管理是一个切面,权限管理也是一个切面;

2) Join point :连接点,也就是可以进行横向切入的位置;

3) Advice :通知,切面在某个连接点执行的操作(分为: Before advice , After returning advice , After throwing advice , After (finally) advice , Around advice );

4) Pointcut :切点,符合切点表达式的连接点,也就是真正被切入的地方;

理解示意图:

4.AOP的分类:

AOP分为静态AOP和动态AOP。静态AOP他是将切面代码直接编译到Java类文件中。动态AOP是指先将切面代码统一放到一个切面类里去,然后进行动态织入到指定的切点方法周围,从而实现AOP。Spring的AOP为动态AOP,实现的技术为: JDK提供的动态代理技术 和 CGLIB(动态字节码增强技术) 。尽管实现技术不一样,但 都是基于代理模式 , 都是生成一个代理对象 。

5.3静态代理实现AOP

5.3.1第一阶段的静态代理

实现步骤:

1.创建接口UserService


void add() throw Exception;
void delet() throw Exception;  

2.创建接口实现类UserServiceImpl


public void add() throw Exception{
 	check();
	System.out.println("添加成功");
	log();
}
public  void  check(){
	System.out.println("权限检查");
}
public  void  log(){
	System.out.println("日志记录");
}  

3.编写测试方法


 ApplicationContext app=new ClassPathXmlApplicationContext("applicationTest.xml");
 UserService UserService=(UserService)app.getBean("UserService");
 UserService.add();  

4.存在问题:

第一阶段的静态代理,在UserServiceImpl实现类中业务代码严重的与横切性代码耦合在一起了。

解决办法:将横切性代码提取出来,与业务代码 分开存放。

5.3.2第二阶段的静态代理

代码实现:

1.创建一个静态代理类:

com.msb.proxy 包下创建创建UserServiceProxy类 实现跟UserServiceImpl类一样的接口


public class UserServiceProxy implement UserService{
	private UserServiceImpl usi;//静态代理,指明代理的是谁。
	public UserServiceProxy(UserServiceImpl userServiceImpl){
		this.usi=userServiceImpl;	
	}
	public void add() throw Exception{
 		check();
		usi.add();
		log();
	}
	
	public  void  check(){
		System.out.println("权限检查");
	}
	
	public  void  log(){
		System.out.println("日志记录");
	}

}  

2.实现类UserServiceImpl代码改动


public void add() throw Exception{	
	System.out.println("添加成功");
}  

3.存在问题:

第二阶段的静态代理,将UserServiceImpl实现类中的横切性代码提取出来 放到代理类里,在代理类里做整合。 那么一个service接口就要写一个代理类,如果Service接口特别多的话,程序中将多出非常多的代理类。

解决办法:需要一个代理类,能代理所有实现接口的实现类。这就需要下面的动态代理

5.4动态代理实现AOP

5.4.1JDK动态代理实现AOP

1.动态代理的分类: 2.1 JDK动态代理---代理拥有接口的实现类 2.2 cglib动态代理---代理拥有父类的子类

2.动态代理: 3.1 底层是根据反射实现的. 3.2 只要给代理对象传递被代理对象,直接调用被代理对象中方法

3.动态代理中动态含义 3.1 代理类可以代理任意类型对象.(被代理对象必须实现了指定接口)

4.实现步骤:

4.1.创建动态代理类:


//使用动态代理时需要实现InvocationHandler,因为在调用者中通过接口调用方法时知道需要执行哪个方法
public class JDKProxy implements InvocationHandler {

	private Object targetObject;//代理的目标对象		
    
	//产生代理对象:
	public Object createProxyInstance(Object targetObject){
		this.targetObject=targetObject;
/**
 * 参数一     ClassLoader   类加载器
 * 参数二:   Interfaces  接口类型
 * 参数三:   InvocationHandler  代理对象
 * */
		 return Proxy.newProxyInstance(
		 	this.targetObject.getclass().getClassLoader(),
		 	this.targetObject.getclass().getInterfaces(),
			this);
	}
	
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		check();
    	Object invoke = method.invoke(this.targetObject, args);
		log();
    	return invoke;
	}

	public  void  check(){
		System.out.println("权限检查");
	}
	
	public  void  log(){
		System.out.println("日志记录");
	}

}  

4.2创建测试类:


JDKProxy jdkProxy=new JDKProxy();

	//给UserService接口创建临时代理对象userService
UserService userService=(UserService)jdkProxy.createProxyInstance(new UserServiceImpl());

	//调用JDKProxy中invoke方法,把UserServiceImpl.add()方法赋值给invoke方法第二个参数Method,还会add()方法参数赋值   //invoke()方法第三个参数Object,执行invoke方法.
UserService.add();  

5.存在问题:

JDK动态代理的产生必须要实现对应的接口的,如果没有对应的接口,这个时候代理对象就没有办法产生。

5.4.2CGLIB动态代理实现AOP

实现步骤:

1.创建父类


public abstract   class UserSuper {

   public  abstract   void add();
}  

2.创建子类


public class UserSub extends UserSuper{
	public void add(){
		System.out.println("添加成功!");	
	}
}  

3.创建动态代理类


public class CGLibProxy implements MethodInterceptor{

	private Object targetObject;//代理的目标对象	
	
	//产生代理对象:
	public Object createProxyInstance(Object targetObject){
		this.targetObject=targetObject;
		 Enhancer  en=new Enhancer();//该类用于生成子类的代理对象
		 en.setSuperclass(this.targetObject.class); //设置父类
		 en.setCallback(this); //设置回滚函数
		 return en.create();
	}

    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
       	check(); 
        Object o1 = methodProxy.invokeSuper(o, objects);
        log();
        return o1;
    }
    
    public  void  check(){
		System.out.println("权限检查");
	}
	
	public  void  log(){
		System.out.println("日志记录");
	}
}  

4.创建测试类


    CGLibProxy   cgLibProxy =new CGLibProxy();
    UserSuper userSuper = (UserSuper) cgLibProxy.createProxyInstance(new UserSub());
    userSuper.add();  

5.存在问题:

横切行代码最好还是存放在一个单独的类里面去,然后借助动态代理,在作用在代理类对象上。

Spring提供了两种切面声明方式,实际工作中我们可以选择其中一种: ​ A) 基于XML配置方式声明切面 ​ B) 基于注解方式声明切面

六.基于XML配置方式声明切面

实现Spring AOP的过程,就是告诉Spring哪些方法需要形成切面

代码实现

1.添加依赖


   <dependencies>
        <!--进行junit单元测试 -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.11</version>
            <scope>test</scope>
        </dependency>

        <!--依赖于commons-logging日志管理 -->
        <dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
            <version>1.2</version>
        </dependency>

        <!--提供了框架的基本组成部分,包括IOC 和 DI-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>4.1.6.RELEASE</version>
        </dependency>

        <!-- 提供了BeanFactory-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>4.1.6.RELEASE</version>
        </dependency>

        <!--上下文配置对象,提供一个框架式的对象访问方式-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>4.1.6.RELEASE</version>
        </dependency>

        <!--提供了强大的表达式语言-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-expression</artifactId>
            <version>4.1.6.RELEASE</version>
        </dependency>

<!-- ====注解式声明切面  -->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.1</version>
        </dependency>
 </dependencies>  

2.定义切面类:


public class Advice {
  
    public void check(){
        System.out.println("权限检查");
    }

    public void log(){
        System.out.println("日志记录");
    }
}  

3.编写业务代码:


public interface UserService {
    void add() throws Exception;
    void delete() throws Exception;
}  

public class UserServiceImpl implements UserService {
    public void add() throws Exception {
        System.out.println("添加User成功");
    }

    public void delete() throws Exception {
        System.out.println("删除User成功");
    }
}  

4.编写applicationContext.xml配置文件

===引入一个命名空间: aop


 	   xmlns:aop="http://www.springframework.org/schema/aop"      
       
       http://www.springframework.org/schema/aop
	   http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
    <!--创建业务实现类对象 -->
    <bean id="usi" class="com.jr.aop.aspectj.UserServiceImpl"/>

    <!--创建切面类对象 -->
    <bean id="advice" class="com.jr.aop.aspectj.Advice"/>

    <!-- <aop:config proxy-target-class="true"> 如果这样配置则是强制使用CGLIB方式进行代理
            不写或者设置为false默认使用 : jdk方式进行代理  -->
<aop:config>
   <aop:aspect ref="advice">
      <!--定义切点: -->
      <aop:pointcut id="addpointcut" expression="execution(* com.jr.aop.aspectj.UserServiceImpl.add*(..))"/>
      <!--定义通知 -->
      <aop:before method="check" pointcut-ref="addpointcut"/>

      <aop:after method="log" pointcut="execution(* com.jr.aop.aspectj.UserServiceImpl.add*(..))"/>
   </aop:aspect>

</aop:config>  

5.编写测试代码:


    @Test
    public void test5() throws Exception {

        ApplicationContext app=new ClassPathXmlApplicationContext("applicationAOP.xml");
       	UserService userService=(UserService)app.getBean("usi");
        userService.add();
        userService.delete();
    }
    运行结果:
    	权限检查
		添加User成功
		日志记录
		删除User成功  

2.介绍execution表达式

Execution表达式语法:

execution(<修饰符模式>?<返回类型模式><方法名模式>(<参数模式>))<异常模式>?)

除了返回类型模式,方法名模式和参数模式外,其他项都是可选的。

execution(public * * (..))

匹配所有目标类的public方法,第一个 * 代表返回类型,第二个 * 代表方法名,而 .. 代表任意入参方法;

execution( * *To (..))

匹配目标类所有以To为后缀的方法,第一个 * 代表返回类型,而 * To代表任意以To为后缀的方法;

execution( * com.jr.UserService.* (..))

匹配UserService接口的所有方法,第一个 * 代表返回任意类型,com.msb.UserService.*代表UserService接口中的所有方法;

execution( * com.jr.* (..))

匹配com.msb包下所有类的所有方法

execution( * com.jr..* (..))

匹配com.msb包,子孙包下所有类的所有方法,“..”出现在类名中时,后面必须跟“*”,表示包,子孙包下的所有类;

execution( * com.jr.. * .*Dao.find * (..))

匹配包名前缀为com.jr的任何包下类名后缀为Dao的方法,方法名必须以find为前缀。

七.基于注解方式声明切面

实现步骤:

1.添加依赖


    <dependencies>
        <!--进行junit单元测试 -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.11</version>
            <scope>test</scope>
        </dependency>

        <!--依赖于commons-logging日志管理 -->
        <dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
            <version>1.2</version>
        </dependency>

        <!--提供了框架的基本组成部分,包括IOC 和 DI-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>4.1.6.RELEASE</version>
        </dependency>

        <!-- 提供了BeanFactory-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>4.1.6.RELEASE</version>
        </dependency>

        <!--上下文配置对象,提供一个框架式的对象访问方式-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>4.1.6.RELEASE</version>
        </dependency>

        <!--提供了强大的表达式语言-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-expression</artifactId>
            <version>4.1.6.RELEASE</version>
        </dependency>

<!-- ====注解式声明切面  -->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.1</version>
        </dependency>
 </dependencies>     

2.定义切面类:


@Aspect
@Component
public class Advice {

    @Before("execution(* com.jr.aop.aspectj.UserServiceImpl.add*(..))")
    public void check(){
        System.out.println("权限检查");
    }

    @After("execution(* com.jr.aop.aspectj.UserServiceImpl.add*(..))")
    public void log(){
        System.out.println("日志记录");
    }

}  

3.编写业务代码:


public interface UserService {
    void add() throws Exception;
    void delete() throws Exception;
}  

@Service
public class UserServiceImpl implements UserService {
    public void add() throws Exception {
        System.out.println("添加User成功");
    }

    public void delete() throws Exception {
        System.out.println("删除User成功");
    }
}  

4.编写applicationContext.xml配置文件

===引入两个命名空间:context 和 aop


 	   xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:context="http://www.springframework.org/schema/context"
       
       http://www.springframework.org/schema/aop
	   http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
	   http://www.springframework.org/schema/context
	   http://www.springframework.org/schema/context/spring-context-4.3.xsd
	   
    	<!-- 扫描指定路径,自动注入注解-->
    <context:component-scan base-package="com.msb"/>
   	 	<!--自动为spring容器中那些配置@aspectJ切面的bean创建代理,
    	有一个proxy-target-class属性,默认为false 那么标准的JDK 基于接口的代理将起作用。
    	不过即使proxy-target-class设置为false,如果目标类没有声明接口,则spring将自动使用CGLib动态代理。-->
    <aop:aspectj-autoproxy/>  

5.编写测试代码:


    @Test
    public void test5() throws Exception {

        ApplicationContext app=new ClassPathXmlApplicationContext("applicationAOP.xml");
       	UserService userService=(UserService)app.getBean("userServiceImpl");
        userService.add();
        userService.delete();
    }
    运行结果:
    	权限检查
		添加User成功
		日志记录
		删除User成功  

八.Spring中注解的支持

Spring的常见注解及其作用:

  1. @Component 创建类对象,相当于配置<bean/> bean的ID默认为类名首字母小写,也可以指定ID,例如@Component("stu")

  2. @Service 与@Component功能相同. 2.1 写在ServiceImpl类上.

  3. @Repository 与@Component功能相同. 3.1 写在数据访问层类上.

  4. @Controller 与@Component功能相同. 4.1 写在控制器类上.

  5. @Resource(不需要写对象的get/set) 5.1 java中的注解 5.2 默认按照 名称 注入,如果没有名称对象,按照byType注入 5.2.1 建议把对象名称和spring容器中对象名相同

  6. @Autowired(不需要写对象的get/set) 6.1 spring的注解 6.2 默认按照byType注入.

  7. @Value() 获取properties文件中内容

  8. @Pointcut() 定义切点

  9. @Aspect() 定义切面类

  10. @Before() 前置通知

  11. @After 后置通知

  12. @AfterReturning 后置通知,必须切点正确执行

  13. @AfterThrowing 异常通知

  14. @Arround 环绕通知 注意:


  使用注解,一定要在配置文件中声明注解扫描 
  <context:component-scan base-package="包名路径"></context:component-scan>         
  <aop:aspectj-autoproxy></aop:aspectj-autoproxy>   

九.Spring整合MyBatis的实现

A. 导入Spring和MyBatis的jar包依赖:


 
<dependencies>


    <!-- mybatis核心包-->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.5.3</version>
    </dependency>

    <!-- mysql驱动包 -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.8</version>
    </dependency>

    <!-- 日志包,方便看sql语句 -->
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-log4j12</artifactId>
        <version>1.6.1</version>
    </dependency>



    <!--进行junit单元测试 -->
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.11</version>
        <scope>test</scope>
    </dependency>

    <!--依赖于commons-logging日志管理 -->
    <dependency>
        <groupId>commons-logging</groupId>
        <artifactId>commons-logging</artifactId>
        <version>1.2</version>
    </dependency>

    <!--提供了框架的基本组成部分,包括IOC 和 DI-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-core</artifactId>
        <version>4.1.6.RELEASE</version>
    </dependency>

    <!-- 提供了BeanFactory-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-beans</artifactId>
        <version>4.1.6.RELEASE</version>
    </dependency>

    <!--上下文配置对象,提供一个框架式的对象访问方式-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>4.1.6.RELEASE</version>
    </dependency>

    <!--提供了强大的表达式语言-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-expression</artifactId>
        <version>4.1.6.RELEASE</version>
    </dependency>
    <!-- ====注解式声明切面  -->
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>1.9.1</version>
    </dependency>


    <!--整合Spring + Mybatis -->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis-spring</artifactId>
        <version>1.3.0</version>
    </dependency>

    <!-- 导入dbcp的jar包,用来在spring-mybatis.xml中配置数据库 -->
    <dependency>
        <groupId>commons-dbcp</groupId>
        <artifactId>commons-dbcp</artifactId>
        <version>1.4</version>
    </dependency>

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-tx</artifactId>
        <version>4.3.18.RELEASE</version>
    </dependency>

    <!--对Spring 对JDBC 数据访问进行封装的所有类-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>4.1.6.RELEASE</version>
    </dependency>
</dependencies>
  

B.resources下添加log4j.properties

C.resources下新建applicationContext.xml


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
	   http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
	   http://www.springframework.org/schema/context
	   http://www.springframework.org/schema/context/spring-context-4.3.xsd">

<!--配置数据源 -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
    <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
    <property name="url" value="jdbc:mysql://127.0.0.1:3306/test"></property>
    <property name="username" value="root"></property>
    <property name="password" value="root"></property>
</bean>

<!-- 管理sqlsessionFactory对象 -->
<bean id="factory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="dataSource"></property>
</bean>   

<!--配置mapper扫描器 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
    <property name="basePackage" value="com.msb.mapper"></property>
    <property name="sqlSessionFactoryBeanName" value="factory"></property>
</bean>

<!--配置注解扫描路径 -->
<context:component-scan base-package="com.msb"/>

</beans>  

D.使用逆向工程生成pojo实体类,mapper接口,mapper.xml映射文件:实现删除,添加,查询全部功能!


@Component
public class Dept {
    private Integer deptno;

    private String dname;

    private String loc;

    public Integer getDeptno() {
        return deptno;
    }

    public void setDeptno(Integer deptno) {
        this.deptno = deptno;
    }

    public String getDname() {
        return dname;
    }

    public void setDname(String dname) {
        this.dname = dname == null ? null : dname.trim();
    }

    public String getLoc() {
        return loc;
    }

    public void setLoc(String loc) {
        this.loc = loc == null ? null : loc.trim();
    }
}  

public interface DeptMapper {


    int insertDept(Dept record);

    int deleteDept(int deptno);

    List<Dept> selectAll();
}  

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.jr.mapper.DeptMapper" >

    <insert id="insertDept" parameterType="com.msb.pojo.Dept">
        insert into dept values(#{deptno},#{dname},#{loc})

    </insert>

    <delete id="deleteDept" parameterType="int">

        delete from dept where deptno=#{id}
    </delete>

    <select id="selectAll" resultType="com.jr.pojo.Dept">
        select * from dept
    </select>

</mapper>  

E.创建service接口和实现类


public interface DeptService {

    int addDept(Dept dept) throws Exception;

    int removeDept(int id) throws Exception;

    List<Dept> findAll() throws Exception;
}  

@Service
public class DeptServiceImpl implements DeptService {

    @Autowired
    private DeptMapper deptMapper;

    public DeptMapper getDeptMapper() {
        return deptMapper;
    }

    public void setDeptMapper(DeptMapper deptMapper) {
        this.deptMapper = deptMapper;
    }

    public int addDept(Dept dept) throws Exception {
      return deptMapper.insertDept(dept);
    }

    public int removeDept(int id) throws Exception {
        return deptMapper.deleteDept(id);
    }

    public List<Dept> findAll() throws Exception {
        return deptMapper.selectAll();
    }
}  

F.创建测试方法,运行结果:


public class SpringTest {

    @Test
    public void test1() throws Exception {

        ApplicationContext app=new ClassPathXmlApplicationContext("applicationContext.xml");
        DeptService deptService=(DeptService) app.getBean("deptServiceImpl");
        List<Dept> list =deptService.findAll();
        for (Dept d:list){
            System.out.println(d.getDeptno()+";"+d.getDname()+";"+d.getLoc());
        }
    }
    
    @Test
    public void test2() throws Exception {

        ApplicationContext app=new ClassPathXmlApplicationContext("applicationContext.xml");
        DeptService deptService=(DeptService) app.getBean("deptServiceImpl");
        int i=deptService.removeDept(31);
        System.out.println(i==1?"删除成功":"删除失败");
    }
}

  

十.Spring中TX事务管理

A.事务的特性

事务要么整体生效,要么整体失效。在数据库上即使多条SQL语句要么全执行成功,要么全执行失败!

B.事务的四个原则

1.原子性(atomicity):一个事务必须视为一个不可分割的最小工作单元,整个事务中的所有操作要么全部提交成功,要么全部失败回 滚,对于一个事务来说,不可能只执行其中的一部分操作,这就是事务的原子性。

2.一致性(consistency):数据库总数从一个一致性的状态转换到另一个一致性的状态。

3.隔离性(isolation):一个事务所做的操作(添加、修改、删除)在最终提交以前,对其他事务是不可见的。

4.持久性(durability):一旦事务提交,则其所做的操作(添加、修改、删除)就会永久保存到数据库中。此时即使系统崩溃,修改 的数据也不会丢失。

C.事务并发问题

在实际开发中数据库操作一般都是并发执行的,即有多个事务并发执行,并发执行就可能遇到问题,目前常见的问题如下:

1) 脏读: 一个事务(A)读取到另一个事务(B)中未提交的数据,另一个事务中数据可能进行了改变,此时A事务读取的数据可能和数据库中数据是 不一致的,此时认为数据是脏数据,读取脏数据过程叫做脏读.

2) 不可重复读: ​ 主要针对的是某行数据.(或行中某列) ​ 主要针对的操作是修改操作. ​ 两次读取在同一个事务内 ​ 当事务A第一次读取数据后,事务B对事务A读取的数据进行修改,事务A中再次读取的数据和之前读取的数据不一致,过程不可重复读.

3) 幻读: ​ 主要针对的操作是新增或删除 ​ 两次事务的结果. ​ 事务A按照特定条件查询出结果,事务B新增了一条符合条件的数据.事务A中查询的数据和数据库中的数据不一致的,事务A好像出现 了幻觉,这种情况称为幻读.

4)丢失更新:

两个事务同时更新一行数据,最后一个事务的更新会覆盖掉第一个事务的更新,从而导致第一个事务更新的数据丢失,这是由于没 有加锁造成的。

那在多线程或并发访问下如何保证访问到的数据具有完整性呢?

使用事务的 isolation="" 事务隔离级别

DEFAULT: 默认值,由底层数据库自动判断应该使用什么隔离界别

READ_UNCOMMITTED: 可以读取未提交数据,可能出现脏读,不重复读,幻读. === 效率最高.

READ_COMMITTED:只能读取其他事务已提交数据.可以防止脏读,可能出现不可重复读和幻读.

REPEATABLE_READ: 读取的数据被添加锁,防止其他事务修改此数据,可以防止不可重复读.脏读,可能出现幻读.

SERIALIZABLE: 排队操作,对整个表添加锁.一个事务在操作数据时,另一个事务等待事务操作完成后才能操作这个表. === 最安全的 === 效率最低的.

D.Spring事务传播策略


当一个具有事务控制的方法被另一个有事务控制的方法调用后,需要如何管理事务(新建事务?在事务中执行?把事务挂起?报异常?)   

事务的隔离级别是数据库本身的事务功能,然而事务的传播策略则是Spring自己为我们提供的功能,数据库事务没有事务传播策略这一说法

propagation 控制事务传播行为.

  1. REQUIRED (默认值): 如果当前有事务,就在事务中执行,如果当前没有事务,新建一个事务. ==增,删,改方法

  2. SUPPORTS:如果当前有事务就在事务中执行,如果当前没有事务,就在非事务状态下执行. ==查询。

  3. MANDATORY:必须在事务内部执行,如果当前有事务,就在事务中执行,如果没有事务,报错.

  4. REQUIRES_NEW:必须在事务中执行,如果当前没有事务,新建事务,如果当前有事务,把当前事务挂起

  5. NOT_SUPPORTED:必须在非事务下执行,如果当前没有事务,正常执行,如果当前有事务,把当前事务挂起

  6. NEVER:必须在非事务状态下执行,如果当前没有事务,正常执行,如果当前有事务,报错.

  7. NESTED:必须在事务状态下执行.如果没有事务,新建事务,如果当前有事务,创建一个嵌套事务.

E.Xml配置声明式事务


   我们之前学习mybatis 的时候我们使用的事务和JDBC的事务是一致的,但是我们现在学习的mybatis 结合Spring 以后,这个时候是如何管理事务的?  

1.事务的分类: 编程式事务 整个事务的管理都是程序员自己书写的代码进行的控制 如:获取事务对象,设置事务隔离级别,传播策略,开启,提交,回滚等。 声明式事务 现在整个事务管理已经做好了,如果我们想要使用事务,只要在我们自己的程序中进行声明配置即可

声明式事务分为两种:Xml配置声明式事务

注解配置声明式事务

2.事务使用的条件:


在一个业务中执行两条或者两条以上的增删改操作的时候  

3.事务的配置

A) 切点:增加事务的方法 B) 通知:---事务 C) 织入切面

4.实现步骤: 基于Spring整合Mybatis例子!

1.修改service接口和实现类


 public  int addRemoveFindDept(Dept dept,int id) throws Exception;  

    public int addRemoveDept(Dept dept, int id) throws Exception {
       int i= deptMapper.insertDept(dept);
       i=i+deptMapper.deleteDept(id);
       return i;
    }  

2.编写applicationContext.xml配置文件


 	   xmlns:tx="http://www.springframework.org/schema/tx"
       
	   http://www.springframework.org/schema/tx
	   http://www.springframework.org/schema/tx/spring-tx-4.3.xsd

<!--声明事务管理的对象-->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"></property>
</bean>

<!--事务的通知-->
<tx:advice id="txAdvice" transaction-manager="txManager">
    <tx:attributes>
        <tx:method name="add*" propagation="REQUIRED"/>
        <tx:method name="remove*" propagation="REQUIRED"/>
        <tx:method name="find*" propagation="SUPPORTS"/>
    </tx:attributes>
</tx:advice>

<--配置TX声明式事务-->
<aop:config>    
    <aop:pointcut id="pt2" expression="execution(* com.jr.service.impl.DeptServiceImpl.*(..))"/>			
    <aop:advisor advice-ref="txAdvice" pointcut-ref="pt2"></aop:advisor>    
</aop:config>  

注意: ​ 我们使用Spring 中的声明式事务的时候一定注意,不要自己捕捉异常

F.注解配置声明式事务

实现步骤:

1.编写applicationContext.xml配置文件


 	   xmlns:tx="http://www.springframework.org/schema/tx"
       
	   http://www.springframework.org/schema/tx
	   http://www.springframework.org/schema/tx/spring-tx-4.3.xsd

<!--声明事务管理的对象-->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"></property>
</bean>
<!--事务的通知-->
<tx:annotation-driven transaction-manager="txManager"/>
  

2.修改ServiceImpl实现类代码:


@Service
@Transactional(propagation = Propagation.REQUIRED)
public class DeptServiceImpl implements DeptService {

    @Autowired
    private DeptMapper deptMapper;

    public DeptMapper getDeptMapper() {
        return deptMapper;
    }

    public void setDeptMapper(DeptMapper deptMapper) {
        this.deptMapper = deptMapper;
    }

    public int addDept(Dept dept) throws Exception {
      return deptMapper.insertDept(dept);
    }

    public int removeDept(int id) throws Exception {
        return deptMapper.deleteDept(id);
    }

    public List<Dept> findAll() throws Exception {
        return deptMapper.selectAll();
    }
}  

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Spring自学笔记(学完老杜视频后再进行修改) 的相关文章

随机推荐

  • KindEditor中使用val()获取content内容后图片不显示

    场景 使用KindEditor进行图片上传后 xff0c 在js部分通过 val 获取内容后 xff0c 所获取的图片的 lt imgsrc 61 34 34 其中img标签与src连接在了一起导致图片不能显示 错误的数据库存取内容 xff
  • 微信登录显示连接失败,请检查网络

    背景 xff1a 最近公司网络不知道怎么回事 xff0c 显示连接失败 xff0c 请检查网络 最初解决方案 重新插拔网线 xff0c 就可以登陆微信了 xff0c 但是退出重登需要继续插拔网线 同事分享的解决方案 xff1a 1 右键以太
  • Property or method “XXX“ is not defined on the instance but referenced during render.解决方法

    在做Vue项目时 xff0c 有时候会看到这个警告 这里是因为vue检测到了 count 这个属性有被使用 xff0c 但是未定义 xff0c 页面虽然能够显示但是有红色信息总归是不好看的 xff0c 解决方法如下 xff1a 我们只需要在
  • 如何用Idea 创建Spring项目

    如何用IntelliJ Idea创建一个简单的Spring项目呢 xff0c 刚入门的人可能不太懂 xff0c 那我就来简单分享一下吧 第一步 点击新建一个maven项目 xff0c 点击下一步 xff08 不用选择从原型创建 xff09
  • OpenCV初尝试13——图像特征

    13 图像特征 13 1 Harris角点检测 Harris角点检测的思想是通过图像的局部的小窗口观察图像 xff0c 角点的特征是窗口沿任意方向移动都会导致图像灰度的明显变化 Harris角点检测的数学原理较为繁琐 xff0c 直接上个链
  • 华为secoclient客户端安装

    下载安装包 xff0c 右键以管理员身份运行 2 安装过程中一律选择同意 是 xff0c 完成后打开软件 点击标注处 3 输入网关地址和端口号 xff0c 选择添加 4 添加完成后确定并点击连接 xff0c 输入用户名 密码 xff0c 记
  • maven配置连接MySQL数据库

    2019年7月9号 问题 xff1a maven项目中连接不上mysql数据库 问题 xff1a maven项目中连接不上mysql数据库 从昨晚调bug一直调到今天上午 xff0c 昨晚发现了是maven项目中mysql数据库连接的问题
  • python学习:最适合初学者的8本Python书籍

    Python是最友好的编程语言之一 xff0c 也因此成为初学者的首选 xff0c 为了帮助你更好更快的上手Python xff0c 并学会使用Python进行编程 xff0c 本文我们为初学者分享了最好的Python书籍 希望能够对你有所
  • 最适合Python入门到大牛必看的7本书籍,一定要收藏!

    Python零基础应该阅读哪些书籍 xff1f 我推荐这三本书 1 Python学习手册 xff08 第4版 xff09 以计算机科学家一样的思维方式来理解Python语言编程 xff0c 实用的学习指南 xff0c 适合没有Python编
  • 前端开发:深入使用proxy代理解决前端跨域问题

    在前端领域里面 xff0c 跨域指的是浏览器允许向服务器发送跨域请求 xff0c 进而克服Ajax只能同源使用的局限性限制 同源策略是一种约定 xff0c 而且是浏览器中最基本也是最核心的安全功能 xff0c 若缺少了该策略 xff0c 浏
  • 手工搭建Servlet实现

    现在作为一个Java程序员 xff0c 我们已经习惯了使用IDE和Web框架进行开发 xff0c IDE帮助我们做了编译 打包的工作 Spring框架则帮助我们实现了Servlet接口 xff0c 并把Servlet容器注册到了Web容器中
  • airflow 文档学习(二) - 概念

    1 核心功能 1 1 DAGs 有向无环图 反映所涉及的task的依赖关系 注 xff1a 搜索dag的时候 xff0c airflow只会关注同事包含 34 DAG 34 和 34 airflow 34 字样的py文件 1 2 scope
  • java使用枚举进行前后端交互,以列表方式返回前端

    在有些情况下 xff0c 有一些下拉选择器的数据项 xff0c 我们采取了枚举的方式返回前端一个列表 xff0c 但是里面的东西多 xff0c 前端不想写死 xff0c 需要提供接口返回 xff0c 如下图类似这种 第一步 xff1a 先创
  • python循环,16段代码入门Python循环语句,值得收藏!

    导读 本文重点讲述for语句和while语句 for语句属于遍历循环 xff0c while语句属于当型循环 除了两个循环语句外 xff0c 还介绍了break continue与pass三个用于控制循环结构中的程序流向的语句 在此基础之上
  • IntelliJ IDEA中Error java: 程序包org.slf4j不存在 解决办法

    前言 问题描述 是我这边重构一个工程的时候新建一个module 希望这个module仅仅做kafka消费的服务 刚刚搭建起来运行发现有异常 Error nbsp java 程序包org slf4j不存在 解决办法 很显然可以想到的就是这个里
  • Linux下的Ubuntu系统下载安装python3.9.0

    在安装python3 9 0之前 xff0c 首先要进行换源 xff0c 这样才能防止下载过慢的情况 我这里换的是阿里云的镜像源 xff0c 在终端输入一下命令 其他镜像源可以查看 xff1a https www myfreax com u
  • 操作系统的基本概念

    操作系统的基本概念 一 操作系统的基本概念1 1概念1 2特征1 2 1 并发1 2 2 共享1 2 2 1 互斥共享方式1 2 2 2 同时访问方式 1 2 3 虚拟1 2 4 异步 1 3 目的和功能1 3 1操作系统作为计算机系统资源
  • Android -No toolchains found in the NDK toolchains folder for ABI with prefix: arm-linux-androideabi

    1 原因分析 xff1a 最新版ndk xff08 version 61 25 1 8937393 xff09 的toolchains文件夹中无arm linux androideabi文件 2 解决方案 xff1a 同时安装低版本的ndk
  • Python中的函数

    一 前言 我们在写Python时 xff0c 经常需要用到函数 xff0c 在此来说一下函数 xff0c 也就是本章要介绍的函数的作用于使用步骤 文章内容有点长 xff0c 请耐心看完哦 xff0c 文末有惊喜 二 Python中函数的作用
  • Spring自学笔记(学完老杜视频后再进行修改)

    Spring 概念 Spring框架是一个储存对象的容器 xff0c 是一个轻量级的开源Java开发框架 xff0c 它的核心是控制反转 xff08 IoC xff09 和面向切面编程 xff08 AOP xff09 xff0c 它由20多