面向面试的博客,以问答式Q/A方式呈现。
Spring是一个全面的、企业应用开发一站式的解决方案,贯穿表现层、业务层、持久层。而且Spring也可以和其他的框架无缝整合。Spring具有轻量级、控制反转IOC、面向切面AOP、容器、框架集合等特点,如图:
Spring特点 | 描述 |
---|---|
轻量 | 1、无论从大小和开销两方面而言,Spring都是轻量的,完整的Spring框架可以在一个大小只有1M多的Jar文件里发布,并且Spring所需的处理开销也是微不足道的。2、Spring是非侵入式的,Spring应用中的对象不依赖于Spring特定类。 |
控制反转IOC | 1、Spring通过控制反转IOC实现了低耦合。2、当应用了IOC,一个对象依赖的其他对象会通过被动的方式传递进来,而不是这个对象自己创建或者查找依赖对象。 |
面向切面AOP | Spring支持面向切面的编程,并且把应用业务逻辑和系统服务分开。 |
容器 | Spring是一个容器:Spring包含并管理应用对象的配置和生命周期,程序员可以配置每一个Bean如何被创建,每个Bean可以创建一个单独的实例或者每次需要时都生成一个新的实例 |
框架 | 1、Spring可以将简单的组件配置、组合成为复杂的应用。 2、在Spring中,应用对象被声明式地组合,典型的是在一个XML文件中。 3、Spring也提供了很多基础功能(事务管理、持久化框架集成等),将应用逻辑的开发留给开发者。 |
Spring4框架结构(我们用Spring4,相对来说比较新一点)组成,如下图所示:
由上图可知,
Spring核心,Spring Core Container,提供Beans、上下文Context,管理者所有的Bean,提供配置文件ApplicationContext.xml,用于完成Spring核心功能“依赖注入”;
Spring网络,Spring Web,包括Servlet、SpringMVC、Struts这些,用于和业务层打交道;
Spring数据访问,Spring Access Data,包括JDBC ORM这些,用于和持久成打交道;
Spring切面编程,Spring AOP,包括 AOP Aspects这些,用于面向切面编程。
Spring由最重要的七个模块组成,分别是 Spring Core、 Spring AOP、 Spring ORM、 Spring DAO、Spring Context、 Spring Web和 Spring Web MVC。
Spring常用模块组成,如下表所示(保持与上面Spring结构组成图一一对应):
模块名称 | 明细 |
---|---|
Spring Core模块 | 对应Spring结构图中的Core,主要组件是BeanFactory,它是工厂模式的实现,BeanFactory使用控制反转IOC模式将应用程序的配置和依赖性规范与实际应用程序代码分开。 |
Spring Context模块 | 对应Spring结构图中的Context, 是一个配置文件,一般名称为ApplicationContext.xml,向Spring框架提供上下文信息。 |
Spring AOP模块 | 对应Spring结构图中的AOP,通过配置管理特性,Spring AOP模块直接将面向切面编程的功能集成到Spring框架中。可以将一些通用任务,如安全、事务、日志等集中进行管理,提高了复用性和管理的便捷性。 |
Spring DAO模块 | 对应Spring结构图中的DAO,用于与持久层沟通,Spring DAO模块为JDBC DAO抽象层提供了有意义的异常层次结构,可用该结构来管理异常处理和不同数据库供应商抛出的错误信息。异常层次结构简化了错误处理,并且极大地降低了需要编写的异常代码数量(比如打开和管理连接)。Spring DAO的面向JDBC的异常遵从通用的DAO异常层次结构。 |
Spring ORM模块 | 对应Spring结构图中的ORM,也是用于与持久层沟通,英文全称为Object Relational Mapping,直译为对象关系映射。 Spring框架中插入了若干个ORM框架,而且提供了ORM的对象关系工具,其中包括JDO、Hibernate和iBatis SQL Map,所有的这些都遵从Spring的通用事务和DAO异常层次结构。 |
Spring Web模块 | 对应于Spring结构图中的Web,用于与业务层沟通,Web 上下文模块建立在应用程序上下文模块之上,为基于 Web 的应用程序提供了上下文。所以,Spring框架支持与 Jakarta Struts 的集成。Web 模块还简化了处理多部分请求以及将请求参数绑定到域对象的工作。 |
Spring Web MVC模块 | 对应于Spring结构图中的MVC,用于与业务层沟通,MVC框架是一个全功能的构建 Web应用程序的 MVC 实现。通过策略接口,MVC框架变成为高度可配置的,MVC 容纳了大量视图技术,其中包括 JSP、Velocity、Tiles、iText 和 POI。 |
Spring的七个模块(或者说Spring的所有结构组成)都是由各种不同的Jar包组成的。
Spring常用包package组成,如下表所示(保持与上面Spring结构组成图、Spring七个模块一一对应):
注意,下面所有的关于jar包属于xx模块,都只是一个大概划分,可以这样理解,并不完全准确,只是出于要将 架构-模块-jar包 对应起来的需要
jar包 | 明细 |
---|---|
org.springframework.test | 不属于七个模块,对junit和mock等测试框架的简单封装。 |
jar包之间依赖关系:
上图为jar包与jar间依赖关系:
1、org.springframework.test包依赖于org.springframework.core包。
jar包 | 明细 |
---|---|
org.springframework.core | 属于Spring Core模块,是Spring的核心工具包,其他包依赖于这个包。 |
org.springframework.beans | 属于Spring Core模块,所有应用都用到,包含访问配置文件applicationContext.xml,创建和管理Bean等功能。 |
org.springframework.context | 属于Spring Context模块,提供在基础IOC功能上的扩展服务,此外还提供许多企业级服务的支持,如邮箱服务、任务调度、JNDI定位、EJB集成、远程访问、缓存以及多种视图层框架的支持。 |
org.springframework.expression | 属于Spring Context模块,提供Spring表达式语言。 |
上图为jar包与jar间依赖关系:
1、org.springframework.spring-context包依赖于org.springframework.aop包、org.springframework.beans包、org.springframework.core包、org.springframework.expression包;
2、org.springframework.beans包依赖于org.springframework.core包;
3、org.springframework.expression包依赖于org.springframework.core包;
4、org.springframework.core包依赖于org.springframework.common-logging包。
jar包 | 明细 |
---|---|
org.springframework.aop | 属于Spring AOP模块,用于实现Spring的面向切面编程。 |
org.springframework.aspects | 属于Spring AOP模块,包含Spring提供的对AspectJ框架的整合。 |
org.springframework.instrument.tomcat | 不属于七大模块,Spring对tomcat连接池的集成。 |
org.springframework.instrument | 不属于七大模块,包含Spring对服务器的代理接口。 |
org.springframework.spring-websocket | 不属于七大模块,为web应用提供的高效通信工具 。 |
org.springframework.spring-messaging | 不属于七大模块,用于构建基于消息的应用程序。 |
jar包依赖关系:
上图为jar包与jar间依赖关系:
1、org.springframework.aop包依赖于org.springframework.core包、org.springframework.beans包。
jar包 | 明细 |
---|---|
org.springframework.jdbc | 属于Spring DAO模块,该包是对JDBC(全称Java Database Connect ,即Java数据库连接)的简单封装 |
org.springframework.transaction | 属于Spring ORM模块,该包为JDBC,HIBERNATE,JDO,JPA提供一致性的声明式和编程式事务管理。 |
org.springframework.orm | 属于Spring ORM模块,用于整合第三方orm的实现,如hibernate,ibatis(mybatis),jdo,jps等。 |
org.springframework.oxm | 属于Spring ORM模块,包含Spring对于object/xml映射的支持,可以让JAVA与XML相互切换。 |
org.springframework.jms | 属于Spring DAO模块,该包为简化jms api的使用而做的简单封装。 |
jar包依赖关系:
上图为jar包与jar间依赖关系:
1、org.springframework.jdbc包依赖于org.springframework.core包、org.springframework.beans包、org.springframework.transaction包;
2、org.springframework.transaction包依赖于org.springframework.core包、org.springframework.beans包;
3、org.springframework.orm包依赖于org.springframework.core包、org.springframework.beans包、org.springframework.transaction包、org.springframework.jdbc包。
4、org.springframework.oxm包依赖于org.springframework.core包、org.springframework.beans包;
5、org.springframework.jms包依赖于org.springframework.core包、org.springframework.beans包、org.springframework.aop包、org.springframework.transaction包、org.springframework.context包;
jar包 | 明细 |
---|---|
org.springframework.web.mvc | 属于Spring Web MVC模块,包含SpringMVC应用开发时所需的核心类。 |
org.springframework.web | 属于Spring Web模块,该包包含Web应用开发时,用到的Spring框架时所需的核心类。 |
org.springframework.web.portlet | 属于Spring Web模块,用于对Spring MVC的增强。 |
org.springframework.web.servlet | 属于Spring Web模块,用于对servlet的支持。 |
上图为jar包与jar间依赖关系:
1、org.springframework.web 包依赖于org.springframework.core包、org.springframework.beans包、org.springframework.aop包、org.springframework.context包;
2、org.springframework.web.mvc 包依赖于org.springframework.core包、org.springframework.beans包、org.springframework.web包、org.springframework.expression包、org.springframework.context包;
3、org.springframework.web.portlet 包依赖于org.springframework.core包、org.springframework.beans包、org.springframework.web包、org.springframework.web.mvc包、org.springframework.context包;
注意,Spring4中不再有org.springframework.web.struts包。
jar包 | 明细 |
---|---|
org.springframework.asm | 属于Spring Core模块,spring2.5.6 的时候需要asm jar包,spring3.0 开始提供它自己独立的asm jar包。 |
org.springframework.context.support | 属于Spring Context模块,Spring Context的扩展功能,用于MVC方面。 |
注意,上面所有的关于jar包属于xx模块,都只是一个大概划分,可以这样理解,并不完全准确,只是出于要将 架构-模块-jar包 对应起来的需要
注意,上面所有的关于jar包属于xx模块,都只是一个大概划分,可以这样理解,并不完全准确,只是出于要将 架构-模块-jar包 对应起来的需要
第一,Spring3体系框架图如下:
第二,Spring4体系框架如下:
注意,上面两个图,第一个为Spring3体系框架图,第二个为Spring4体系框架图。
可以看到,Spring3到Spring4的变化是:
Spring4中去掉了spring3的struts,添加了messaging和websocket,其他模块保持不变,因此,spring4的jar有22个
spring-websocket:为web应用提供的高效通信工具
spring-messaging:用于构建基于消息的应用程序
jar包之间的依赖关系:
该图表示:
1、org.springframework.spring-websocket包依赖于org.springframework.spring-core包、org.springframework.spring-web包、org.springframework.spring-context包;
2、org.springframework.spring-messaging包依赖于org.springframework.spring-beans包、org.springframework.spring-core包、org.springframework.spring-context包。
注意,Spring4的七大模块和各种包package,都是在Answer2中将了不再赘余。
bean 注入与装配的的方式有很多种,可以通过 xml,getter-setter 方式,构造函数或者注解等。简单易用的方式就是使用 Spring 的注解了,Spring 提供了大量的注解方式。把这三个表丢给面试官:
第一个表,用在类上的注解
注解 | 明细 |
---|---|
@Controller注解 | 1、用于标注控制层组件; 2、@Controller用于标注在一个类上,使用它的类就是一个SpringMVC Controller对象; 3、分发处理器将会扫描使用了该注解的类的方法,并检测该方法是否使用了@RequestMapping注解; 4、可以把Request请求header部分的值绑定到方法的参数上。 |
@RestControlller注解 | 等效于@Controller与@responseBody的组合效果 |
@Component注解 | 泛指组件,当组件不好归类的时候,一般使用这个注解标注。 |
@Repository注解 | 用于注解dao层,在daoImpl类上面注解。 |
@Service注解 | 用于标注业务层组件。 |
第二个表,用在方法和属性上的注解
注解 | 明细 |
---|---|
@ResponseBody注解 | 1、用于异步请求; 2、@ResponseBody注解用于将Controller的方法返回的对象,通过适当的HttpMessageConverter转换为指定格式后,写入到Response对象的body数据区; 3、返回的数量不是html标签的页面,而是其他某种格式的数据时(如json xml等)使用。 |
@RequstMapping注解 | 一个用来处理请求地址映射的注解,可用于类或方法上。用于类上,表示类中的所有响应请求的方法都是以该地址为父路径。 |
@Autowired注解 | @Autowired注解可以用来对类成员变量、方法及构造函数进行标注,完成自动装配的工作。通过@Autowired的使用来消除set,get方法。 |
@PathVariable注解 | @PathVariable注解用于将请求URL中的模块变量映射到功能处理方法的参数上,即取出url模块中的变量作为参数。 |
@requestParam注解 | @requestParam注解用于在SpringMVC后台控制层获取参数,类似一种是request.getParameter(“name”)。 |
@requestHeader注解 | @requestHeader注解可以把Request请求header部分的值绑定到方法的参数上。 |
第三个表,其他注解
注解 | 明细 |
---|---|
@ModelAttribute注解 | 该Controller的所有方法在调用前,先执行此@ModelAttribute方法,可用于注解和方法参数中,可以把这个@ModelAttribute特性,应用到BaseController当中,所有的Controller继承BaseController,即可实现在调用Controller时,先执行@ModelAttribute方法。 |
@SessionAttributes注解 | 即将值放在session作用域中,写在class上面 |
@Valid注解 | 实体数据校验,可以结合hibernate validator一起使用 |
@CookieValue注解 | 用来获取Cookie中的值 |
Spring框架可以与其他框架结合使用,如下:
集成功能 | 集成工具 | 明细 |
---|---|---|
权限 | shiro | 1、Java的一个安全框架; 2、认证、授权、加密、会话管理、与Web集成。 |
缓存 | Ehcache | 是一个纯Java的进程内缓存框架,具有快速、精干等特点,是Hibernate中默认的CacheProvider。 |
redis | 一个开源的使用ANSI C语言编写、支持网络的、可基于内存亦可持久化的日志型、Key-Value数据库。 | |
持久化框架 | Hibernate | 一个开源的ORM对象关系映射框架,它对JDBC进行了轻量级的对象封装,它将POJO与数据库表建立映射关系,是一个自动的ORM框架。 |
Mybatis | 一个支持普通的SQL查询,存储过程和高级映射的优秀持久层框架。 | |
定时任务 | Quartz | 一个开源的作业调度框架,由Java编写,可以快速完成任务调度的工作。 |
Spring-Task | 可以看做是一个轻量级的Quartz,使用起来很简单,除spring相关的包之外不需要额外的包,支持注解和xml配置文件两种方式。 | |
校验框架 | Hibernate validator | Hibernate validator经常用来验证bean的字段,基于注解,方便快捷。 |
Oval | Oval是一个可扩展的Java对象数据验证框架,验证的规则可以通过配置文件、Annotation、POJOs进行设定,可以使用纯Java语言、JavaScript、Groovy、BeanShell等进行规则的编写。 |
第一,用自己的话描述Spring IOC(Spring IOC的底层工作)
Spring IOC 容器底层工作:Spring 通过一个配置文件描述 Bean 及 Bean 之间的依赖关系,利用 Java 语言的反射功能实例化Bean 并建立 Bean 之间的依赖关系,还提供了 Bean 实例缓存、生命周期管理、 Bean 实例代理、事件发布、资源装载等高级服务。
第二,Spring IOC容器视图
Spring IOC容器视图如图所示:
用自己的话解释一下上图:
Spring 启动时读取应用程序提供的 Bean 配置信息,并在 Spring 容器中生成一份相应的 Bean 定义注册表,然后根据这张Bean注册表实例化 Bean,装配好 Bean 之间的依赖关系,然后将 Bean 实例放到Spring 容器的 Bean缓冲池中(ps:这里 Bean 缓存池是使用 HashMap 实现。),为上层应用提供准备就绪的运行环境,当应用程序需要使用的时候,直接从 Bean缓冲池中取就好了。
BeanFactory与ApplicationContext
BeanFactory 是 Spring 框架的基础设施,面向 Spring本身;ApplicationContext 面向使用Spring 框架的开发者,几乎所有的应用场合我们都直接使用ApplicationContext 而非底层的 BeanFactory。
BeanDefinitionRegistry 注册表
Spring 配置文件中每一个节点元素在 Spring 容器里都通过一个 BeanDefinition 对象表示,它描述了 Bean 的配置信息。而 BeanDefinitionRegistry 接口提供了向容器手工注册
BeanDefinition 对象的方法。
BeanFactory 顶层接口
位于类结构树的顶端 ,它最主要的方法就是 getBean(String beanName),该方法从容器中返回特定名称的 Bean,BeanFactory 的功能通过其他的接口得到不断扩展。
ListableBeanFactory
该接口定义了访问容器中 Bean 基本信息的若干方法,如查看 Bean 的个数、获取某一类型Bean 的配置名、查看容器中是否包括某一 Bean 等方法。
HierarchicalBeanFactory 父子级联
父子级联 IoC 容器的接口,子容器可以通过接口方法访问父容器; 通过HierarchicalBeanFactory 接口, Spring 的 IoC 容器可以建立父子层级关联的容器体系,子容器可以访问父容器中的 Bean,但父容器不能访问子容器的 Bean。Spring 使用父子容器实现了很多功能,比如在 Spring MVC 中,展现层 Bean 位于一个子容器中,而业务层和持久层的 Bean 位于父容器中。这样,展现层 Bean 就可以引用业务层和持久层的 Bean,而业务层和持久层的 Bean 则看不到展现层的 Bean。
ConfigurableBeanFactory
是一个重要的接口,增强了 IoC 容器的可定制性,它定义了设置类装载器、属性编辑器、容器初始化后置处理器等方法;
AutowireCapableBeanFactory 自动装配
定义了将容器中的 Bean 按某种规则(如按名字匹配、按类型匹配等)进行自动装配的方法。
SingletonBeanRegistry 运行期间注册单例 Bean
定义了允许在运行期间向容器注册单实例 Bean 的方法;对于单实例( singleton)的 Bean来说,BeanFactory 会缓存 Bean 实例,所以第二次使用 getBean() 获取 Bean 时将直接从IoC 容器的缓存中获取 Bean 实例。Spring 在 DefaultSingletonBeanRegistry 类中提供了一个用于缓存单实例 Bean 的缓存器,它是一个用 HashMap 实现的缓存器,单实例的 Bean 以 beanName 为键保存在这个 HashMap 中。
依赖日志框框
在初始化 BeanFactory 时,必须为其提供一种日志框架,比如使用 Log4J, 即在类路径下提供 Log4J 配置文件,这样启动 Spring 容器才不会报错。
ApplicationContext 由 BeanFactory 派 生 而 来 , 提 供 了 更 多 面 向 实 际 应 用 的 功 能 。ApplicationContext 继承了 HierarchicalBeanFactory 和 ListableBeanFactory 接口,在此基础上,还通过多个其他的接口扩展了 BeanFactory 的功能。
ApplicationContext类继承体系,如下图所示:
WebApplicationContext 是专门为 Web 应用准备的,它允许从相对于 Web 根目录的
路径中装载配置文件完成初始化工作。
对上图的解释:
从 WebApplicationContext 中可以获得ServletContext 的引用,整个 Web 应用上下文对象将作为属性放置到 ServletContext中,以便 Web 应用环境可以访问 Spring 应用上下文。
Spring 为 Bean 定义了 5 种作用域,分别为 singleton(单例)、prototype(原型)、
request、session 和 global session,5 种作用域说明如下:
第一个,singleton作用域 :单例模式 (多线程下不安全)
singleton:单例模式,Spring IoC 容器中只会存在一个共享的 Bean 实例,无论有多少个
Bean 引用它,始终指向同一对象。该模式在多线程下是不安全的。Singleton 作用域是
Spring 中的缺省作用域,也可以显示的将 Bean 定义为 singleton 模式,配置为:
<bean id="userDao" class="com.ioc.UserDaoImpl" scope="singleton"/>
第二个,prototype作用域: 原型模式 每次使用时创建
prototype:原型模式,每次通过 Spring 容器获取 prototype 定义的 bean 时,容器都将创建一个新的 Bean 实例,每个 Bean 实例都有自己的属性和状态,而 singleton 全局只有一个对象。
一般经验:对有状态的bean使用prototype作用域,而对无状态的bean使用singleton作用域。
第三个,Request作用域 :一次 request 一个实例
request:在一次 Http 请求中,容器会返回该 Bean 的同一实例。而对不同的 Http 请求则会产生新的 Bean,而且该 bean 仅在当前 Http Request 内有效,当前 Http 请求结束,该 bean实例也将会被销毁。
<bean id="loginAction" class="com.cnblogs.Login" scope="request"/>
第四个,session作用域
session:在一次 Http Session 中,容器会返回该 Bean 的同一实例。而对不同的 Session 请求则会创建新的实例,该 bean 实例仅在当前 Session 内有效。同 Http 请求相同,每一次session 请求创建新的实例,而不同的实例之间不共享属性,且实例仅在自己的 session 请求内有效,请求结束,则实例将被销毁。
<bean id="userPreference" class="com.ioc.UserPreference" scope="session"/>
第五个,global Session作用域
global Session:在一个全局的 Http Session 中,容器会返回该 Bean 的同一个实例,仅在使用 portlet context 时有效。
Spring Bean生命周期,如下图所示:
步骤1:实例化
实例化一个 Bean,也就是我们常说的 new。
步骤2:IOC 依赖注入
按照 Spring 上下文对实例化的 Bean 进行配置,也就是 IOC 注入。
步骤3:setBeanName 实现
如果这个 Bean 已经实现了 BeanNameAware 接口,会调用它实现的。setBeanName(String)方法,此处传递的就是 Spring 配置文件中 Bean 的 id 值。
步骤4:BeanFactoryAware 实现
如果这个 Bean 已经实现了 BeanFactoryAware 接口,会调用它实现的 setBeanFactory,
setBeanFactory(BeanFactory)传递的是 Spring 工厂自身(可以用这个方式来获取其它 Bean,只需在 Spring 配置文件中配置一个普通的 Bean 就可以)。
步骤5:ApplicationContextAware 实现
如果这个 Bean 已经实现了 ApplicationContextAware 接口,会调用
setApplicationContext(ApplicationContext)方法,传入 Spring 上下文(同样这个方式也
可以实现步骤 4 的内容,但比 4 更好,因为 ApplicationContext 是 BeanFactory 的子接
口,有更多的实现方法)。
步骤6:postProcessBeforeInitialization 接口实现 - 初始化预处理
:如果这个 Bean 关联了 BeanPostProcessor 接口,将会调用
postProcessBeforeInitialization(Object obj, String s)方法,BeanPostProcessor 经常被用
作是 Bean 内容的更改,并且由于这个是在 Bean 初始化结束时调用那个的方法,也可以被应用于内存或缓存技术。
步骤7:init-method
:如果 Bean 在 Spring 配置文件中配置了 init-method 属性会自动调用其配置的初始化方法。
步骤8:postProcessAfterInitialization
如果这个 Bean 关联了 BeanPostProcessor 接口,将会调用postProcessAfterInitialization(Object obj, String s)方法。
注:以上工作完成以后就可以应用这个 Bean 了,那这个 Bean 是一个 Singleton 的,所以一般情况下我们调用同一个 id 的 Bean 会是在内容地址相同的实例,当然在 Spring 配置文件中也可以配置非 Singleton。
步骤9:Destroy 过期自动清理阶段
当 Bean 不再需要时,会经过清理阶段,如果 Bean 实现了 DisposableBean 这个接口,会调用那个其实现的 destroy()方法。
步骤10:destroy-method 自配置清理
最后,如果这个 Bean 的 Spring 配置中配置了 destroy-method 属性,会自动调用其配置的销毁方法。
注意:bean 标签有两个重要的属性(init-method 和destroy-method)。用它们你可以自己定制初始化和注销方法。它们也有相应的注解(@PostConstruct和@PreDestroy)。
实现方式一:构造器注入
/*带参数,方便利用构造器进行注入*/
public CatDaoImpl(String message){
this. message = message;
}
<bean id="CatDaoImpl" class="com.CatDaoImpl">
<constructor-arg value=" message "></constructor-arg>
</bean>
实现方式二:setter 方法注入
public class Id {
private int id;
public int getId() { return id; }
public void setId(int id) { this.id = id; }
}
<bean id="id" class="com.id "> <property name="id" value="123"></property> </bean>
实现方式三:静态工厂注入
静态工厂顾名思义,就是通过调用静态工厂的方法来获取自己需要的对象,为了让 spring 管理所有对象,我们不能直接通过"工程类.静态方法()"来获取对象,而是依然通过 spring 注入的形式获取:
public class DaoFactory { //静态工厂
public static final FactoryDao getStaticFactoryDaoImpl(){
return new StaticFacotryDaoImpl();
}
}
public class SpringAction {
private FactoryDao staticFactoryDao; //注入对象
//注入对象的 set 方法
public void setStaticFactoryDao(FactoryDao staticFactoryDao) {
this.staticFactoryDao = staticFactoryDao;
}
}
//factory-method="getStaticFactoryDaoImpl"指定调用哪个工厂方法
<bean name="springAction" class=" SpringAction" >
<!--使用静态工厂的方法注入对象,对应下面的配置文件-->
<property name="staticFactoryDao" ref="staticFactoryDao"></property>
</bean>
<!--此处获取对象的方式是从工厂类中获取静态方法-->
<bean name="staticFactoryDao" class="DaoFactory"
factory-method="getStaticFactoryDaoImpl"></bean>
实现方式四:实例工厂
实例工厂的意思是获取对象实例的方法不是静态的,所以你需要首先 new 工厂类,再调用普通的实例方法:
public class DaoFactory { //实例工厂
public FactoryDao getFactoryDaoImpl(){
return new FactoryDaoImpl();
}
}
public class SpringAction {
private FactoryDao factoryDao; //注入对象
public void setFactoryDao(FactoryDao factoryDao) {
this.factoryDao = factoryDao;
}
}
<bean name="springAction" class="SpringAction">
<!--使用实例工厂的方法注入对象,对应下面的配置文件-->
<property name="factoryDao" ref="factoryDao"></property>
</bean>
<!--此处获取对象的方式是从工厂类中获取实例方法-->
<bean name="daoFactory" class="com.DaoFactory"></bean>
<bean name="factoryDao" factory-bean="daoFactory"
factory-method="getFactoryDaoImpl"></bean>
Spring 装配包括手动装配和自动装配,手动装配是有基于 xml 装配、构造方法、setter 方法等自动装配有五种自动装配的方式,可以用来指导 Spring 容器用自动装配方式来进行依赖注入。
Spring AOP含义
" 横切"的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将其命名为"Aspect",即切面。所谓"切面",简单说就是那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块之间的耦合度,并有利于未来的可操作性和可维护性。
使用"横切"技术,AOP 把软件系统分为两个部分:核心关注点和横切关注点。业务处理的主要流程是核心关注点,与之关系不大的部分是横切关注点。横切关注点的一个特点是,他们经常发生在核心关注点的多处,而各处基本相似,比如权限认证、日志、事物。AOP 的作用在于分离系统中的各种关注点,将核心关注点和横切关注点分离开来。
AOP 主要应用场景
AOP 核心概念(或 AOP 8个概念)
1、切面(aspect):类是对物体特征的抽象,切面就是对横切关注点的抽象
2、横切关注点:对哪些方法进行拦截,拦截后怎么处理,这些关注点称之为横切关注点。
3、连接点(joinpoint):被拦截到的点,因为 Spring 只支持方法类型的连接点,所以在 Spring中连接点指的就是被拦截到的方法,实际上连接点还可以是字段或者构造器。
4、切入点(pointcut):对连接点进行拦截的定义
5、通知(advice):所谓通知指的就是指拦截到连接点之后要执行的代码,通知分为前置、后置、异常、最终、环绕通知五类。
6、目标对象:代理的目标对象
7、织入(weave):将切面应用到目标对象并导致代理对象创建的过程
8、引入(introduction):在不修改代码的前提下,引入可以在运行期为类动态地添加一些方法或字段。
AOP 5种通知
1、前置通知(before advice):在某连接点之前执行的通知,但这个通知不能阻止连接点之前的执行流程(除非它抛出一个异常)。
2、后置通知(after returning advice):在某连接点正常完成之后执行的通知,一个方法没有抛出任何异常,正常返回。
3、异常通知(after throwing advice):在方法抛出异常退出时执行的通知。
4、最终通知(after finally advice):但某连接点退出的时候执行的通知(无论是正常返回还是异常退出都执行)。
5、环绕通知(around advice):包围一个连接点的通知,如方法调用。这是最强大的一个通知类型,环绕通知可以在方法调用前后完成自定义的行为,它也会选择是否继续执行连接点 或 直接返回它自己的返回值 或 抛出异常 三种方式之一来结束执行。
Spring 提供了两种方式来生成代理对象: JDKProxy 和 Cglib,具体使用哪种方式生成由
AopProxyFactory 根据 AdvisedSupport 对象的配置来决定。默认的策略是如果目标类是接口,则使用 JDK 动态代理技术,否则使用 Cglib 来生成代理。
JDK 动态接口代理
JDK 动态代理主要涉及到 java.lang.reflect 包中的两个类:Proxy 和InvocationHandler。InvocationHandler是一个接口,通过实现该接口定义横切逻辑,并通过反射机制调用目标类的代码,动态将横切逻辑和业务逻辑编制在一起。Proxy 利用 InvocationHandler 动态创建一个符合某一接口的实例,生成目标类的代理对象。
CGLib 动态代理
CGLib 全称为 Code Generation Library,是一个强大的高性能,高质量的代码生成类库,可以在运行期扩展 Java 类与实现 Java 接口,CGLib 封装了 asm,可以再运行期动态生成新的 class。和 JDK 动态代理相比较:JDK 创建代理有一个限制,就是只能为接口创建代理实例,而对于没有通过接口定义业务方法的类,则可以通过 CGLib 创建动态代理。
Spring AOP 实现原理
@Aspect
public class TransactionDemo {
@Pointcut(value="execution(* com.yangxin.core.service.*.*.*(..))")
public void point(){
}
@Before(value="point()")
public void before(){
System.out.println("transaction begin");
}
@AfterReturning(value = "point()")
public void after(){
System.out.println("transaction commit");
}
@Around("point()")
public void around(ProceedingJoinPoint joinPoint) throws Throwable{
System.out.println("transaction begin");
joinPoint.proceed();
System.out.println("transaction commit");
}
}
Spring 的模型-视图-控制器(MVC)框架是围绕一个 DispatcherServlet 来设计的,这个 Servlet会把请求分发给各个处理器,并支持可配置的处理器映射、视图渲染、本地化、时区与主题渲染等,甚至还能支持文件上传。
Spring MAC流程如下图所示:
步骤一:Http 请求 到 DispatcherServlet
客户端请求提交到 DispatcherServlet。
步骤二:HandlerMapping 寻找处理器
由 DispatcherServlet 控制器查询一个或多个 HandlerMapping,找到处理请求的Controller。
步骤三:调用处理器 Controller
DispatcherServlet 将请求提交到 Controller。
步骤四+步骤五:Controller 调用业务逻辑处理后,返回 ModelAndView
调用业务处理和返回结果:Controller 调用业务逻辑处理后,返回 ModelAndView。
步骤六+步骤七:DispatcherServlet 查询 ModelAndView。
处理视图映射并返回模型: DispatcherServlet 查询一个或多个 ViewResoler 视图解析器,找到 ModelAndView 指定的视图。
步骤八:ModelAndView 反馈浏览器 HTTP
Http 响应:视图负责将结果显示到客户端。
spring MVC常用注解如下:
注解 | 描述 |
---|---|
@Controller | 1、用于标注控制层组件; 2、@Controller注解标注在一个类上,这个被标记的类就是一个SpringMVC Controller对象; 3、分发处理器将会扫描使用了该注解的类的方法,并检测该方法是否使用了@RequestMapping注解; 4、可以把Request请求header部分的值绑定到方法的参数上。 |
@RestController | 等效于@Controller注解和@responseBody注解的组合效果 |
@Component | 泛指组件,当组件不好归类的时候,我们可以使用这个注解进行标注 |
@Repository | 用于注解Dao层,在daoImpl类上面注解 |
@Service | 用于标注业务类组件 |
@ResponseBody | 1、异步请求; 2、该主机用于将Controller的方法返回的对象,通过适当的HttpMesssageConverter转换为指定格式后,写入到Response对象的body数据区; 3、返回的数据不是html标签的页面,而是其他某种格式的数据时(如json、xml等)使用。 |
@RequestMapping | 一个用来处理请求地址转换映射的注解,可用于类或方法上。用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径 |
@Autowired | 它可以对类成员变量、方法及构造函数进行标注,完成自动装配的工作,通过@Autowired的使用来消除set、get方法 |
@PathVariable | 用于将请求URL的模板变量映射到功能处理方法的参数上,即取出url模板中的变量作为参数 |
@requestParam | 主要用于在SpringMVC后台控制层获取参数,类似一种是request.getParameter(“name”) |
@RequestHeader | 可以把Resquest请求header部分的值绑定到方法的参数上 |
Spring Boot 是由 Pivotal 团队提供的全新框架,其设计目的是用来简化新 Spring 应用的初始搭建以及开发过程。该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置。通过这种方式,Spring Boot 致力于在蓬勃发展的快速应用开发领域(rapid applicationdevelopment)成为领导者。其特点如下:
1、创建独立的 Spring 应用程序
2、嵌入的 Tomcat ,无需部署 WAR 文件
3、简化 Maven 配置
4、自动配置 Spring
5、提供生产就绪型功能,如指标,健康检查和外部配置
6、没有代码生成和对 XML 没有要求配置
事务是计算机应用中不可或缺的组件模型,它保证了用户操作的原子性 ( Atomicity )、一致性( Consistency )、隔离性 ( Isolation ) 和持久性 ( Durabilily )。事务分为两种:本地事务和分布式事务。
第一,本地事务
紧密依赖于底层资源管理器(例如数据库连接 ),事务处理局限在当前事务资源内。此种事务处理方式不存在对应用服务器的依赖,因而部署灵活却无法支持多数据源的分布式事务。在数据库连接中使用本地事务示例如下:
public void transferAccount() {
Connection conn = null;
Statement stmt = null;
try{
conn = getDataSource().getConnection();
// 将自动提交设置为 false,若设置为 true 则数据库将会把每一次数据更新认定为一个事务并自动提交
conn.setAutoCommit(false);
stmt = conn.createStatement();
// 将 A 账户中的金额减少 500
stmt.execute("update t_account set amount = amount - 500 where account_id = 'A'");
// 将 B 账户中的金额增加 500
stmt.execute("update t_account set amount = amount + 500 where account_id = 'B'");
// 提交事务
conn.commit();
// 事务提交:转账的两步操作同时成功
} catch(SQLException sqle){
// 发生异常,回滚在本事务中的操做
conn.rollback();
// 事务回滚:转账的两步操作完全撤销
stmt.close();
conn.close();
}
}
第二,分布式事务
Java 事务编程接口(JTA:Java Transaction API)和 Java 事务服务 (JTS;Java TransactionService) 为 J2EE 平台提供了分布式事务服务。分布式事务(Distributed Transaction)包括事务管理器(Transaction Manager)和一个或多个支持 XA 协议的资源管理器 ( ResourceManager )。我们可以将资源管理器看做任意类型的持久化数据存储;事务管理器承担着所有事务参与单元的协调与控制。
public void transferAccount() {
UserTransaction userTx = null;
Connection connA = null; Statement stmtA = null;
Connection connB = null; Statement stmtB = null;
try{
// 获得 Transaction 管理对象
userTx = (UserTransaction)getContext().lookup("java:comp/UserTransaction");
connA = getDataSourceA().getConnection();// 从数据库 A 中取得数据库连接
connB = getDataSourceB().getConnection();// 从数据库 B 中取得数据库连接
userTx.begin(); // 启动事务
stmtA = connA.createStatement();// 将 A 账户中的金额减少 500
stmtA.execute("update t_account set amount = amount - 500 where account_id = 'A'");
// 将 B 账户中的金额增加 500
stmtB = connB.createStatement();
stmtB.execute("update t_account set amount = amount + 500 where account_id = 'B'");
userTx.commit();// 提交事务
// 事务提交:转账的两步操作同时成功(数据库 A 和数据库 B 中的数据被同时更新)
} catch(SQLException sqle){
// 发生异常,回滚在本事务中的操纵
userTx.rollback();// 事务回滚:数据库 A 和数据库 B 中的数据更新被同时撤销
} catch(Exception ne){ }
}
事务使用两个阶段提交主要保证了分布式事务的原子性:即所有结点要么全做要么全不做,所谓的两个阶段是指:第一阶段:准备阶段;第二阶段:提交阶段。
1 准备阶段
事务协调者(事务管理器)给每个参与者(资源管理器)发送 Prepare 消息,每个参与者要么直接返回失败(如权限验证失败),要么在本地执行事务,写本地的 redo 和 undo 日志,但不提交,到达一种“万事俱备,只欠东风”的状态。
2 提交阶段 :
如果协调者收到了参与者的失败消息或者超时,直接给每个参与者发送回滚(Rollback)消息;否则,发送提交(Commit)消息;参与者根据协调者的指令执行提交或者回滚操作,释放所有事务处理过程中使用的锁资源。(注意:必须在最后阶段释放锁资源)
小结:将提交分成两阶段进行的目的很明确,就是尽可能晚地提交事务,让事务在提交前尽可能地完成所有能完成的工作。
Mybastis缓存机制示意图如下:
Mybatis中有一级缓存和二级缓存,默认情况下一级缓存是开启的,而且是不能关闭的。一级缓存是指 SqlSession 级别的缓存,当在同一个 SqlSession 中进行相同的 SQL 语句查询时,第二次以后的查询不会从数据库查询,而是直接从缓存中获取,一级缓存最多缓存 1024 条 SQL。二级缓存是指可以跨 SqlSession 的缓存。是 mapper 级别的缓存,对于 mapper 级别的缓存不同的sqlsession 是可以共享的。
Mybatis 的一级缓存原理 ( sqlsession 级别 )
第一次发出一个查询 sql,sql 查询结果写入 sqlsession 的一级缓存中,缓存使用的数据结构是一个 map。
key:MapperID+offset+limit+Sql+所有的入参
value:用户信息
同一个 sqlsession 再次发出相同的 sql,就从缓存中取出数据。如果两次中间出现 commit 操作(修改、添加、删除),本 sqlsession 中的一级缓存区域全部清空,下次再去缓存中查询不到所以要从数据库查询,从数据库查询到再写入缓存。
Mybatis 的二级缓存原理 ( mapper 级别 )
二级缓存的范围是 mapper 级别(mapper同一个命名空间),mapper 以命名空间为单位创建缓存数据结构,结构是 map。mybatis 的二级缓存是通过 CacheExecutor 实现的。CacheExecutor其实是 Executor 的代理对象。所有的查询操作,在 CacheExecutor 中都会先匹配缓存中是否存在,不存在则查询数据库。
key:MapperID+offset+limit+Sql+所有的入参
value:用户信息
具体使用需要配置: