Spring,Spring-boot(一)
前言
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
Spring,Spring-boot(一)的更多相关文章
- 和spring cloud/boot 学习如何管理自己的组件
案例, 功能: 需要写一个往kafka上报数据的组建. 当组建启动时,需要建立如下资源: 1, 和kafka建立若干条连接 2, 启动一个线程池 3, 启动上报一个缓冲区 问题如下: 1, 如何在sp ...
- Spring MVC & Boot & Cloud 技术教程汇总(长期更新)
昨天我们发布了Java成神之路上的知识汇总,今天继续. Java成神之路技术整理(长期更新) 以下是Java技术栈微信公众号发布的关于 Spring/ Spring MVC/ Spring Boot/ ...
- Spring -> Spring Boot > Spring Cloud
这几天刚刚上班,公司用的是Spring Cloud,接触不多.我得赶快学起来. 想学习就必须得知道什么是微服务,什么是Spring Boot,什么是Spring Cloud,以及两者之间有什么关系? ...
- HBase 学习之路(十一)—— Spring/Spring Boot + Mybatis + Phoenix 整合
一.前言 使用Spring+Mybatis操作Phoenix和操作其他的关系型数据库(如Mysql,Oracle)在配置上是基本相同的,下面会分别给出Spring/Spring Boot 整合步骤,完 ...
- HBase 系列(十一)—— Spring/Spring Boot + Mybatis + Phoenix 整合
一.前言 使用 Spring+Mybatis 操作 Phoenix 和操作其他的关系型数据库(如 Mysql,Oracle)在配置上是基本相同的,下面会分别给出 Spring/Spring Boot ...
- Spring/Spring Boot整合Weblogic JMS实战
本文主要介绍weblogic jms的配置,包括JMS 服务器和JMS 模块(连接工厂.队列.远程 SAF 上下文.SAF 导入目的地.SAF 错误处理)的配置:并在Spring/Spring Boo ...
- Spring - Spring Boot - Actuator Web 访问开启
1. 概述 打开 Spring Boot Actuator 的 Web 访问 2. 场景 之前看 Spring 的时候, 曾经想了解当时的配置 后来发现, 确实有这么个工具 刚开始发现, 除了 act ...
- Java & Maven & Spring & Spring Boot
Java & Maven & Spring & Spring Boot Spring Boot sb https://start.spring.io/ Spring 4 htt ...
- Spring 5 , 狭义上的spring 以及 广义上的spring , spring 设计模式
Spring 5 距离 Spring4 发布有4年多, 所以说Spring 5是一个重要的版本 要构建和运行Spring 5应用程序, 至少需要Java EE 7 和JDK 8 , 之前的JDK和Ja ...
- spring spring data jpa save操作事务
整合spring spring data jpa的时候,在save方法上加了@Transactional注解.此时调用springdatajpa save方法并不会真的把数据提交给数据库,而是缓存起来 ...
随机推荐
- springboot2.x整合tkmapper
springboot整合tkmapper 1.导入pom依赖 1.1 导入springboot的parent依赖 <parent> <artifactId>spring-boo ...
- 牛客网sql实战参考答案(mysql版):1-15
1.查找最晚入职员工的所有信息,为了减轻入门难度,目前所有的数据里员工入职的日期都不是同一天(sqlite里面的注释为--,mysql为comment) CREATE TABLE `employees ...
- springmvc——CharacterEncodingFilter过滤器要放在所有过滤器前面
CharacterEncodingFilter的拦截顺序必须是第一个,否则还是会出现乱码问题.这是因为 request对象的parameter并不是一开始就解析的,它是等你第一次调用getParame ...
- 09:jQuery(02)
内容概要 jQuery操作标签 jQuery绑定事件 jQuery补充知识点 jQuery动画效果(了解) 零散补充 内容详细 jQuery练习题 $('#i1') r.fn.init [div#i1 ...
- 【模拟8.10】Weed(线段树)
考试只好随便骗骗分过去啦啦啦..... 正解是玄学线段树: 以每个操作为叶子节点,我们定义几个变量ce表示层数,h表示高度,add表示所减的层数 那么问题转化为单点修改的问题输出直接是根节点答案 但是 ...
- MEMORY_TARGET不够时解决办法
一.报错原因:设置的memory_max_target超过了系统中设置的share memory(/dev/shm)而已. 二.解决办法:增加tmpfs的大小 三.调整tmpfs的大小(两种方法) 1 ...
- Golang超时机制--2秒内某个函数没被调用就认为超时
Golang超时机制--2秒内某个函数没被调用就认为超时 需求描述 当一整套流程需要其他程序来调用函数完成时通常需要一个超时机制,防止别人程序故障不调你函数导致你的程序流程卡死 实现demo pack ...
- (Element UI 组件 Table)去除单元格底部的横线
Element UI 组件 Table 有一个属性 border,添加它可以增加纵向边框,但是无法控制横线边框,因此即使是最简单的 el-table,也会包含一个底部横线. 这个底部横线其实是一个 b ...
- 07 修改JumpServer网页信息
1.7.修改JumpServer网页信息 注意:在修改相关配置文件之前要先进行备份,防止文件修改错误无法恢复. 1.Luna图标: /opt/luna/static/imgs/logo.png 2.j ...
- SpringBoot Cache 深入
这上一篇文章中我们熟悉了SpringBoot Cache的基本使用,接下来我们看下它的执行流程 CacheAutoConfiguration 自动装配类 根据图中标注,看到它引用了CachingCon ...