介绍 Spring+SpringMVC+Mybatis集合框架的一些知识
1、什么是 ORM?
对象关系映射(Object-Relational Mapping,简称ORM),是一种为了解决程序的面向对象模型与数据库的关系模型互不匹配问题的技术;简单的说,ORM 是通过使用描述对象和数据库之间映射的元数据(在Java中可以用XML或者是注解),将程序中的对象自动持久化到关系数据库中或者将关系数据库表中的行转换成Java对象,其本质上就是将数据从一种形式转换到另外一种形式。
2、持久层设计要考虑的问题有哪些?你用过的持久层框架有哪些?
所谓”持久”就是将数据保存到可掉电式存储设备中以便今后使用,简单的说,就是将内存中的数据保存到关系型数据库、文件系统、消息队列等提供持久化支持的设备中。持久层就是系统中专注于实现数据持久化的相对独立的层面。
持久层设计的目标包括:
* 数据存储逻辑的分离,提供抽象化的数据访问接口。
* 数据访问底层实现的分离,可以在不修改代码的情况下切换底层实现。
* 资源管理和调度的分离,在数据访问层实现统一的资源调度(如缓存机制)。
* 数据抽象,提供更面向对象的数据操作。
持久层框架有:
* Hibernate
* MyBatis
* TopLink
* Guzz
* jOOQ
* Spring Data
* ActiveJDBC
3、MyBatis中使用 #
和 $
书写占位符有什么区别?
#
将传入的数据都当成一个字符串,会对传入的数据自动加上引号;$
将传入的数据直接显示生成在 SQL 中。注意:使用 $
占位符可能会导致 SQL 注入攻击,能用 #
的地方就不要使用 $
,写order by子句的时候应该用 $
而不是 #
。
4、解释一下 MyBatis 中命名空间(namespace)的作用。
-
在大型项目中,可能存在大量的 SQL 语句,这时候为每个 SQL 语句起一个唯一的标识(ID)就变得并不容易了。为了解决这个问题,在 MyBatis 中,可以为每个映射文件起一个唯一的命名空间,这样定义在这个映射文件中的每个 SQL 语句就成了定义在这个命名空间中的一个 ID。只要我们能够保证每个命名空间中这个 ID 是唯一的,即使在不同映射文件中的语句 ID 相同,也不会再产生冲突了。
-
绑定 Dao 接口,面向接口编程。
5、MyBatis 动态 SQL。
MyBatis中用于实现动态SQL的元素主要有:
- if
- choose / when / otherwise
- trim
- where
- set
- foreach
代码示例
<select id="selectStudentsByCondition" parameterType="Student" resultType="Student">
select * from student
<where>
<if test="stuId != null and stuId != '' ">
AND stuId = #{stuId}
</if>
<if test="stuName != null and stuName != '' ">
AND stuName like CONCAT(CONCAT('%',#{stuName}),'%')
</if>
<if test="stuAge != null and stuAge != '' ">
AND stuAge = #{stuAge}
</if>
</where>
</select>
<select id="selectStudentByIds" resultType="Student">
SELECT * FROM student WHERE stuId in
<foreach item="stuIds" index="index" collection="list" open="(" separator="," close=")">
#{stuId}
</foreach>
</select>
<update id="updateStudent" parameterType="Student" >
update student
<set>
<if test="stuName != null and stuName != ''">stuName=#{stuName},</if>
<if test="stuAge != null">stuAge=#{stuAge},</if>
</set>
where stuId=#{stuId}
</update>
<select id="dynamicChooseTest" parameterType="Blog" resultType="Blog">
select * from t_blog where 11 = 1
<choose>
<when test="title != null">
and title = #{title}
</when>
<when test="content != null">
and content = #{content}
</when>
<otherwise>
and owner = "owner1"
</otherwise>
</choose>
</select>
<select id="dynamicTrimTest" parameterType="Blog" resultType="Blog">
select * from t_blog
<trim prefix="where" prefixOverrides="and |or">
<if test="title != null">
title = #{title}
</if>
<if test="content != null">
and content = #{content}
</if>
<if test="owner != null">
or owner = #{owner}
</if>
</trim>
</select>
6、什么是IoC和DI?DI是如何实现的?
IoC 叫控制反转,是 Inversion of Control 的缩写,DI(Dependency Injection)叫依赖注入,是对 IoC 更简单的诠释。
控制反转是把传统上由程序代码直接操控的对象的调用权交给容器,通过容器来实现对象组件的装配和管理。所谓的”控制反转”就是对组件对象控制权的转移,从程序代码本身转移到了外部容器,由容器来创建对象并管理对象之间的依赖关系。IoC 体现了好莱坞原则 - “Don’t call me, we will call you”。依赖注入的基本原则是应用组件不应该负责查找资源或者其他依赖的协作对象。配置对象的工作应该由容器负责,查找资源的逻辑应该从应用组件的代码中抽取出来,交给容器来完成。DI 是对 IoC 更准确的描述,即组件之间的依赖关系由容器在运行期决定,形象的来说,即由容器动态的将某种依赖关系注入到组件之中。
依赖注入可以通过 setter方法注入
(设值注入)、构造器注入
和 接口注入
三种方式来实现,Spring 支持 setter注入
和 构造器注入
,通常使用 构造器注
入来注入必须的依赖关系,对于可选的依赖关系,则 setter注入
是更好的选择,setter注入
需要类提供无参构造器或者无参的静态工厂方法来创建对象。
7、Spring 中的 Bean 的作用域有哪些?
singleton
: 表示 Bean 在一个 Spring IOC 容器中只会有一个实例。prototype
: 表示每次从 Spring IOC 获取 Bean 时,都会产生一个新的实例,prototype
通常翻译为原型(原型模式类似于这种方式)。
Spring 不能对一个 prototype bean 的整个生命周期负责,容器在初始化、配置、装饰或者是装配完一个 prototype 实例后,将它交给客户端,随后就对该 prototype 实例不闻不问了。不管何种作用域,容器都会调用所有对象的初始化生命周期回调方法,而对 prototype 而言,任何配置好的析构生命周期回调方法都将不会被调用。 清除 prototype 作用域的对象并释放任何 prototype bean 所持有的昂贵资源,都是客户端代码的职责。(让 Spring 容器释放被 singleton 作用域 bean 占用资源的一种可行方式是,通过使用 bean 的后置处理器,该处理器持有要被清除的 bean 的引用。)
request
: 表示该针对每一次 HTTP 请求都会产生一个新的 bean,同时该 bean 仅在当前 HTTP request 内有效。session
: session 作用域表示该针对每一次 HTTP 请求都会产生一个新的 bean,同时该 bean 仅在当前 HTTP session 内有效。global session
: global session 作用域类似于标准的 HTTP Session 作用域,不过它仅仅在基于 portlet 的 web 应用中才有意义。Portlet 规范定义了全局 Session 的概念,它被所有构成某个 portlet web 应用的各种不同的 portlet 所共享。在 global session 作用域中定义的 bean 被限定于全局 portlet Session 的生命周期范围内。如果你在 web 中使用 global session 作用域来标识 bean,那么 web 会自动当成 session 类型来使用。
request、session、global session 使用的时候首先要在初始化 web 的 web.xml 中做如下配置。
//Servlet 2.4 之后配置
<web-app>
...
<listener>
<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>
...
</web-app>
//Servlet 2.4 以前配置
<web-app>
..
<filter>
<filter-name>requestContextFilter</filter-name>
<filter-class>org.springframework.web.filter.RequestContextFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>requestContextFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
...
</web-app>
Request 配置示例
<bean id="role" class="spring.chapter2.maryGame.Role" scope="request"/>
Session 配置示例
<bean id="role" class="spring.chapter2.maryGame.Role" scope="session"/>
Global Session 配置示例
<bean id="role" class="spring.chapter2.maryGame.Role" scope="global session"/>
扩展
单例模式和原型模式都是重要的设计模式。一般情况下,无状态或状态不可变的类适合使用单例模式。在传统开发中,由于 DAO 持有 Connection 这个非线程安全对象因而没有使用单例模式;但在 Spring 环境下,所有 DAO 类对可以采用单例模式,因为 Spring 利用 AOP 和 Java API 中的 ThreadLocal 对非线程安全的对象进行了特殊处理。
8、什么是 AOP?
全名 Aspect Oriented Programming,中译为面向切面编程。通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。是从动态角度考虑程序运行过程。
9、AOP 相关概念。
-
切面(Aspect): 一个关注点的模块化,这个关注点可能会横切多个对象。事务管理是J2EE应用中一个关于横切关注点的很好的例子。在Spring AOP中,切面可以使用通用类(基于模式的风格) 或者在普通类中以@Aspect 注解(@AspectJ风格)来实现。切面是由切点和增强(引介)组成的,它包括了对横切关注功能的定义,也包括了对连接点的定义。
-
连接点(Joinpoint): 在程序执行过程中某个特定的点,比如某方法调用的时候或者处理异常的时候。 在Spring AOP中,一个连接点 总是 代表一个方法的执行。通过声明一个org.aspectj.lang.JoinPoint类型的参数可以使通知(Advice)的主体部分获得连接点信息。
-
通知(Advice):在切面的某个特定的连接点(Joinpoint)上执行的动作。通知有各种类型,其中包括“around”、“before”和“after”等通知。通知的类型将在后面部分进行讨论。许多AOP框架,包括Spring,都是以拦截器做通知模型, 并维护一个以连接点为中心的拦截器链。
-
切入点(Pointcut):匹配连接点(Joinpoint)的断言。通知和一个切入点表达式关联,并在满足这个切入点的连接点上运行(例如,当执行某个特定名称的方法时)。切入点表达式如何和连接点匹配是AOP的核心:Spring缺省使用AspectJ切入点语法。
-
引入(Introduction): (也被称为内部类型声明(inter-type declaration))。声明额外的方法或者某个类型的字段。 Spring允许引入新的接口(以及一个对应的实现)到任何被代理的对象。例如,你可以使用一个引入来使bean实现 IsModified 接口,以便简化缓存机制。
-
目标对象(Target Object): 被一个或者多个切面(aspect)所通知(advise)的对象。也有人把它叫做被通知(advised) 对象。 既然Spring AOP是通过运行时代理实现的,这个对象永远是一个 被代理(proxied) 对象。
-
AOP代理(AOP Proxy): AOP框架创建的对象,用来实现切面契约(aspect contract)(包括通知方法执行等功能)。 在Spring中,AOP代理可以是JDK动态代理或者CGLIB代理。 注意:Spring 2.0最新引入的基于模式(schema-based)风格和@AspectJ注解风格的切面声明,对于使用这些风格的用户来说,代理的创建是透明的。
-
织入(Weaving): 把切面(aspect)连接到其它的应用程序类型或者对象上,并创建一个被通知(advised)的对象。 这些可以在编译时(例如使用AspectJ编译器),类加载时和运行时完成。 Spring和其他纯Java AOP框架一样,在运行时完成织入。
通知的类型:
-
前置通知(Before advice):在某连接点(join point)之前执行的通知,但这个通知不能阻止连接点前的执行(除非它抛出一个异常)。
-
返回后通知(After returning advice):在某连接点(join point)正常完成后执行的通知:例如,一个方法没有抛出任何异常,正常返回。
-
抛出异常后通知(After throwing advice): 在方法抛出异常退出时执行的通知。
-
后通知(After (finally)advice):当某连接点退出的时候执行的通知(不论是正常返回还是异常退出)。
-
环绕通知(Around Advice):包围一个连接点(join point)的通知,如方法调用。这是最强大的一种通知类型。 环绕通知可以在方法调用前后完成自定义的行为。它也会选择是否继续执行连接点或直接返回它们自己的返回值或抛出异常来结束执行。
10、Spring中自动装配的方式有哪些?
no
:不进行自动装配,手动设置Bean的依赖关系。byName
:根据 Bean 的名字进行自动装配。byType
:根据 Bean 的类型进行自动装配。constructor
:类似于 byType,不过是应用于构造器的参数,如果正好有一个 Bean 与构造器的参数类型相同则可以自动装配,否则会导致错误。autodetect
:如果有默认的构造器,则通过 constructor 的方式进行自动装配,否则使用 byType 的方式进行自动装配。
说明:自动装配没有自定义装配方式那么精确,而且不能自动装配简单属性(基本类型、字符串等),在使用时应注意。
11、Spring中如何使用注解来配置 Bean?有哪些相关的注解?
答:首先需要在 Spring 配置文件中增加如下配置:
<context:component-scan base-package="org.example"/>
然后可以用 @Component
、@Controller
、@Service
、@Repository
注解来标注需要由 Spring IoC 容器进行对象托管的类。这几个注解没有本质区别,只不过 @Controller
通常用于控制器,@Service
通常用于业务逻辑类,@Repository
通常用于仓储类(例如我们的 DAO 实现类),普通的类用 @Component
来标注。
12、Spring支持的事务管理类型有哪些?你在项目中使用哪种方式?
Spring 支持编程式事务管理和声明式事务管理。许多 Spring 框架的用户选择声明式事务管理,因为这种方式和应用程序的关联较少,因此更加符合轻量级容器的概念。声明式事务管理要优于编程式事务管理,尽管在灵活性方面它弱于编程式事务管理,因为编程式事务允许你通过代码控制业务。
事务分为全局事务和局部事务。全局事务由应用服务器管理,需要底层服务器 JTA 支持(如 WebLogic、WildFly 等)。局部事务和底层采用的持久化方案有关,例如使用JDBC进行持久化时,需要使用 Connetion 对象来操作事务;而采用 Hibernate 进行持久化时,需要使用 Session 对象来操作事务。
事务管理器实现类 | 目标对象 |
---|---|
DataSourceTransactionManager | 注入DataSource |
HibernateTransactionManager | 注入SessionFactory |
JdoTransactionManager | 管理JDO事务 |
JtaTransactionManager | 使用JTA管理事务 |
PersistenceBrokerTransactionManager | 管理Apache的OJB事务 |
这些事务的父接口都是 PlatformTransactionManager
。Spring 的事务管理机制是一种典型的策略模式,PlatformTransactionManager
代表事务管理接口,该接口定义了三个方法,该接口并不知道底层如何管理事务,但是它的实现类必须提供 getTransaction()
方法(开启事务)、commit()
方法(提交事务)、rollback()
方法(回滚事务)的多态实现,这样就可以用不同的实现类代表不同的事务管理策略。使用 JTA 全局事务策略时,需要底层应用服务器支持,而不同的应用服务器所提供的 JTA 全局事务可能存在细节上的差异,因此实际配置全局事务管理器是可能需要使用 JtaTransactionManager
的子类,如:WebLogicJtaTransactionManager
(Oracle的WebLogic服务器提供)、UowJtaTransactionManager
(IBM的WebSphere服务器提供)等。
事务配置示例
<!-- 加载jdbc属性文件到上下文 -->
<context:property-placeholder location="jdbc.properties"/>
<!-- 使用了dbcp数据源,从context读取了jdbc属性文件中设定的值 -->
<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<!-- 添加事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- the transactional advice (what 'happens'; see the <aop:advisor/> bean below) -->
<!-- 定义Spring aop通知 -->
<tx:advice id="transactionAdvice" transaction-manager="transactionManager">
<!-- the transactional semantics... -->
<tx:attributes>
<!-- all methods starting with 'get' are read-only -->
<tx:method name="get*" read-only="true"/>
<!-- other methods use the default transaction settings (see below) -->
<!-- 使用事务的方法 -->
<tx:method name="*"/>
<!-- <tx:method name="insert*" propagation="REQUIRED" /> -->
</tx:attributes>
</tx:advice>
<!-- 定义切入点,引用通知 -->
<aop:config>
<aop:pointcut id="accountAspect" expression="execution(* com.doctor.service.AccountService.*(..))"/>
<aop:advisor advice-ref="transactionAdvice" pointcut-ref="accountAspect"/>
</aop:config>
<!-- 使用注解方式实现事务管理配置 -->
<!--<tx:annotation-driven transaction-manager="transactionManager"/>-->
13、如何在Web项目中配置Spring的IoC容器?
如果需要在Web项目中使用 Spring 的 IoC 容器,可以在 Web 项目配置文件 web.xml 中做出如下配置:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
14、如何在Web项目中配置Spring MVC?
要使用 Spring MVC 需要在 Web 项目配置文件中配置其前端控制器 DispatcherServlet,如下所示:
<web-app>
<servlet>
<servlet-name>example</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>example</servlet-name>
<url-pattern>*.html</url-pattern>
</servlet-mapping>
</web-app>
15、Spring MVC的工作原理是怎样的?
示意图一
示意图二
示意图三
流程解析
- 客户端的所有请求都交给前端控制器 DispatcherServlet 来处理,它会负责调用系统的其他模块来真正处理用户的请求。
- DispatcherServlet 收到请求后,将根据请求的信息(包括URL、HTTP协议方法、请求头、请求参数、Cookie等)以及 HandlerMapping 的配置找到处理该请求的 Handler(任何一个对象都可以作为请求的Handler)。
- 在这个地方 Spring 会通过 HandlerAdapter 对该处理器进行封装。
- HandlerAdapter 是一个适配器,它用统一的接口对各种 Handler 中的方法进行调用。
- Handler 完成对用户请求的处理后,会返回一个 ModelAndView 对象给 DispatcherServlet,ModelAndView 顾名思义,包含了数据模型以及相应的视图的信息。
- ModelAndView 的视图是逻辑视图,DispatcherServlet 还要借助 ViewResolver 完成从逻辑视图到真实视图对象的解析工作。
- 当得到真正的视图对象后,DispatcherServlet 会利用视图对象对模型数据进行渲染。
- 客户端得到响应,可能是一个普通的 HTML 页面,也可以是 XML 或 JSON 字符串,还可以是一张图片或者一个 PDF 文件。
16、如何在 Spring IoC 容器中配置数据源?
DBCP配置:
<bean id="dataSource"class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<context:property-placeholder location="jdbc.properties"/>
C3P0配置:
<bean id="dataSource"class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<property name="driverClass" value="${jdbc.driverClassName}"/>
<property name="jdbcUrl" value="${jdbc.url}"/>
<property name="user" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<context:property-placeholder location="jdbc.properties"/>
17、如何配置事务增强?
<?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"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd"><!-- this is the service object that we want to make
transactional -->
<bean id="fooService" class="x.y.service.DefaultFooService" /><!--
the transactional advice -->
<tx:advice id="txAdvice" transaction-manager="txManager"><!-- the transactional
semantics... -->
<tx:attributes><!-- all methods starting with 'get' are read-only -->
<tx:method name="get*" read-only="true" /><!-- other methods
use the default transaction settings (see below) -->
<tx:method name="*" />
</tx:attributes>
</tx:advice><!-- ensure that the above transactional advice runs for any
execution of an operation defined by the FooService interface -->
<aop:config>
<aop:pointcut id="fooServiceOperation"
expression="execution(* x.y.service.FooService.*(..))" />
<aop:advisor advice-ref="txAdvice" pointcut-ref="fooServiceOperation" />
</aop:config><!-- don't forget the DataSource -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
<property name="url" value="jdbc:oracle:thin:@localhost:1521:orcl" />
<property name="username" value="scott" />
<property name="password" value="tiger" />
</bean><!-- similarly, don't forget the PlatformTransactionManager -->
<bean id="txManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean><!-- other <bean/> definitions here -->
</beans>
18、Spring 的优点?
- 非侵入式:不强制性的要求实现 Spring 框架中的接口或继承 Spring 框架中的类,所以 Spring 对代码的污染较低。
- 使用 Spring 的 IOC 容器,将对象之间的依赖关系交给 Spring,降低组件之间的耦合性,让我们更专注于应用逻辑。
- 对主流框架例如:Mybatis、Hibernate,Struts2 等都有良好的支持。
- 开放性、可配置性强,开发人员可以自由的选择 Spring 部分或全部。
- 提供了众多的服务,例如:事物管理。
- 对 AOP 有良好的支持。
19、阐述Spring框架中Bean的生命周期?
- Spring IoC 容器找到关于Bean的定义并实例化该 Bean。
- Spring IoC 容器对 Bean 进行依赖注入。
- 如果 Bean 实现了 BeanNameAware 接口,则将该 Bean 的 id 传给 setBeanName 方法。
- 如果 Bean 实现了 BeanFactoryAware 接口,则将 BeanFactory 对象传给 setBeanFactory 方法。
- 如果 Bean 实现了 BeanPostProcessor 接口,则调用其 postProcessBeforeInitialization 方法。
- 如果 Bean 实现了 InitializingBean 接口,则调用其 afterPropertySet 方法。
- 如果有和 Bean 关联的 BeanPostProcessors 对象,则这些对象的 postProcessAfterInitialization 方法被调用。
- 当销毁 Bean 实例时,如果 Bean 实现了 DisposableBean 接口,则调用其 destroy 方法。
20、依赖注入时如何注入集合属性?
可以在定义 Bean 属性时,通过 <list>
<set>
<map>
<props>
分别为其注入列表、集合、映射和键值都是字符串的映射属性.
21、Spring中的自动装配有哪些限制?
- 如果使用了构造器注入或者 setter 注入,那么将覆盖自动装配的依赖关系。
- 基本数据类型的值、字符串字面量、类字面量无法使用自动装配来注入。
- 优先考虑使用显式的装配来进行更精确的依赖注入而不是使用自动装配。
22、大型网站在架构上应当考虑哪些问题?
-
分层:分层是处理任何复杂系统最常见的手段之一,将系统横向切分成若干个层面,每个层面只承担单一的职责,然后通过下层为上层提供的基础设施和服务以及上层对下层的调用来形成一个完整的复杂的系统。计算机网络的开放系统互联参考模型(OSI/RM)和Internet的TCP/IP模型都是分层结构,大型网站的软件系统也可以使用分层的理念将其分为持久层(提供数据存储和访问服务)、业务层(处理业务逻辑,系统中最核心的部分)和表示层(系统交互、视图展示)。需要指出的是:(1)分层是逻辑上的划分,在物理上可以位于同一设备上也可以在不同的设备上部署不同的功能模块,这样可以使用更多的计算资源来应对用户的并发访问;(2)层与层之间应当有清晰的边界,这样分层才有意义,才更利于软件的开发和维护。
-
分割:分割是对软件的纵向切分。我们可以将大型网站的不同功能和服务分割开,形成高内聚低耦合的功能模块(单元)。在设计初期可以做一个粗粒度的分割,将网站分割为若干个功能模块,后期还可以进一步对每个模块进行细粒度的分割,这样一方面有助于软件的开发和维护,另一方面有助于分布式的部署,提供网站的并发处理能力和功能的扩展。
-
分布式:除了上面提到的内容,网站的静态资源(JavaScript、CSS、图片等)也可以采用独立分布式部署并采用独立的域名,这样可以减轻应用服务器的负载压力,也使得浏览器对资源的加载更快。数据的存取也应该是分布式的,传统的商业级关系型数据库产品基本上都支持分布式部署,而新生的NoSQL产品几乎都是分布式的。当然,网站后台的业务处理也要使用分布式技术,例如查询索引的构建、数据分析等,这些业务计算规模庞大,可以使用Hadoop以及MapReduce分布式计算框架来处理。
-
集群:集群使得有更多的服务器提供相同的服务,可以更好的提供对并发的支持。
-
缓存:所谓缓存就是用空间换取时间的技术,将数据尽可能放在距离计算最近的位置。使用缓存是网站优化的第一定律。我们通常说的CDN、反向代理、热点数据都是对缓存技术的使用。
-
异步:异步是实现软件实体之间解耦合的又一重要手段。异步架构是典型的生产者消费者模式,二者之间没有直接的调用关系,只要保持数据结构不变,彼此功能实现可以随意变化而不互相影响,这对网站的扩展非常有利。使用异步处理还可以提高系统可用性,加快网站的响应速度(用Ajax加载数据就是一种异步技术),同时还可以起到削峰作用(应对瞬时高并发)。";能推迟处理的都要推迟处理”是网站优化的第二定律,而异步是践行网站优化第二定律的重要手段。
-
冗余:各种服务器都要提供相应的冗余服务器以便在某台或某些服务器宕机时还能保证网站可以正常工作,同时也提供了灾难恢复的可能性。冗余是网站高可用性的重要保证。
23、你用过的网站前端优化的技术有哪些?
- 浏览器访问优化:
- 减少HTTP请求数量:合并CSS、合并JavaScript、合并图片(CSS Sprite)
- 使用浏览器缓存:通过设置HTTP响应头中的Cache-Control和Expires属性,将CSS、JavaScript、图片等在浏览器中缓存,当这些静态资源需要更新时,可以更新HTML文件中的引用来让浏览器重新请求新的资源
- 启用压缩
- CSS前置,JavaScript后置
- 减少Cookie传输
- CDN加速:CDN(Content Distribute Network)的本质仍然是缓存,将数据缓存在离用户最近的地方,CDN通常部署在网络运营商的机房,不仅可以提升响应速度,还可以减少应用服务器的压力。当然,CDN缓存的通常都是静态资源。
- 反向代理:反向代理相当于应用服务器的一个门面,可以保护网站的安全性,也可以实现负载均衡的功能,当然最重要的是它缓存了用户访问的热点资源,可以直接从反向代理将某些内容返回给用户浏览器。