一、 Spring概述

1.spring框架是什么?

spring是java的开源框架, 核心技术是ioc,aop。 spring也是一个容器,容器放的是java对象。
通过spring框架可以实现解耦合,解决业务对象之间的耦合,也可以解决业务对象和非业务对象之间的耦合。

2.Spring优点

(1) 轻量
(2) 针对接口编程,解耦合
(3) AOP 编程的支持
(4) 方便集成各种优秀框架

3.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">

    	/*告诉spring创建对象
        声明bean , 就是告诉spring要创建某个类的对象
        id:对象的自定义名称,唯一值。 spring通过这个名称找到对象
        class:类的全限定名称(不能是接口,因为spring是反射机制创建对象,必须使用类)

        spring就完成 SomeService someService = new SomeServiceImpl();
        spring是把创建好的对象放入到map中, spring框架有一个map存放对象的。
           springMap.put(id的值, 对象);
           例如 springMap.put("someService", new SomeServiceImpl());

        一个bean标签声明一个对象。
    */
    <bean id="someService" class="com.bjpowernode.service.impl.SomeServiceImpl" />

    <bean id="someService1" class="com.bjpowernode.service.impl.SomeServiceImpl" scope="prototype"/>
    
       //spring能创建一个非自定义类的对象吗, 创建一个存在的某个类的对象。
       
    <bean id="mydate" class="java.util.Date" />

</beans>
        /*
           spring的配置文件
           1.beans : 是根标签,spring把java对象成为bean。
           2.spring-beans.xsd 是约束文件,和mybatis指定  dtd是一样的。
        */

二 、IOC控制反转

1.概念

1、把对象的创建,属性赋值,依赖关系都交给代码之外的容器,由容器实现对象的管理。
2、把控制对象的权利转移给代码之外的容器。IoC是一个理论,概念,思想
3、IoC的重要技术实现DI(依赖注入): 通过名称就可以获取对象, 对象创建,属性赋值都由容器内部实现
4、Spring使用DI的技术, 底层实现是反射机制
注意:
1.spring默认调用无参数构造方法,创建对象。
2.创建spring容器ApplicationContext时,会把配置文件中所有对象都创建,备用。

2.基于配置文件的依赖注入(给类中的简单类型,引用类型的属性赋值)

DI给属性赋值有两种方式:
1、在spring的xml配置文件中,使用标签和属性, 和
2、在java的源代码中,使用注解

1.set注入(设值注入)

spring框架调用类中的set方法,通过set方法可以完成属性赋值:
1.简单的属性赋值
2.引用类型赋值

<?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">

    /*声明student对象
        注入:就是赋值的意思
        简单类型: spring中规定java的基本数据类型和String都是简单类型。
        di:给属性赋值
        1. set注入(设值注入) :spring调用类的set方法, 你可以在set方法中完成属性赋值
         1)简单类型的set注入
            <bean id="xx" class="yyy">
               <property name="属性名字" value="此属性的值"/>
               一个property只能给一个属性赋值
               <property....>
            </bean>

         2) 引用类型的set注入 : spring调用类的set方法
           <bean id="xxx" class="yyy">
              <property name="属性名称" ref="bean的id(对象的名称)" />
           </bean>
    */
    <bean id="myStudent" class="com.bjpowernode.ba02.Student">
        <property name="name" value="李四"/>
        <property name="age" value="20"/>
        //引用类型
        <property name="school" ref="mySchool"/>
    </bean>
    //声明school对象
    <bean id="mySchool" class="com.bjpowernode.ba02.School">
        <property name="name" value="北京大学"/>
        <property name="address" value="北京"/>
    </bean>
</beans>
2.构造注入

spring调用类有参数构造方法,在创建对象的同时,在构造方法中给属性赋值:
构造注入使用constructor-arg标签

constructor-arg标签:一个constructor-arg表示构造方法一个参数。

constructor-arg标签属性:
	name:表示构造方法的形参名
	index:表示构造方法的参数的位置,参数从左往右位置是 0 , 1 ,2的顺序
	value:构造方法的形参类型是简单类型的,使用value
	ref:构造方法的形参类型是引用类型的,使用ref
//使用name属性实现构造注入
    <bean id="myStudent" class="com.bjpowernode.ba03.Student" >
        <constructor-arg name="myage" value="20" />
        <constructor-arg name="mySchool" ref="myXueXiao" />
        <constructor-arg name="myname" value="周良"/>
    </bean>

    //使用index属性
    <bean id="myStudent2" class="com.bjpowernode.ba03.Student">
        <constructor-arg index="1" value="22" />
        <constructor-arg index="0" value="李四" />
        <constructor-arg index="2" ref="myXueXiao" />
    </bean>

    //省略index
    <bean id="myStudent3" class="com.bjpowernode.ba03.Student">
        <constructor-arg  value="张强强" />
        <constructor-arg  value="22" />
        <constructor-arg  ref="myXueXiao" />
    </bean>
3.引用类型自动注入

spring框架根据byName,byType规则给引用类型赋值:

1.byName: 按名称注入, 把引用类型的属性名称当做是bean的id使用,从spring容器中获取这个bean赋值给引用类型
2.byType: 按类型注入,把和引用类型的数据类型同源的对象,从容器中获取,赋值给引用类型
同源关系: 相同类型;父子关系;接口和接口实现类

<?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">


    /*
            引用类型的自动注入: spring框架根据某些规则可以给引用类型赋值。·不用你在给引用类型赋值了
       使用的规则常用的是byName, byType.
       1.byName(按名称注入) : java类中引用类型的属性名和spring容器中(配置文件)<bean>的id名称一样,
                              且数据类型是一致的,这样的容器中的bean,spring能够赋值给引用类型。
         语法:
         <bean id="xx" class="yyy" autowire="byName">
            简单类型属性赋值
         </bean>

       2.byType(按类型注入) : java类中引用类型的数据类型和spring容器中(配置文件)<bean>的class属性
                              是同源关系的,这样的bean能够赋值给引用类型
         同源就是一类的意思:
          1.java类中引用类型的数据类型和bean的class的值是一样的。
          2.java类中引用类型的数据类型和bean的class的值父子类关系的。
          3.java类中引用类型的数据类型和bean的class的值接口和实现类关系的
         语法:
         <bean id="xx" class="yyy" autowire="byType">
            简单类型属性赋值
         </bean>
         注意:在byType中, 在xml配置文件中声明bean只能有一个符合条件的,
              多余一个是错误的
    */
    //byName
    <bean id="myStudent" class="com.bjpowernode.ba04.Student" autowire="byName">
        <property name="name" value="李四" />
        <property name="age" value="26" />
    </bean>

    //声明School对象
    <bean id="school" class="com.bjpowernode.ba04.School">
        <property name="name" value="清华大学"/>
        <property name="address" value="北京的海淀区" />
    </bean>

</beans>
4.多配置文件的使用方式
包含关系的配置文件:一个总的文件,包含其他的多个配置文件
<import resource="classpath:其他配置文件的路径"/>
使用通配符 , <import resource="classpath: spring-*.xml"/>

3.基于注解的依赖注入

1.使用注解的基本步骤

1.在类中加入注解,例如@Component
2.在spring的配置文件中加入注解驱动的标签 <context:component-scan=“包名” />

2.创建对象的注解

1.@Component:创建对象,调用类的无参数构造方法
2.@Repository:创建dao对象的,访问数据库
3.@Service: 创建service对象, service是业务类,能够执行业务方法,可以有事务的功能
4.@Controller:创建控制器对象, 控制器能够接受用户的请求,显示请求的处理结果

注意:
@Component: 创建对象的, 等同于的功能
属性:value 就是对象的名称,也就是bean的id值,value的值是唯一的,创建的对象在整个spring容器中就一个
位置:在类的上面

@Component(value = “myStudent”)等同于

spring中和@Component功能一致,创建对象的注解还有:

1.@Repository(用在持久层类的上面) : 放在dao的实现类上面, 表示创建dao对象,dao对象是能访问数据库的。
2.@Service(用在业务层类的上面):放在service的实现类上面,创建service对象,service对象是做业务处理,可以有事务等功能的。
3.@Controller(用在控制器的上面):放在控制器(处理器)类的上面,创建控制器对象的,控制器对象,能够接受用户提交的参数,显示请求的处理结果。

以上三个注解的使用语法和@Component一样的。 都能创建对象,但是这三个注解还有额外的功能。
@Repository,@Service,@Controller是给项目的对象分层的。

3.给属性赋值

I.简单类型:使用@Value

II.引用类型
1.@Autowired: spring框架中提供的:
①.byType: 默认是byType,从容器中找到同源关系的对象,进行赋值;
属性:required ,是一个boolean类型的,默认true
required=true:表示引用类型赋值失败,程序报错,并终止执行。
required=false:引用类型如果赋值失败, 程序正常执行,引用类型是null
②.byName:@Qualifier: 指定对象的名称,使用这个名字的对象,赋值给引用类型

2.@Resource(jdk中的注解):
①.byType: @Resource默认是byName,如果byName失败,再使用byType方式
②.byName:需要指定@Resource的属性name,name是对象的名称

三、AOP面向切面编程

1.基本概念

1.什么是aop:
要给业务方法增加功能,在原有的业务方法代码不改变的情况下,增加一些功能。

2.aop作用:
实现解耦合:业务功能和其它的非业务功能的解耦合
减少重复的代码
专注业务方法的实现,不用考虑其他的代码

3.Aspect:切面
给业务方法增加的功能, 切面通常是非业务功能,例如事务功能,日志,权限管理

4.JoinPoint:连接点
业务方法,表示这个方法执行时,要增加切面的功能

5.Pointcut:切入点
是多个连接的集合,表示切面在这些方法执行时, 要增强切面的功能

6.Advice:通知,增强
表示切面功能的执行时间

2.aspectj框架的使用

1.实现aop的基本步骤:
①:加入一个aspectj的依赖
②:定义业务方法
③:定义切面类:类的上面加入@Aspect;类的里面加入@Before等注解
④:在spring的配置文件加入对象的声明

注解:
1.@Before:前置通知:在目标方法之前先执行的
属性:value ,是切入点表达式,表示切面的功能执行的位置。
位置:在方法的上面
特点:
不会改变目标方法的执行结果
不会影响目标方法的执行

指定通知方法中的参数 : JoinPoint
JoinPoint:业务方法,要加入切面功能的业务方法
作用是:可以在通知方法中获取方法执行时的信息, 例如方法名称,方法的实参。
如果你的切面功能中需要用到方法的信息,就加入JoinPoint.
这个JoinPoint参数的值是由框架赋予, 必须是第一个位置的参数

2.@AfterReturning:后置通知:在目标方法执行之后执行的, 能够获取到目标方法的执行结果
属性:
1.value 切入点表达式
2.returning 自定义的变量,表示目标方法的返回值的,自定义变量名必须和通知方法的形参名一样。
位置:在方法定义的上面
特点:
能够获取到目标方法的返回值,可以根据这个返回值做不同的处理功能
可以修改这个返回值

3.@Around:环绕通知:在目标方法的前和后都能增强功能, 可以修改目标方法的执行结果, 控制目标方法是否执行
属性:value 切入点表达式
位置:在方法的定义上面
特点:
1.它是功能最强的通知
2.在目标方法的前和后都能增强功能。
3.控制目标方法是否被调用执行
4.修改原来的目标方法的执行结果。 影响最后的调用结果

环绕通知,等同于jdk动态代理的InvocationHandler接口
参数: ProceedingJoinPoint 就等同于 Method
作用:执行目标方法
返回值: 就是目标方法的执行结果,可以被修改。
环绕通知: 经常做事务, 在目标方法之前开启事务,执行目标方法, 在目标方法之后提交事务

4.@AfterThrowing:异常通知:在目标方法抛出异常时执行的,通过Exception类型的参数,能够获取到异常信息

5.@After:最终通知:总是会被执行的。

6.@Pointcut:定义和管理切入点的注解

7.动态代理:代理对象是指由框架创建的一种内存中的对象,通过这个对象执行方法时,可以执行切面的功能代码。实现功能的增强

四、Spring集成Mybatis

步骤:
1.新建maven项目
2.加入maven的依赖
1)spring依赖
2)mybatis依赖
3)mysql驱动
4)spring的事务的依赖
5)mybatis和spring集成的依赖: mybatis官方体用的,用来在spring项目中创建mybatis的SqlSesissonFactory,dao对象的
3.创建实体类
4.创建dao接口和mapper文件
5.创建mybatis主配置文件
6.创建Service接口和实现类,属性是dao。
7.创建spring的配置文件:声明mybatis的对象交给spring创建
1)数据源DataSource
2)SqlSessionFactory
3) Dao对象
4)声明自定义的service

8.创建测试类,获取Service对象,通过service调用dao完成数据库的访问

五、Spring事物

1.什么是事务
讲mysql的时候,提出了事务。 事务是指一组sql语句的集合, 集合中有多条sql语句,可能是insert , update ,select ,delete, 我们希望这些多个sql语句都能成功,或者都失败, 这些sql语句的执行是一致的,作为一个整体执行。

2.在什么时候想到使用事务
当我的操作,涉及得到多个表,或者是多个sql语句的insert,update,delete。需要保证这些语句都是成功才能完成我的功能,或者都失败,保证操作是符合要求的。

在java代码中写程序,控制事务,此时事务应该放在那里呢?
service类的业务方法上,因为业务方法会调用多个dao方法,执行多个sql语句

3.通常使用JDBC访问数据库, 还是mybatis访问数据库怎么处理事务
jdbc访问数据库,处理事务 Connection conn ; conn.commit(); conn.rollback();
mybatis访问数据库,处理事务, SqlSession.commit(); SqlSession.rollback();
hibernate访问数据库,处理事务, Session.commit(); Session.rollback();

4.3问题中事务的处理方式,有什么不足
1)不同的数据库访问技术,处理事务的对象,方法不同,需要了解不同数据库访问技术使用事务的原理
2)掌握多种数据库中事务的处理逻辑。什么时候提交事务,什么时候回顾事务
3)处理事务的多种方法。

总结: 就是多种数据库的访问技术,有不同的事务处理的机制,对象,方法。

5.怎么解决不足
spring提供一种处理事务的统一模型, 能使用统一步骤,方式完成多种不同数据库访问技术的事务处理。
使用spring的事务处理机制,可以完成mybatis访问数据库的事务处理
使用spring的事务处理机制,可以完成hibernate访问数据库的事务处理。

6.处理事务,需要怎么做,做什么
spring处理事务的模型,使用的步骤都是固定的。把事务使用的信息提供给spring就可以了

1)事务内部提交,回滚事务,使用的事务管理器对象,代替你完成commit,rollback,事务管理器是一个接口和他的众多实现类。
接口:PlatformTransactionManager ,定义了事务重要方法 commit ,rollback
实现类:
spring把每一种数据库访问技术对应的事务处理类都创建好了。
mybatis访问数据库—spring创建好的是DataSourceTransactionManager
hibernate访问数据库----spring创建的是HibernateTransactionManager

怎么使用:你需要告诉spring 你用是那种数据库的访问技术,怎么告诉spring呢?
声明数据库访问技术的事务管理器实现类, 在spring的配置文件中使用< bean >声明就可以了
例如,你要使用mybatis访问数据库,你应该在xml配置文件中
<bean id=“xxx" class=“…DataSourceTransactionManager”>

2)你的业务方法需要什么样的事务,说明需要事务的类型。
说明方法需要的事务:
1)事务的隔离级别:有4个值。
➢DEFAULT:采用 DB 默认的事务隔离级别。MySql 的默认为 REPEATABLE_READ; Oracle默认为 READ_COMMITTED。
➢ READ_UNCOMMITTED:读未提交。未解决任何并发问题。
➢ READ_COMMITTED:读已提交。解决脏读,存在不可重复读与幻读。
➢ REPEATABLE_READ:可重复读。解决脏读、不可重复读,存在幻读
➢ SERIALIZABLE:串行化。不存在并发问题。

  1. 事务的超时时间: 表示一个方法最长的执行时间,如果方法执行时超过了时间,事务就回滚。单位是秒, 整数值, 默认是 -1.

3)事务的传播行为 : 控制业务方法是不是有事务的, 是什么样的事务的。
7个传播行为,表示你的业务方法调用时,事务在方法之间是如果使用的。

PROPAGATION_REQUIRED
		PROPAGATION_REQUIRES_NEW
		PROPAGATION_SUPPORTS
		以上三个需要掌握的

		PROPAGATION_MANDATORY
		PROPAGATION_NESTED
		PROPAGATION_NEVER
		PROPAGATION_NOT_SUPPORTED

3)事务提交事务,回滚事务的时机
1)当你的业务方法,执行成功,没有异常抛出,当方法执行完毕,spring在方法执行后提交事务。事务管理器commit

2)当你的业务方法抛出运行时异常或ERROR, spring执行回滚,调用事务管理器的rollback
运行时异常的定义: RuntimeException 和他的子类都是运行时异常, 例如NullPointException ,NumberFormatException

  1. 当你的业务方法抛出非运行时异常, 主要是受查异常时,提交事务
    受查异常:在你写代码中,必须处理的异常。例如IOException, SQLException

总结spring的事务
1.管理事务的是 事务管理和他的实现类
2.spring的事务是一个统一模型
1)指定要使用的事务管理器实现类,使用< bean >
2)指定哪些类,哪些方法需要加入事务的功能
3)指定方法需要的隔离级别,传播行为,超时

你需要告诉spring,你的项目中类信息,方法的名称,方法的事务传播行为。

spring框架中提供的事务处理方案
1.适合中小项目使用的, 注解方案。
spring框架自己用aop实现给业务方法增加事务的功能, 使用@Transactional注解增加事务。
@Transactional注解是spring框架自己注解,放在public方法的上面,表示当前方法具有事务。
可以给注解的属性赋值,表示具体的隔离级别,传播行为,异常信息等等

使用@Transactional的步骤:
1.需要声明事务管理器对象

2.开启事务注解驱动, 告诉spring框架,我要使用注解的方式管理事务。
spring使用aop机制,创建@Transactional所在的类代理对象,给方法加入事务的功能。
spring给业务方法加入事务:
在你的业务方法执行之前,先开启事务,在业务方法之后提交或回滚事务,使用aop的环绕通知

@Around("你要增加的事务功能的业务方法名称")
	 Object myAround(){
       开启事务,spring给你开启
		  try{
		     buy(1001,10);
			  spring的事务管理器.commit();
		  }catch(Exception e){
         spring的事务管理器.rollback();
		  }
		 
	 }

3.在你的方法的上面加入@Trancational

2.适合大型项目,有很多的类,方法,需要大量的配置事务,使用aspectj框架功能,在spring配置文件中
声明类,方法需要的事务。这种方式业务方法和事务配置完全分离。

实现步骤: 都是在xml配置文件中实现。
1)要使用的是aspectj框架,需要加入依赖

< dependency >
	< groupId >org.springframework< /groupId >
	< artifactId >spring-aspects< /artifactId >
	< version >5.2.5.RELEASE< /version >
< /dependency >

2)声明事务管理器对象

<bean id="xx" class="DataSourceTransactionManager">

3)声明方法需要的事务类型(配置方法的事务属性【隔离级别,传播行为,超时】)

4)配置aop:指定哪些哪类要创建代理。

六、Spring与web

1.做的是javase项目有main方法的,执行代码是执行main方法的,在main里面创建的容器对象

ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");

2.web项目是在tomcat服务器上运行的。 tomcat一起动,项目一直运行的。

需求:
web项目中容器对象只需要创建一次, 把容器对象放入到全局作用域ServletContext中。

怎么实现:
使用监听器 当全局作用域对象被创建时 创建容器 存入ServletContext

监听器作用:
1)创建容器对象,执行 ApplicationContext ctx = new ClassPathXmlApplicationContext(“applicationContext.xml”);
2)把容器对象放入到ServletContext, ServletContext.setAttribute(key,ctx)

监听器可以自己创建,也可以使用框架中提供好的ContextLoaderListener

private WebApplicationContext context;
 public interface WebApplicationContext extends ApplicationContext

ApplicationContext:javase项目中使用的容器对象
WebApplicationContext:web项目中的使用的容器对象

把创建的容器对象,放入到全局作用域

key: WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE
       WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE
 value:this.context

 servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);