在学习之前要知道啥是SSM,他是Spring ,SpringMVC跟Mybatis的简称;
按照字母顺序我们应该先学习Spring

Spring框架体系
SSM模式学习路线-----[Spring入门笔记]_maven

本次笔记内容主要是核心框架,AOP,ASPECT以及transaction

SSM模式

Spring

什么是Spring?

网上和书上有很多定义,简单来说就是
IOC---->控制反转
DI—>依赖注入
AOP---->内核框架

首先如果不是maven方式配置环境的话,需要手动下载Spring

请移步官网----->>

先看一下spring框架的目录结构

SSM模式学习路线-----[Spring入门笔记]_bc_02

重点在于lib目录下----->>SSM模式学习路线-----[Spring入门笔记]_spring_03其中由有个核心包----->>

SSM模式学习路线-----[Spring入门笔记]_spring_04
第三方依赖包----

核心容器需要依赖一个JAR包----commons-logging-1.2.jar

基本环境需要的jar包都已经介绍完毕!

几个重要概念----->>

控制反转—IOC

什么叫控制反转?
在传统的面向对象编程中,获取对象的基本方式 new 一个,这时是由我们主动创建的,而在Spring中对象的生命周期由Spring框架提供的IOC容器来管理即我们可以直接从IOC容器中获取一个对象;

我们在表示小明有一本书的时候,我们常常在 小明这个类中去new 一个Book,在Book类中去new一个小明,这样对象之间的练习就很紧密,如果引入了人IOC,小明和书之间失去了直接联系,当小明需要这本书的时候由IOC容器创建一个书对象,这时候就不需要我们手动去创建书对象了;
一张图表示----->>>

SSM模式学习路线-----[Spring入门笔记]_java_05

依赖注入—DI

跟控制反转是同一件事情,只不过是描述的对象不一样,这次主人公是书
就是主动与 被动的区别-----有点神奇!!!

IOC与DI给开发带来的好处—>

1,可维护性比较好,因为减少了代码的耦合性,使得修改代码时尽可能的减少对整体程序的影响;
2,每个团队可以专注于自己要实现的业务逻辑,需要别的团队的代码时可以通过IOC/DI来实现;
3,增强了代码的复用性—即我们可以把常用的代码抽取成一个类/方法以供各个开发组使用;
4,项目可快速部署—具有热插拔的特性;

IOC/DI的实现

Spring 主要依靠4个核心jar包和一个第三方jar包来实现;

IOC的简单实现----->>>>
准备工作------>
1,新建一个maven工程
SSM模式学习路线-----[Spring入门笔记]_java_06

2,引入依赖----
到maven仓库中引入依赖
commons-logging
spring-context
spring-context-support
spring-expression
spring-core
SSM模式学习路线-----[Spring入门笔记]_maven_07

3,编写测试代码

目路结构---->>

SSM模式学习路线-----[Spring入门笔记]_intellij-idea_08
代码实现---->>>

SSM模式学习路线-----[Spring入门笔记]_intellij-idea_09

Spring中Bean详解

bean的配置

bean的配置方式有两种方式,一个是通过xml来配置,一个是通过注解方式来配置,工作中常用注解方式完成配置;
SSM模式学习路线-----[Spring入门笔记]_spring_10Bean中可以配置的子元素/属性
SSM模式学习路线-----[Spring入门笔记]_spring_11

如果在Bean中未指定id和name,那么Spring会将class值当作id使用。

bean的作用域

Spring中常用的作用域是 singleton 和prototype

SSM模式学习路线-----[Spring入门笔记]_intellij-idea_12
指定作用域----

SSM模式学习路线-----[Spring入门笔记]_java_13SSM模式学习路线-----[Spring入门笔记]_intellij-idea_14

如果不设置scope=“singleton”,其输出结果也是一个实例,因为Spring容器默认的作用域就是singleton。

singleton作用域对于无会话状态的Bean(如Dao组件、Service组件)来说是最理想的选择。

对需要保持会话状态的Bean应用使用prototype作用域。

bean的装配方式

bean的装配方式有基于xml方式,注解方式以及自动装配

基于xml方式的装配

Spring提供了两种基于XML的装配方式:设值注入(Setter Injection)和构造注入(ConstructorInjection),

依赖注入

Setter方式注入

SSM模式学习路线-----[Spring入门笔记]_maven_15例中的se**()方法完成属性赋值,从而实现依赖注入。其name属性表示Bean实例中的相应属性名,ref属性用于指定其属性值;

在Spring配置文件中需要使用元素的子元素来为每个属性注入值;

注意---->设值注入的方式—

1,Bean类必须提供一个默认的无参构造方法。
2,Bean类必须为需要注入的属性提供对应的setter()方法。

SSM模式学习路线-----[Spring入门笔记]_intellij-idea_16

构造方法注入

SSM模式学习路线-----[Spring入门笔记]_intellij-idea_17SSM模式学习路线-----[Spring入门笔记]_intellij-idea_18

P命名空间与C命名空间

通过P和C命名空间简化装配

  xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop"

SSM模式学习路线-----[Spring入门笔记]_maven_19

基于注解的方式装配

当xml中装配的越来越多,会显得非常的乱,不容易维护;
此时可以用注解的方式来完成装配
注解的详解----->>
SSM模式学习路线-----[Spring入门笔记]_bc_20
再实际开发中问常常会习惯于将repository,servive,与controller注解的作用域进行限制,使其只对某个包下(或者更小的方位内有效;
)
use-default-filters=“false”
默认值为true 代表使用默认的扫描过滤器
默认的扫描过滤器会识别并包含 @Component @Controller @Service @Repository 四个注解
不使用默认的filter,使用我们自己的filter

SSM模式学习路线-----[Spring入门笔记]_spring_21

依赖注入的实际应用---->>

SSM模式学习路线-----[Spring入门笔记]_spring_22如果出现-----

java.lang.NoClassDefFoundError:org/springframework/aop/TargetSource”错误。

则是因为Spring-aop包没有导入

注解完成自动装配---->>
SSM模式学习路线-----[Spring入门笔记]_bc_23SSM模式学习路线-----[Spring入门笔记]_spring_24

SpringAop

Spring的AOP模块是Spring框架体系结构中十分重要的内容,提供了面向切面编程的实现。

什么是SpringAop

SpringAop是Spring中面向切面的一种编程方式,是对面向对象编程的一种补充;

Aop设计的初衷---->>>

这里纯属意淫,如有不当之处还望各路大神指正!

在传统的面向对象过程中,有很多地方用到的代码重复的地方太多,虽然可以用继承的方式来提高代码复用性,但继承的局限性是得代码的复用性得不到很好的放大;

那可不可以将相同类型的代码抽取出来,在编译或者运行的时候将这些代码应用到需要的地方-----SpringAop

SpringAop框架有两个,一个是SpringAOP(纯java实现,不需要专门的编译过程和类加载器,在运行期间通过代理方式向目标类注入代码)一个是ApectJ是一个基于Java语言的AOP框架,提供了一个专门的编译器,在编译时提供横向代码的植入。

新版本的Spring框架建议使用AspectJ来开发AOP。

SpringAop中的一些术语

Aspect
切面 ----即java中的类,通常是用于横向插入系统中功能实现的类

Joinpoint
即我们要在哪里插入时做的一个标记

Pointcut
指类或者方法名

Advice
通知增强处理,指在定义好的切入点处要执行的程序代码

Target Object
被通知的对象

Proxy
将通知应用到目标对象后,被动态的创建的对象

Weaving
将切面代码插入目标对象上,从而生成代理对象的过程。

AOP的实现方式

实现方式跟注入方式类似,都可以通过XML注入或者通过注解方式注入

常用的xml配置
可以当作模板来用,不过一般习惯用注解的方式

<!--    定义一个bean-->
    <bean id="myAspect"  class="com.gavin.myAspect.MyAspect"/>
<!--    将bean转为切面bean-->
<!--    aop配置-->
    <aop:config>
<!--        配置切面-->
<aop:aspect id="aspect" ref="myAspect">
<!--    定义切入点-->
    <aop:pointcut id="myPointCut" expression="execution(* com.gavin.myAspect.*.*(..))"/>
<!--    在切入点之前运行的代码,一般用于检查验证之类的-->
    <aop:before method="myBefore" pointcut-ref="myPointCut"/>
<!--    运行时要插入的功能代码-->
<aop:after-returning method="myAfterReturning" returning="returnVal" pointcut-ref="myPointCut"/>
<!-- 环绕通知-->
   <aop:around method="myAround" pointcut-ref="myPointCut" />
<!--    最终通知-->
    <aop:after-throwing method="myAfterThrowing" pointcut-ref="myPointCut" throwing="e"/>

<aop:after method="myAfter" pointcut-ref="myPointCut"/>
</aop:aspect>
    </aop:config>
</beans>

基于xml的声明式AspectJ

注意,在配置时可能会遇到一点问题比如在导入JoinPoint时候爆红无法导入-----

SSM模式学习路线-----[Spring入门笔记]_intellij-idea_25

后来才发现是作用域的问题,scope作用域标签中改为complie或者直接去掉.保持默认----complie

下面是具体的AOP实现

public class MyAspect {
 public void myBefore (JoinPoint joinPoint){
  System.out.print("前置通知---权限检查,");
  System.out.print("目标类--"+joinPoint.getTarget());
  System.out.println(",被植入的增强处理的目标方法为--"+joinPoint.getSignature().getName());
  }
 public void myAfterReturning(JoinPoint joinPoint)  {
  System.out.println("后置通知,模拟日志记录");
  System.out.println(",被植入的增强处理的目标方法为--"+joinPoint.getSignature().getName());
 }
 public Object myAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
  System.out.println("环绕开始");
//  invoke current method
  Object proceed = proceedingJoinPoint.proceed();
  System.out.println("环绕结束");
  return proceed;
 }
 public void myAfterThrowing(JoinPoint joinPoint, Throwable e)  {
  System.out.println("出现异常:"+e.getMessage());
 }
 public void myAfter(JoinPoint joinPoint)  {
  System.out.println("最终通知:结束后释放资源");
 }
}

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

<bean id="userDao" class="com.gavin.Dao.UserDaoImp"/>

<!--    定义一个bean-->
    <bean id="myAspect"  class="com.gavin.myAspect.MyAspect"/>
<!--    将bean转为切面bean-->
<!--    aop配置-->
    <aop:config>
<!--        配置切面-->
<aop:aspect id="aspect" ref="myAspect">
<!--    定义切入点-->
    <aop:pointcut  expression="execution(* com.gavin.Dao.*.*(..))" id="myPointCut"/>
<!--    在切入点之前运行的代码,一般用于检查验证之类的-->
    <aop:before method="myBefore" pointcut-ref="myPointCut"/>
<!--    运行时要插入的功能代码-->
<aop:after-returning method="myAfterReturning"  pointcut-ref="myPointCut"  returning="joinPoint"/>
<!-- 环绕通知-->
   <aop:around method="myAround" pointcut-ref="myPointCut" />
<!--异常通知-->
    <aop:after-throwing method="myAfterThrowing" pointcut-ref="myPointCut" throwing="e"/>
    <!--    最终通知-->
<aop:after method="myAfter" pointcut-ref="myPointCut"/>
</aop:aspect>
    </aop:config>
</beans>

SSM模式学习路线-----[Spring入门笔记]_spring_26
开始配置时出现java.lang.ClassCastException: class jdk.proxy2.$Proxy9 cannot be cast to class com.gavin.Dao.UserDaoImp (jdk.proxy2.$Proxy9 is in module jdk.proxy2 of loader 'app'; com.gavin.Dao.UserDaoImp is in unnamed module of loader 'app')

原因在于 proxy代理模式的原理,返回的是一个接口,所以 要用接口来接,而不是实现类来接返回值;

使用aop:after-returning配置的后置通知和使用aop:after配置的最终通知虽然都是在目标方法执行之后执行,但它们是有区别的。后置通知只有在目标方法成功执行后才会被植入,而最终通知不论目标方法如何结束(包括成功执行和异常中止两种情况),它都会被植入。另外,如果程序没有异常,异常通知将不会执行。

PROCCEDINGJOINPOINT用于控制在环绕通知中哪些在切入点之前执行,哪些在切入点之后执行

如果方法很多,那么基于xml配置的aspect的优势也会荡然无存,所以为了方便开发,使用注解来减少代码配置的繁琐是个不错的选择;

基于注解的声明式AspectJ

首先熟悉AspectJ的注解
SSM模式学习路线-----[Spring入门笔记]_bc_27
基于注解的开发
SSM模式学习路线-----[Spring入门笔记]_bc_28

相对来说,使用注解的方式更加简单、方便,所以在实际开发中推荐使用注解的方式进行AOP开发。

SSM模式学习路线-----[Spring入门笔记]_java_29

如果在同一个连接点有多个通知需要执行,那么在同一切面中,目标方法之前的前置通知和环绕通知的执行顺序是未知的,目标方法之后的后置通知和环绕通知的执行顺序也是未知的。

如果遇到下面的错误类型很可能是切入点配置出现了问题;

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'userDao' defined in class path resource [applicationContext.xml]: Initialization of bean failed; nested exception is java.lang.IllegalArgumentException: warning no match for this type name: com.gavin.Dao [Xlint:invalidAbsoluteTypeName]

全注解开发Aop主要是用aspect来实现
SSM模式学习路线-----[Spring入门笔记]_spring_30

SpringJdbc

Spring的JDBC模块负责数据库资源管理和错误处理,大大简化了开发人员对数据库的操作,使得开发人员可以从烦琐的数据库操作中解脱出来,从而将更多的精力投入编写业务逻辑中。

SPringJdbc核心

JdbcTemplate是SpringJdbc的核心,
继承自抽象类JdbcAccessor,同时实现了JdbcOperations接口。(1)JdbcOperations接口定义了在JdbcTemplate类中可以使用的操作集合,包括添加、修改、查询和删除等操作。(2)JdbcTemplate类的直接父类是JdbcAccessor,该类为子类提供了一些访问数据库时使用的公共属性

SSM模式学习路线-----[Spring入门笔记]_intellij-idea_31

在Spring源码中可以看到数据库连接的操做的影子,所以使用Spring框架开发能够简化开发人员面对数据库是重复的一些操做,同时能够降低代码的耦合度,便于开发;

SSM模式学习路线-----[Spring入门笔记]_java_32

SpringJdbc的配置

基于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="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
    <property name="url" value="jdbc:mysql://127.0.0.1:3306/gavin?"/>
<property name="username" value="gavin"/>
    <property name="password" value="955945"/>
</bean>
<!--配置jdbc连接模板-->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<!--        配置连接的数据源-->
        <property name="dataSource" ref="dataSource"/>
    </bean>
<!--配置注入类-->

    <bean id="user" class="注入实现类">
        <property name="jdbcTemplate" ref="jdbcTemplate"/>
    </bean>
........省略号........

</beans>

在SpringJdbc中封装了很多对数据库操做的方法

SpringJDBC中的常用方法

还是基本操做
1,新建一个项目,
2导入Spring核心包—4个
core , context , context-support ,expression
外部依赖包 common-loging
3,导入数据库驱动jar包
4,导入SpringJdbc相关的包
spring-jdbc , spring-tx
5配置springjdbc模板文件
然后开始写代码
SpringJDBC创建一个表
SSM模式学习路线-----[Spring入门笔记]_intellij-idea_33代码就很多简单了,是不是比传统JDBC实现简单的多了

配置文件详解
SSM模式学习路线-----[Spring入门笔记]_bc_34
SpringJDBC更新表中数据
包括插入,删除,更新操做都用update来操做

配置文件中多了注入类的Bean
SSM模式学习路线-----[Spring入门笔记]_java_35
SSM模式学习路线-----[Spring入门笔记]_spring_36

SpringJDBC查询表中数据

先看API中常用方法

SSM模式学习路线-----[Spring入门笔记]_bc_37选几个常用的方法------>>

SSM模式学习路线-----[Spring入门笔记]_java_38
实际应用---->>
SSM模式学习路线-----[Spring入门笔记]_bc_39放几条执行的结果----嘻嘻
SSM模式学习路线-----[Spring入门笔记]_bc_40
真是大大简化了jdbc的代码,不用开发人员去管理每个数据库接口的声明周期;

Spring的事务声明

声明式事务管理:基于XML方式的声明式事务和基于Annotation方式的声明式事务。

Spring中事务生命的核心Jar包
Spring-tx
在maven中直接引入Transaction依赖就可以了;

在包中有三个用于事务管理的接口
SSM模式学习路线-----[Spring入门笔记]_java_41PlatformTransactionManager

PlatformTransactionManager接口是Spring提供的平台事务管理器,主要用于管理事务。

TransactionStatus getTransaction(TransactionDefinition definition):用于获取事务状态信息。该方法会根据TransactionDefinition参数返回一个TransactionStatus对象。TransactionStatus对象表示一个事务,被关联在当前执行的线程上。
 void commit(TransactionStatus status):用于提交事务。 void rollback(TransactionStatus status):用于回滚事务

针对不同的持久层框架,需要使用事务管理接口不同的实现类来实现事务管理;

DataSourceTransactionManager:用于配置JDBC数据源的事务管理器。

HibernateTransactionManager:用于配置Hibernate的事务管理器。

JtaTransactionManager:用于配置全局事务管理器。

关于获取事物描述的一些方法---->>>

string getName():获取事务对象名称。
int getlsolationLeve():获取事务的隔离级别。 
int getPropagationBehavior():获取事务的传播行为。  
int setTimeout():获取事务的超时时间。
boolean isReadOnly():获取事务是否只读。

事务的管理主要是针对于数据的插入,更新
和删除,必须要进行事务管理,如果没有指定事务传播行为,Spring默认为Required;

SSM模式学习路线-----[Spring入门笔记]_bc_42
TransactionStatus

用于描述事务的状态

SSM模式学习路线-----[Spring入门笔记]_maven_43

Spring中事物的管理方式

基于xml实现声明式事务管理

新建一个maven项目,
引入核心依赖
SpringJdbc
数据管理由于要用到数据库,所以要引入数据库驱动;
xml方式实现事务管理要写通知来声明事务,最后用AOP自动生成代理;
引入 aop,aspectj

SSM模式学习路线-----[Spring入门笔记]_intellij-idea_44
xml中的基本配置
数据库连接部分配置是一样的方式,
然后是变化的部分
tx-advice 来编写增强通知

最后编写aop
SSM模式学习路线-----[Spring入门笔记]_intellij-idea_45在没有异常的情况下执行
SSM模式学习路线-----[Spring入门笔记]_spring_46SSM模式学习路线-----[Spring入门笔记]_spring_47
改回原始值-1000,并创建一个异常,再次测试
报异常,数据库中的值没有变化

SSM模式学习路线-----[Spring入门笔记]_bc_48

基于Annotation实现声明式事务管理

SSM模式学习路线-----[Spring入门笔记]_java_49

如果使用注解式开发,就需要在配置文件中开启注解处理器,指定扫描哪些包下的注解。

在实际开发中,事务的配置信息通常是在Spring的配置文件中完成的,而在业务层类上只需使用@Transactional注解即可,不需要配置@Transactional注解的属性。

至此Spring常用框架已经学习完毕; 21.11.25

补充内容----->

关于spring中引入集合的一些操做;

SSM模式学习路线-----[Spring入门笔记]_intellij-idea_50

除此之外还也已定义一个公共的集合空间,使得该集合能被多个bean引用

SSM模式学习路线-----[Spring入门笔记]_maven_51SSM模式学习路线-----[Spring入门笔记]_java_52SSM模式学习路线-----[Spring入门笔记]_java_53学完Spring基本框架之后,我们会发现Spring对Bean的一个管理,Bean是怎样的一个生命周期呢?

Bean的生命周期---->>

SSM模式学习路线-----[Spring入门笔记]_maven_54

BeanPostProcessor接口作用:

如果我们想在Spring容器中完成bean实例化、配置以及其他初始化方法前后要添加一些自己逻辑处理。我们需要定义一个或多个BeanPostProcessor接口实现类,然后注册到Spring IoC容器中。

1、接口中的两个方法都要将传入的bean返回,而不能返回null,如果返回的是null那么我们通过getBean方法将得不到目标。
2、ApplicationContext会自动检测在配置文件中实现了BeanPostProcessor接口的所有bean,并把它们注册为后置处理器,然后在容器创建bean的适当时候调用它,因此部署一个后置处理器同部署其他的bean并没有什么区别。而使用BeanFactory实现的时候,bean 后置处理器必须通过代码显式地去注册,在IoC容器继承体系中的ConfigurableBeanFactory接口中定义了注册方法

前置通知和后置通知一定会执行的,跟是否我们初始化Bean没有关联;

使用纯注解开发---->>>
SSM模式学习路线-----[Spring入门笔记]_java_55

有时候使用纯注解开发会难以理解,因为要有一个脉络,不然很容易出错,所以xml配合注解实现会更好!

案例开发1

案例开发2

Spring5中还用到了最新的日志log4j2,跟log4j的不同之处在于log4j2是使用xml来配置的;

顺带说一下log4j2

spring5框架自带了通用的日志封装,也可以整合自己的日志 1)spring移除了
LOG4jConfigListener,官方建议使用log4j2 2)spring5整合log4j2 导入log4j2依赖

SSM模式学习路线-----[Spring入门笔记]_spring_56
依赖的传递性使得导入impl就使得其他依赖一同导进来了,非常方便,maven的方便体现出来了;

log4j2.xml文件配置

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="DEBUG">
    <Appenders>
        <Console name="Console" target="SYSTEM_OUT">
            <PatternLayout pattern="%d{YYYY-MM-dd HH:mm:ss} [%t] %-5p %c{1}:%L - %msg%n" />
        </Console>
    </Appenders>
    <Loggers>
        <Root level="debug">
            <AppenderRef ref="Console" />
        </Root>
    </Loggers>
</Configuration>