前言
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