Spring、SpringMvc、SpringBoot介绍

前言

Spring作为java开源世界第一开源框架,已经成为事实上的Java EE开发标准。

最根本的使命就是简化Java开发。

不重复制造车轮 Don’t reinvent the wheel .从代码层面来看,就是一句话,如何更加合理的利用已有的代码,不重复创建。

本文重点整理Spring、SpringMVC的核心功能、主要组件、用到的设计模式、及Spring-boot的使用。

参看资料

1、Spring源码解析

设计理念与整体架构、容器的基本实现、默认标签的解析、自定义标签的解析、bean的加载、容器的功能扩展、AOP、数据库连接JDBC、整合Mybatis、事务、

SpringMVC、远程服务、Spring消息服务等内容。

2、Spring-boot实战

3、Java EE 开发的颠覆者 Spring-boot实战

4、springboot视频教程

一、Spring的基础功能

1.1 主要模块:

  • JDBC:完成了对底层jdbc纯粹的封装。
  • Orm : 对象关系映射(Object Relational Mapping)。Spring没有主动提供支持mybatis框架的功能 (提供包),此orm模块主要支持hibernate,如果想在spring框架中使用mybatis,需要另外导包。
  • Transaction: 事务处理模块。
  • Aop: 面向切面编程,他和Aspects模块配合使用。
  • Bean: 对象 ,专门用来处理对象的实例化功能。
  • Core: spring的核心包。
  • Web,websevlet,属于控制器层的,spring框架对该曾也有支持,但是并不理想,后来由springMVC来替代。
  • Context: 上下文路径,主要功能加载配置文件,或者扫描加载项目下包。
  • spEl: spring的EL表达式。

(1)Core Container。

Core Container(核心容器)包含有Core、Beans、Context和Expression Language模块。
Core和Beans模块是框架的基础部分,提供loC(转控制)和依赖注入特性。这里的基础概念是BeanFactory,它提供对Factory模式的经典实现来消除对程序性单例模式的需要,并真正地允许你从程序逻辑中分离出依赖关系和配置。

  • Core模块主要包含Spring框架基本的核心工具类,Spring的其他组件要都要使用到这个包里的类,Core模块是其他组件的基本核心。当然你也可以在自己的应用系统中使用这些工具类。
  • Beans模块是所有应用都要用到的,它包含访问配置文件、创建和管理 bean以及进行Inversion ofControl/Dependency Injection(loC/DI)操作相关的所有类。
  • Context模块构建于Core和Beans模块基础之上,提供了一种类似于JNDI注册器的框架式的对象访问方法。Context模块继承了Beans的特性,为Spring核心提供了大量扩展,添加了对国际化(例如资源绑定)、事件传播、资源加载和对Context的透明创建的支持。Context模块同时也支持J2EE的一些特性,例如EJB、JMX和基础的远程处理。ApplicationContext接口是Context模块的关键。
  • Expression Language 模块提供了一个强大的表达式语言用于在运行时查询和操纵对象。它是JSP2.1规范中定义的unifed expression language的一个扩展。该语言支持设置/获取属性的值,属性的分配,方法的调用,访问数组上下文(accessiong the context ofarrays)、容器和索引器、逻辑和算术运算符、命名变量以及从Spring的IoC容器中根据名称检索对象。它也支持 list投影、选择和一般的 list聚合。

(2)Data Access/Integration。

Data Access/Integration层包含有JDBC、ORM、OXM、JMS和Transaction模块,其中∶JDBC模块提供了一个JDBC抽象层,它可以消除冗长的JDBC编码和解析数据库厂商特有的错误代码。这个模块包含了Spring对JDBC数据访问进行封装的所有类。ORM模块为流行的对象-关系映射API,如JPA、JDO、Hibernate、Batis等,提供了一个交互层。利用ORM封装包,可以混合使用所有Spring提供的特性进行O/R映射。如前边提到的简单声明性事物管理。
Springg框架插入了若干个ORM框架,从而提供了ORM的对象关系工具,其中包括JDO、Hibernate和iBatisSQLMap。所有这些都遵从 Spring的通用事务和DAO异常层次结构。

  • OXM模块提供了一个对ObjectXML映射实现的抽象层,ObjectXML映射实现包括JAXB、Castor、XMLBeans、JiBX和XStream。
  • JMS(Java Messaging Service)模块主要包含了一些制造和消费消息的特性
  • Transaction模块支持编程和声明性的事物管理,这些事物类必须实现特定的接口,并且对所有的POJO都适用。

(3)Web。

  • Web上下文模块建立在应用程序上下文模块之上,为基于Web的应用程序提供了上下文。所以,Spring框架支持与Jakarta Struts的集成。Web模块还简化了处理多部分请求以及将请求参数绑定到域对象的工作。Web层包含了Web、Web-Servlet、Web-Struts和WebPorlet模块,具体说明如下。
  • Web模块∶提供了基础的面向Web的集成特性。例如,多文件上传、使用servletlsteners初始化loC容器以及一个面向 Web的应用上下文。它还包含Spring远程支持中Web的相关部分。
  • Web-Servlet模块 web.servletjar∶该模块包含Spring的model-view-controller(MVC)实现。Spring的MVC框架使得模型范围内的代码和web forms之间能够清楚地分离开来,并与Spring 框架的其他特性集成在一起。
  • Web-Struts模块∶该模块提供了对Struts的支持,使得类在Spring应用中能够与一个典型的Struts Web层集成在一起。注意,该支持在Spring3.0中是deprecated的.
  • Web-Porlet模块∶提供了用于Portlet 环境和Web-Servlet模块的 MVC的实现。

(4)AOP。

  • AOP模块提供了一个符合 AOP联盟标准的面向切面编程的实现,它让你可以定义例如方法拦截器和切点,从而将逻辑代码分开,降低它们之间的耦合性。利用 source-level的元数据功能,还可以将各种行为信息合并到你的代码中,这有点像Net技术中的atribute概念。

通过配置管理特性,SpringAOP模块直接将面向切面的编程功能集成到了Spring框架中,所以可以很容易地使Spring框架管理的任何对象支持AOP。Spring AOP模块为基于Spring的应用程序中的对象提供了事务管理服务。通过使用SpringAOP,不用依赖EJB组件,就可以将声明性事务管理集成到应用程序中。

  • Aspects模块提供了对AspectUJ 的集成支持。
  • Instrumentation模块提供了classinstrumentation 支持和claslader实现,使得可以在特定的应用服务器上使用。

(5)Test。

Test模块支持使用JUnit和 TestNG 对 Spring 组件进行测试。

1.2 主要功能介绍

Spring的功效:

  • 通过xml配置文件在项目运行后,帮助程序员创建了在xml中配置标签的类对象的实例。 这样就降低了程序人员对于创建实例的关注度,而是把更多的精力放在更重要的业务逻辑功能。
  • 帮助创建对象实例
  • 帮助控制接口
  • 帮助创建业务逻辑层的实现类(serviceImpl)
  • 能不能托管servlet(不能,交给springMVC去做)

单纯的一个spring的配置文件:就是实例化,配置bean标签,id,calss属性:IOC和DI注入。

Spring不重复的造轮子,它的出现最大的服务的就是Service层,业务层,不再需要new对象。

1.2.1 IOC/DI (现在都是通过注解来实现了。)

对象控制反转 invertion objcet control/ dependency injection(依赖注入) ,用来处理类的实例化问题。

控制: 控制类的实例化
反转: 程序员在获取对象实例的正常过程,需要是new关键字创建实例,现在有xml配置文件帮助生成对象实例。

1.2.1.1  对象控制反转 invertion objcet control

实例化对象的几种方式:

1 采用默认空参构造器创建对象(这是spring创建对象实例采用的默认的方式)
<!-- 方式1 :通过默认的空参构造器构建对象 -->
<bean id="peo" class="com.bjsxt.pojo.People"></bean> 
2采用有参构造器构建对象:
  • 前提: 首先类中需要提供带参的构造器,属性的类型、名称必须与参数完全一致,使用index注入的时候,还要注意参数的顺序。
  • 使用 name value 根据参数的名称匹配对应的类的成员变量
  • 使用 index value 根据参数的下标索引匹配成员变量
  • 使用type 自动查找类的属性的类型,如果匹配完成值的注入
  • 注意事项: 对于基本数据类和String,值的注入使用value属性即可,对于引用类型 需要使用 ref属性标签
<!--方式2: 通过带参构造器创建对象 -->
<bean id="peo" class="com.bjsxt.pojo.People">
<!-- 使用name 与value 的属性为成员变量通过构造器赋值 --> 
<!-- <constructor-arg name="id" value="101"></constructor-arg>
<constructor-arg name="name" value="张三"></constructor-arg> -->

<!-- 使用index索引给属性赋值 -->
<!-- <constructor-arg index="1" value="101"></constructor-arg>
<constructor-arg index="0" value="张三"></constructor-arg> -->
<!-- 通过参数的类型自动匹配注入类的成员变量 -->
<constructor-arg type="int" value="101"></constructor-arg>
<constructor-arg type="java.lang.String" value="张三"></constructor-arg>
</bean>

1.2.1.2 依赖注入 --- > dependency injection 

总的来说,所谓依赖注入说的是类和类之间的关系。
依赖,指一个类作为另一个类的属性。
注入,通过外部的方式给这个属性赋值。
本质上来说,依赖注入 就是IOC . IOC 是通过spring管理器来给类实例化,而DI是给一个类中的另一个类赋值,看问题的角度不同,一个是实例化对象,另一个是为了赋值,但是从代码角度来说,没有区别。

类与类之间的6种关系:
继承: 父子关系
实现: 接口 与实现类之间的关系
依赖: 一个类作为另一个类的方法的参数或者局部变量
关联: 一种强烈的依赖关系,一个类作为另一个类的属性而存在
聚合: 两个类之间存在局部与整体的关系, 就好比 主机与主板之间的关系,一个类作为另一个类的属性而存在。
组合: 二者之间存在局部与整体的关系,就好比脑袋和人,一个类作为另一个类的属性而存在。
从代码的角度,后三者的结构相同,但是从语义的角度来看,三者之间的紧密型排列如下:
组合>聚合>关联>依赖
使用依赖注入的用途:
解决类与类之间耦合性太高的问题,比如在一个控制器中手动创建业务实体类。那么通过这种依赖注入降低耦合性,以配置的方式为类中另一个作为属性的类赋值。

代码事例:
创建People和Company两个类,Company作为People类的属性,具备了依赖关系,通过Di给该属性注入值

<!-- 通过依赖注入给people类属性赋值 --> 
<bean id="peo" class="com.bjsxt.pojo.People">
    <property name="id" value="101"></property> 
    <property name="name" value="zhangsan"></property>
    <!-- value 属性只适用于基本数据类型,String,以及date类型,如果属性为对象类型,则需要使用ref关键字来进行注入 -->
    <property name="company" ref="com"></property> 
</bean>
<bean id="com" class="com.bjsxt.pojo.Company">
    <property name="id" value="1011"></property>
    <property name="name" value="航空航天公司"></property>
</bean>

在使用属性注入的时候,需要注意:

  • 属性名称必须一致,包括大小写;
  • 在给基本类型、String类型以及Date类型注入值,可以使用value属性,但是如果属性是一个类,则需要使用ref属性,被注入的作为属性的类必须出现在spring容器中,以<bean>标签的形式创建实例对象;
  • 使用属性注入方式,注入者必须具有set、get方法。

关于自动装配:

  • 当一个类作为无论另一类的属性时,可以通过autowire="no";autowire="byName";;autowire="byType" ;autowire=" constructor"来给该对象属性自动装配,注入值;需要注意的是:当采用通过byName与byType时,注入者必须有该对象属性的set,get方法,而采用construtor时则必须有其构造方法(不常用)。
  • 此外,无论是否注入了值,该对象都是会被实例化了的。

参看链接:https://www.cnblogs.com/zhangshuaivole/p/13493299.html

测试:

//测试:

类路径: 从classes文件包中查找xml配置文件,生成spring容器

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

//获取People实例

People people = ac.getBean("peo", People.class);

关于@Resource、@Autowired和default-autowire区别联系

后面引入注解,当配置文件中引入

<context:component-scan base-package="com.bjsxt.service.impl"></context:component-scan>

支持注解扫描com.bjsxt.service.impl这个类,(我认为已经封装了bean形式的name和class属性)即支持注解时,@Autowired根据byName注入,注解@Resource依次byName和byType注入。而Spring还有其他的子标签。我们只是介绍了它实例化对象即配置bean(和支持注解)的配置。

@Autowired和@Resource都可以用来装配bean,都可以写在字段上,或者方法上。
@Autowired属于Spring的;@Resource为JSR-250标准的注释,属于J2EE的。
@Autowired默认按类型装配,默认情况下必须要求依赖对象必须存在,如果
要允许null值,可以设置它的required属性为false,例如:@Autowired(required=false),如果我们想使用名称装配可以结合@Qualifier注解进行使用,如下:
@Autowired()
@Qualifier("baseDao")
private BaseDao baseDao;
@Resource,默认安装名称进行装配,名称可以通过name属性进行指定,如果没有指定name属性,当注解写在字段上时,默认取字段名进行安装名称查找,如果注解写在setter方法上默认取属性名进行装配。当找不到与名称匹配的bean时才按照类型进行装配。但是需要注意的是,如果name属性一旦指定,就只会按照名称进行装配。
例如:
@Resource(name="baseDao")
private BaseDao baseDao;
推荐使用:@Resource注解在字段上,这样就不用写setter方法了,并且这个注解是属于J2EE的,减少了与spring的耦合。这样代码看起就比较优雅。

1.2.1.3 简单工厂(实例工厂)

<!-- 方式3: 使用简单工厂模式构建对象 -->
<!-- <bean id="factory" class="com.bjsxt.factory.PeopleFactory"></bean>
<bean id="peo" factory-bean="factory" factory-method="getPeople"></bean> -->

1.2.1.4 静态工厂

<!-- 方式4:静态工厂模式构建对象 -->
<bean id="peo" class="com.bjsxt.factory.PeopleFactory" factory-method="getPeople"></bean>

1.2.1.5不同数据类型的注入方式:


List
<property name="list">
    <list>
        <value>1</value>
        <value>2</value>
        <value>3</value>
        <value>4</value>
        <value>5</value>
        <value>6</value>
    </list>        
</property>

Array
<property name="array">
    <array>
        <value>a</value>
        <value>b</value>
        <value>c</value>
        <value>d</value>
        <value>e</value>
        <value>f</value>
    </array>        
</property>
4.3    Map
<property name="map">
    <map>
        <entry key="CN">
            <value>china</value>        
        </entry>
        <entry>
            <key>
                <value>gn</value>
            </key>
            <value>Germany</value>
        </entry>
        <entry>
            <key>
                <value>us</value>
            </key>
            <value>USA</value>
        </entry>
    </map>
</property>
4.4    Set(略)
4.5    Properties
<property name="pros">
    <props>
        <prop key=""></prop>
        <prop key=""></prop>
        <prop key=""></prop>
        <prop key=""></prop>
        <prop key=""></prop>
        <prop key=""></prop>
        <prop key=""></prop>
    </props>
</property>

1.2.2 AOP 

1.2.2.1简单介绍

定义:ASPECT ORIENTED PROGRAMMING  面向切面的编程,是Spring在自身基本的bean功能的上做的扩展。

aspect oriented programming 面向切面的编程 ,对方法进行一系列的处理。

AOP 切面: 就是由一系列的方法,通知,异常组成的展示面。

所谓 面向切面就是以类中的方法作为切入点(pointcut),然后再每一个切入点的前方或者后方加入新的功能,作用就是扩展原有方法的功能。切入的执行方法就叫做通知(advice)。

在方法前加入的功能叫做前置通知;

在方法后加入的功能称为后置通知

前后都补充加入功能叫做环绕通知。

因方法执行错误报异常叫做异常通知,

这些通知与作为切点的方法共同组成的概念叫做切面。(aspect)

要了解Spring的AOP就必须先了解动态代理的原理,因为AOP就是基于动态代理实现的。动态代理要从 JDK本身说起。

在JDK的java.lang.reflect包下有个Proxy类,它正是构造代理类的入口。

看JDK的java.lang.reflect包下有个Proxy类,我们可以知道,代理的目的是调用目标方法时,可以转而执行InvocationHandler类的invoke方法,所以如何在InvocationHandler上做文章就是Spring实现AOP的关键所在。

Spring 底层采用的是jdk的动态代理,默认不生成接口真正的实体类对象。造成的问题是,如果要执行某个接口的方法,必然要生成一个动态代理对象,此时如果要将动态代理转换真正的实体类,必然抛出动态代理转换异常$proxy。

如何解决:

在spring 配置文件中,添加标签

<aop:aspectj-autoproxyproxy-target-class="true"></aop:aspectj-autoproxy>

此标签的含义即将底层的动态代理模式由jdk转换为cglib.转换之后,无论是否转换类型,都不会再报错。注意:即使是jdk模式的动态代理,如果不发生转换,不会报错。

proxy-target-class 的值,false为默认值,表示不转换成实体类,true正好相反。

例子:在user(登录日志)项目中,当需要真正的实体类对象时。

1.2.2.2四种通知的简单应用代码实例

1、切点

package com.bjsxt.demo;
/**
 * 
 * 在aop看来,每一个方法都是一个切入点
 * @author Administrator
 *
 */
public class Demo {

    
    public void a(){
        
        System.out.println("Demo.a()");
        
    }
    public String b(String x){
        
        System.out.println("Demo.b()");
        return x;
    }
    public void c(){
        
        System.out.println("Demo.c()");
    }
    public void d() throws Exception{
        int a = 10/0;
        /*try {
            int a = 10/0;
        } catch (Exception e) {
            // TODO Auto-generated catch block
        //    e.printStackTrace();
        }*/
        System.out.println("Demo.d()");
        
    }
    public void f(String a){
        System.out.println("Demo.f()");
        
    }
}

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"
    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="demo" class="com.bjsxt.demo.Demo"></bean>        
<bean id="demo2" class="com.bjsxt.demo.Demo2"></bean>        
<!-- 四种通知 -->
<bean id="myBeforeAdvice" class="com.bjsxt.demo.MyBeforeAdvice"></bean>        
<bean id="myAfterAdvice" class="com.bjsxt.demo.MyAfterAdvice"></bean>        
<bean id="myArroundAdvice" class="com.bjsxt.demo.MyArroundAdvice"></bean>        
<bean id="exceptionAdvice" class="com.bjsxt.demo.ExceptionAdvice"></bean>        

<aop:config>
    <!-- 针对切点a(方法)增加前、后置通知 -->
    <!-- <aop:pointcut expression="execution(* com.bjsxt.demo.Demo.a())" id="mypoint"/> -->
    <!-- <aop:pointcut expression="execution(* com.bjsxt.demo.Demo.b(..))" id="mypoint"/> -->
    <!-- <aop:pointcut expression="execution(* com.bjsxt.demo.Demo.c(..))" id="mypoint2"/> -->
    <aop:pointcut expression="execution(* com.bjsxt.demo.Demo.d(..))" id="mypoint3"/>
     <!-- 针对demo下所有的方法增加前后置通知 -->
    <!-- <aop:pointcut expression="execution(* com.bjsxt.demo.Demo.*())" id="mypoint"/> -->
      <!-- 当前bjsxt包下的所有的类的所有的方法都被通知关联 -->
    <!-- <aop:pointcut expression="execution(* com.bjsxt.demo.*.*(String))" id="mypoint"/> -->
    <!-- <aop:pointcut expression="execution(* com.bjsxt.demo.*.*(..))" id="mypoint"/> -->
    <!-- <aop:pointcut expression="execution(* com.bjsxt.*.impl.*.*())" id="mypoint"/> -->
    <!-- <aop:advisor advice-ref="myBeforeAdvice" pointcut-ref="mypoint"/> -->
    <!-- <aop:advisor advice-ref="myAfterAdvice" pointcut-ref="mypoint"/> -->
   <!--  <aop:advisor advice-ref="myArroundAdvice" pointcut-ref="mypoint2"/> -->
    <aop:advisor advice-ref="exceptionAdvice" pointcut-ref="mypoint3"/>
     
</aop:config>

        
</beans>

参数说明:

外层 config配置标签,确立切点与通知之间的切面关系。

使用pointcut标签,确定作为切点的方法,需要设置expressionid属性。

使用aopadvisor 关联作为通知的bean标签,当切点方法执行,随之执行。需要注意,此通知必备的两个属性: advice-ref引用作为通知的类, pointcut-ref,所关联的切点的方法。

3、通知

前置通知:

package com.bjsxt.demo;

import java.lang.reflect.Method;

import org.springframework.aop.MethodBeforeAdvice;

public class MyBeforeAdvice implements MethodBeforeAdvice{

    @Override
    public void before(Method arg0, Object[] arg1, Object arg2) throws Throwable {
        
        System.out.println(arg0.getName());
        System.out.println(arg1);
        System.out.println(arg2);
        
//        System.out.println("MyBeforeAdvice.before()");
//        System.out.println("前置通知执行");
        
    }

}

后置通知:

package com.bjsxt.demo;

import java.lang.reflect.Method;

import org.springframework.aop.AfterReturningAdvice;
//实现环绕通知
public class MyAfterAdvice implements AfterReturningAdvice{
    //重写后置通知的方法
    @Override
    public void afterReturning(Object arg0, Method arg1, Object[] arg2, Object arg3) throws Throwable {

        System.out.println(arg0);
        System.out.println(arg1);
        System.out.println(arg2);
        System.out.println(arg3);
//        System.out.println("MyAfterAdvice.afterReturning()");
//        System.out.println("后置通知执行");
    }

}

环绕通知:

package com.bjsxt.demo;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

public class MyArroundAdvice implements MethodInterceptor{

    @Override
    public Object invoke(MethodInvocation arg0) throws Throwable {
        System.out.println("触发前置通知");
        arg0.proceed();
        System.out.println("触发后置通知");
        
        
        return null;
    }

}

异常通知:

package com.bjsxt.demo;

import org.springframework.aop.ThrowsAdvice;

public class ExceptionAdvice implements ThrowsAdvice{
    
       public void afterThrowing(ArithmeticException ex) throws Throwable {
           
           System.out.println("触发了异常 ");
           System.out.println(ex.getMessage());
           
        }


}

4、测试

package com.bjsxt.demo;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test {

    public static void main(String[] args) {
        //ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
        ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
        Demo demo = ac.getBean("demo", Demo.class);
//        Demo2 demo2 = ac.getBean("demo2", Demo2.class);
//        demo.a();
//        demo.b("haha");
//        demo.c();
        try {
            demo.d();
        } catch (Exception e) {
            e.printStackTrace();
        }
//        demo.f("haha");
//        demo2.e();
        
    }
}

前置方法参数:(3个)

Method arg0, 关联的切点方法

Object[] arg1, 关联切点方法的参数列表(Object类型元素)

Object arg2,切点方法所在的类对象

后置通知的参数:(4个)

arg0, 切点方法的返回值

Method arg1, 关联的切点方法 

Object[] arg2, 关联切点方法的参数列表(Object类型元素)

Object arg3,切点方法所在的类对象

环绕通知:创建环绕类,实现MethodIntercepto 接口,实现invoke方法。一般环绕通知不会和前后置通知并处,有矛盾的地方。 

异常通知:创建异常通知: Exception Advice  ,实现ThrowsAdvice,即异常通知接口,实现了 afaterthrowing这个方法。

作用:一旦在切面的执行过程中,切点方法出现异常,就会被异常通知对象所捕获并给予提示。

注意: 在切点中发生的异常可以不处理,也可以向外声明,都会被异常捕获通知所获取,便于快速查找错误发生的位置。但是,千万不要在错误发生,即切点方法中自行捕获处理异常,因为这样做,异常捕获通知不会获取任何异常信息,不便于程序的调试。

总结:前置通知+后置通知+环绕通知+异常通知+切点方法组合在一起,就行成了所谓切面AOP,aop最主要的功能就是性能的扩展。 

1.2.2.3应用

日志管理,拦截信息。

1.2.2.4Spring 通过XML配置文件以及通过注解形式来AOP 来实现前置,环绕,异常通知,返回后通知,后通知

参看链接:https://www.cnblogs.com/liuhongfeng/p/4736947.html

1.2.3 事务

1事务的分类

1.1编程式事务

例: OpenSessionInView

程序人员将事务的处理用编码的方法手动处理提交,即所谓编程式事务。注意,不是写了代码就叫事务,该代码必须与事务直接相关联,比如commit

或者rollback这类指令,才可以认为是编程式事务。 

1.2声明式事务

1.2.1Spring提供了一种强大的事务管理方案,这种方案允许变成人员只需告知哪些方法需要事务支持,不需要你手动对事务进行处理、

1.2.2Spring的声明式事务与aop息息相关。从本质上说,spring事务就是一个通知类。他把对事务的处理封装到一个事务处理类当中,然后结合aop实现事务的管理。

1.2.3既然与aop结合,必然涉及到切点和通知。通知就是事务的处理类,切点是谁?是service层的业务方法。 原因是业务层是纯粹的业务逻辑层,再有业务层调用持久化层的方法,大多情况下是批量执行的,多个sql语句并行,这时候,就需要事务加以强大的支持,让语句全部执行,或者全部不执行,service作为事务控制层最为合适。

1.2.4使用事务有什么好处?

1.2.4.1简单高效

1.2.4.2功能强大。 

1.2.5在项目中如何引入spring声明事务进行管理

1.2.5.1由于事务与aop相结合,需要定义切点方法(即事务控制的方法)还有通知。

1.2.5.2通知由spring特有的结构模式,<tx:advise></tx>规定

<tx:advice id="tran" transaction-manager="txm" >

    <tx:attributes>

        <tx:method name="register" read-only="false"/>

        <tx:method name="ins*"/>

        <tx:method name="del*"/>

        <tx:method name="upd*"/>

        <tx:method name="*"/>

    </tx:attributes>

</tx:advice>    

而事务通知标签是由spring提供的事务管理类进行监控托管

<bean id="txm" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"></bean>

Aop 负责设置收到事务控制的切点的方法,以及相关联的具体的通知

<aop:config>

    <aop:pointcut expression="execution(* com.bjsxt.service.impl.UserServiceImpl.register(..))" id="mypoint"/>

    <aop:advisor advice-ref="tran" pointcut-ref="mypoint"/>

</aop:config>

1.2.5.3 方法的属性:

1.2.5.3.1Read-only: 默认值为false,表示处理事务。如果为true,则表示不处理事务,一般用于查询方法。

1.2.5.3.2Propogation : 事务传播行为属性

Data Type : string

Default Value : REQUIRED

Enumerated Values : 

    - REQUIRED

    - SUPPORTS

    - MANDATORY

    - REQUIRES_NEW

    - NOT_SUPPORTED

    - NEVER

1.2.4 注解

1       spring 框架本身是有注解的,比如aop就是(很少有人用)

1.1      问题: 使用spring容器管理哪些类,就是在容器当中放置每一个类的标签,然后通过容器进行实例化,从而带到执行实现类方法的效果。但是,如果需要托管的类过多,每一个都要在容器配置文件当中存在,工作十分犯错且易出错。

1.2      解决方式: 使用注解

1.2.1  在需要实例化的对象(或者叫注入值的类的上面)标注

@Component(value=”xxx”),其中value的值就是在容器中的beanid

1.2.2  报错的原因是spring容器不会主动查找需要使用注解的类,你要告诉spring容器哪些类需要使用注解托管。

1.2.2.1 spring配置文件中增加新的命名空间  

xmlns:context=http://www.springframework.org/schema/context

组件:略


1.2.2.2告知spring到哪个包下寻找使用注解的类

<context:component-scan base-package="com.bjsxt.service.impl"></context:component-scan>

1.2.3  注意事项:

1.2.3.1如果只写一个@Component 标注,也会顺利执行操作。spring会默认你的注解类的类名(首字母小写)作为在容器中bean id值、

1.2.3.2如果注解的value值为自定义类型,则从spring获取id值的时候也必须与注解当中定义的值名称完全一致,否则无法从容器中获取gaibean (另: value= 可以省略)

1.2.3.3注解一定标准在实现类上,能标准在接口上?肯定不行,因为接扣无法实例化对象,只有实现类可以。

1.2.4  @Component 注解关键字并不是通常使用的注解声明,这是一个宽泛的该概念,涉及整个spring容器的注解项。对于业务逻辑层,还有一个更加贴切的注解方式,叫 @Service

1.2.4.1service是专注于业务逻辑层的注解,在真正的注解方式中,使用几率要远大与@Component

1.2.5  其他层的Component子注解

1.2.5.1持久化层: @Repository  mybatis中并不使用。因为mybati s使用配置文件+接口完成dao层实现类的功能,本质是动态代理,没有实现类;Hibernate会使用到这个注解关键字。

1.2.5.2控制器层使用: servlet  ,使用的注解 @Controller ,spring能不能用Controller 不能,springMVC使用此注解。

1.3      关注业务逻辑层实现类,需要被注入的属性classroomMapper

1.3.1  此属性需要提供getset方法来采用DI的方式注入值

1.3.1.1使用@Resource : 此种方式为 jdk提供的代替getset对属性注入的注解方式,他默认采用 byName的类型进行值注入

1.3.1.2使用@autowired :此种方式是spring容器默认提供的代替方式,他采用byType的方式进行值注入

1.4      比较常用的注解:

1.4.1  Value${jdbc.driver}

Value${jdbc.driver}

String str;

1.4.2  @Service

1.4.3  @Resource

1.4.4  @Autowired

二、Spring中用到的设计模式

2.1 工厂设计模式

2.1.1整合mybatis,mybatis中用到的设计模式

回忆mybatis中用到的最多的设计模式就是工厂设计模式。

mybatis就做两件事:根据JDBC规范建立与数据库的连接,通过反射打通Java对象与数据库参数交互之间相互转化的关系。

mybatis是典型的交互式框架。

简单工厂设计模式:DataExchangeFactory。简而言之:就是定义好产品接口,具体产品,客户调用工厂类,在工厂中生产产品。

抽象工厂设计模式:dataSourceFactory:有多个产品接口。

2.2代理模式

2.2.1 静态代理

组成:
抽象对象 : 接口或者是父类
被代理对象: 被隐藏起来的对象
代理对象: 暴露在外,向外提供的对象
调用者: 调用代理对象
举例: 房东想要向外租房
抽象对象; 具体要完成的事 : 租房
被代理对象: 房东
代理对象:中介
调度者: 租客
带来的好处:
将被代理对象隐藏,保护隐私,从代码层面说,隐藏那些不必或者不应该暴露在外的类和代码。
扩展了原有的功能的。
使得被代理对象更加专注地完成自己的工作。
坏处:
如果被代理对象过多(比如生活距离,要求被代理的房东多,房源多),那么就需要构筑大量的代码进行逻辑判断,这无形中增加了代码的冗余度。

代码示例:

抽象对象:

package com.bjsxt.pojo;

public interface ZuFang {
    public void zuFang();
}

被代理对象:

package com.bjsxt.pojo;

public class FangDong implements ZuFang{
    public void zuFang(){
        System.out.println("房东出售一套西三旗的房");
    }
}

代理对象:

package com.bjsxt.pojo;

public class ZhongJie implements ZuFang{
    FangDong fd=new FangDong();
    public void zuFang(){
        //中介租房
        System.out.println("向房东收取介绍费");
        fd.zuFang();
        System.out.println("向租客收取介绍费");
    }
}

调度者:

package com.bjsxt.pojo;

public class We {
    public static void main(String[] args) {
        //静态代理
        ZhongJie zj=new ZhongJie();
        zj.zuFang();
        
        //动态代理
        FangDong fongdong = new FangDong();
        ZhongJie2 zj2=new ZhongJie2();
        zj2.setObj(fongdong);
        zj2.zuFang();
    }
    
    
}

 上面的是静态代理,下面向动态代理转变:

可以看出来,黄色部分的代理操作,需要采用反射,才能够实现。

package com.bjsxt.pojo;

public class ZhongJie2 implements ZuFang{
    Object obj=null;
    
    public Object getObj() {
        return obj;
    }

    public void setObj(Object obj) {
        this.obj = obj;
    }

    public void zuFang(){
        //中介租房
        System.out.println("向房东收取介绍费");
        //obj.zuFang();//需要判断是哪一个对象,才能调用方法,故而是必然用到反射的。
        //应用动态代理模式,底层采用反射的机制,得到被代理对象,并得到其,业务接口的实现类对象,方法,
        //参数,从而调用被代理对象实现业务接口的方法
        System.out.println("向租客收取介绍费");
    }
}

2.2.2 动态代理

1 动态代理相对于静态代理带来的改变: 解决静态代理如果被代理类过多造成的冗余代码问题。
2 动态代理的原理: 底层是通过反射的方式完成被代理对象方法的执行。
3 动态代理模式:
3.1 Jdk下的Proxy模式(讲解对象)
3.2 Cglib (需要导包)
4 创建动态代理项目: dynamic_proxy
4.1 动态代理并不改变代理模式的基本架构:
4.1.1 抽象对象
4.1.2 被代理对象
4.1.3 代理对象:重点修改对象
4.1.4 调用者
4.2 对代理对象类的修改:
4.2.1 去掉实现租房业务的接口
4.2.2 继承 InvocationHandler接口重写invoke 方法
4.2.3 添加房东类(被代理对象)的get、set方法
4.2.4 在调用者类中,调用Proxy对象的静态方法newProxyInstance(xx,xx,xx)
4.2.4.1 三个参数的解释:
ClassLoader loader - 定义代理类的类加载器
Class<?>[] interfaces - 代理类要实现的接口列表 (就是你要完成的业务功能—租房)
InvocationHandler h - 指派方法调用的调用处理程序 (谁是代理-中介)
4.2.5 代理类(ZhongJie)实现了InvocationHandler接口,目的是实现invoke方法
4.2.5.1 Invoke 方法的三个参数:
4.2.5.1.1 Proxy 为抽象对象生成的临时代理对象
4.2.5.1.2 Method: reflect包下的Method的对象,要通过反射执行某个类的方法
4.2.5.1.3 Args: 该方法的参数
5 动态代理带来的好处:
5.1 扩展性增加:
5.2 解决了被代理对象过多造成冗余代码的问题
5.3 解耦性提高: 作为代理类的结构代码无需进行返回修改,只要根据调用者提供的代理对象及被代理对象灵活分配(底层应用了反射技术实现)

 代码示例:

抽象对象:

package com.bjsxt.pojo;

public interface ZuFang {
    public void zuFang();
}

被代理对象:

package com.bjsxt.pojo;

public class FangDong implements ZuFang{
    public void zuFang(){
        System.out.println("房东出售一套西三旗的房");
    }
}

代理对象:

package com.bjsxt.pojo;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class ZhongJie implements InvocationHandler{
    Object obj=null;

    public Object getObj() {
        return obj;
    }

    public void setObj(Object obj) {
        this.obj = obj;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // TODO Auto-generated method stub
        System.out.println("收介绍费");
        Object object = method.invoke(obj, args);
        System.out.println("收手续费");
        return object;
    }
    
}

调度者:

package com.bjsxt.pojo;

import java.lang.reflect.Proxy;

public class We {
    public static void main(String[] args) {
        FangDong fd=new FangDong();
        ZhongJie zj=new ZhongJie();
        zj.setObj(fd);
        ZuFang zf = (ZuFang) Proxy.newProxyInstance(We.class.getClassLoader(), new Class[]{ZuFang.class}, zj);
        zf.zuFang();    
    }
    
    
}

2.3单例模式

2.3.1 Scope模式

Spring 对于每一个<bean>表现来说设计模式默认为单例模式,但仅限于本标签(bean标签)。如果创建多个标签,即使 指向的是同一个类,仍然会创建多个实例。

Scope的取值与含义:

Spring的 Bean对象默认情况下为单例模式,只会产生一个单实例,与设置scope=“singleton”等效。另外,spring容器在加载配置文件时,会把所有默认和singleton方式的bean实例化一遍,不论是否被调用。
prototype: 每一次被调用的时候,spring容器都会创建一个新的实例,但是如果不调用,则不会创建任何实例。
request: 当发生请求的时候产生实例
session:当创建会话的时候产生实例
application: 当创建的application对象的时候产生实例
globalapplication: 略
单例的好处:
节省了内存空间
在共享环境如application下可以传值

2.4 策略模式

2.4.1策略模式实现原理

    

2.4.2Spring中策略模式的实现

三、用Spring进行开发

四、SpringMVC介绍

4.1 SpringMVC工作原理

参看链接:https://www.cnblogs.com/xiaoxi/p/6164383.html

五、Spring-boot的介绍

Spring-boot旨在简化Spring的开发。

5.1 介绍

Spring-boot官网:https://spring.io/projects/spring-boot

通过springboot视频源码温习springboot:
3、博客笔记链接:Spring Boot 2 学习笔记(1 / 2):https://blog.csdn.net/u011863024/article/details/113667634
4、博客笔记链接:Spring Boot 2 学习笔记(2 / 2):https://blog.csdn.net/u011863024/article/details/113667946
5、博客笔记链接:Spring Cloud 学习笔记(1 / 3):https://blog.csdn.net/u011863024/article/details/114298270
6、博客笔记链接:Spring Cloud 学习笔记(2 / 3):https://blog.csdn.net/u011863024/article/details/114298282
7、博客笔记链接:Spring Cloud 学习笔记(3 / 3):https://blog.csdn.net/u011863024/article/details/114298288

5.2 视频学习笔记(基于springboot2)

 1、springboot 响应式编程是什么意思?

https://www.python100.com/html/97396.html

https://blog.csdn.net/qq_27602093/article/details/100825912

2、cmd启动jar包注意点:取消掉cmd的快速编辑模式
0
3、分析依赖树
场景启动器依赖分析
0
0
4、p43后面的html页面找半天找不到,还是看弹幕找到的,上传到了阿里云盘,需要的可以下载https://www.aliyundrive.com/s/MNnizeDeoPF提取码:0u2o

六、Spring-boot进行开发

6.1开发流程

详见链接:https://www.cnblogs.com/szrs/p/13790574.html

6.2 常见注解

详见链接:https://www.cnblogs.com/szrs/p/13790574.html

6.3 SpringBoot2.0 整合 Shiro 框架,实现用户权限管理

参看链接:https://www.cnblogs.com/cicada-smile/p/11186513.html

6.4 SpringBoot 教程之 banner 定制

参看链接:https://juejin.im/post/6844903840936886280

存储、数据库、网络、负载均衡、自动扩展等功能,你只需将你的程序交给云计算平台就可以了。你的程序可以是用不同的编程语言开发的,而使用的Docker的云计算平台就是用Docker 来实现以上功能及不同程序之间的隔离的。目前主流的软件以及非主流的软件大部分都有人将其封装成Docker镜像,我们只需下载Docker镜像,然后运行镜像就可以快速获得已做好配置可运行的软件。

6.5发送邮件

https://blog.csdn.net/caychen/article/details/82887926

 

posted @ 2020-10-09 16:13  慎终若始  阅读(151)  评论(0编辑  收藏  举报