前言

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实战

一、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标签,确定作为切点的方法,需要设置expression和id属性。

使用aop:advisor 关联作为通知的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的值就是在容器中的bean的id值

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  此属性需要提供get、set方法来采用DI的方式注入值

1.3.1.1使用@Resource : 此种方式为 jdk提供的代替get、set对属性注入的注解方式,他默认采用 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的使用

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

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

6.2 SpringBoot 教程之 banner 定制

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

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

6.3 Spring-boot开发

6.3.1 开发流程

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

6.3.2 常见注解

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

最新文章

  1. Linux查看系统资源使用情况(转)
  2. Hibernate框架概念
  3. (DFS)hdoj1010-Tempter of the Bone
  4. idea自动生成serialVersionUID
  5. Cocos2d-x中的字符串
  6. Thrift框架使用C++的一个demo
  7. fiddler 抓取 nodejs
  8. 深度学习入门实战(一):像Prisma一样算法生成梵高风格画像
  9. 马凯军201771010116《面向对象与程序设计Java》
  10. 如何在Linux(Ubuntu)上安装Redmine
  11. 2emq服务器压力测试(无用)
  12. R语言学习 - 非参数法生存分析--转载
  13. Java.WeakReference-SoftReference-PhantomReference
  14. 并发编程概述--C#并发编程经典实例
  15. 【bzoj2194】快速傅立叶之二 FFT
  16. [SSH] Intro to SSH command
  17. 解决Anaconda4.2 Navigator打不开的问题
  18. 【Nodejs】cheerio简单示例
  19. Spring表单验证
  20. python学习笔记(十六)内置函数zip、map、filter的使用

热门文章

  1. mybatis 实现增删改查(CRUD)
  2. 浅谈lambda表达式&amp;lt;最通俗易懂的讲解
  3. Redis哨兵的配置和原理
  4. 大白话带你认识JVM
  5. Windows内核开发-Windows内部概述-2-
  6. 理解vertical-align
  7. hdu 1116 敌兵布阵 线段树 区间求和 单点更新
  8. 什么样的CRM系统适合以客户为中心的企业?
  9. sonarqube 8.9版本配置收邮件提醒
  10. JVM,我就不信学不会你了